def do_list_device_type_description(self, line): """ List all device types and their descriptions from maps.yaml. Option to edit device description. """ self.get_device_type_descriptions() print("\nDo you want to edit a device type description [y/n]? Press <Enter> to exit: ", end='') option = raw_input().lower() existed = False if option and str2bool(option): while not existed: print("Enter a device type: ", end='') device_type = raw_input() for t in self._device_type_maps: if t['name'] == device_type: existed = True print("Enter the description for {0}: ".format(device_type), end='') t['description'] = raw_input() self.write_to_map_yaml() self.do_list_device_type_description('') if not existed: print("Device type {0} does not exit. Do you want to choose another device type [y/n]. " "Press <Enter> to exit: ".format(device_type), end='') option = raw_input().lower() if not option or not str2bool(option): existed = True
def do_list_device_type_description(self, line): """ List all device types and their descriptions from maps.yaml. Option to edit device description. """ self.get_device_type_descriptions() print( "\nDo you want to edit a device type description [y/n]? Press <Enter> to exit: ", end='') option = input().lower() existed = False if option and str2bool(option): while not existed: print("Enter a device type: ", end='') device_type = input() for t in self._device_type_maps: if t['name'] == device_type: existed = True print("Enter the description for {0}: ".format( device_type), end='') t['description'] = input() self.write_to_map_yaml() self.do_list_device_type_description('') if not existed: print( "Device type {0} does not exit. Do you want to choose another device type [y/n]. " "Press <Enter> to exit: ".format(device_type), end='') option = input().lower() if not option or not str2bool(option): existed = True
def do_device_type(self, line): """ List information of a selected device type from maps.yaml Option to select another device type Get a specific device type information: device_type <name> <name>: name of a device type in maps.yaml List all device before selecting name: device_type """ existed = False name = line if not name: self.get_device_type_descriptions() print("\nEnter a device type: ", end='') name = input() for device_type in self._device_type_maps: if device_type.get('name', None) == name: existed = True print("\nDEVICE TYPE: {0}".format(device_type['name'].upper())) for k in device_type.keys(): if k is not 'name': print("{0:25} | {1}".format(k, device_type[k])) if not existed: print("Device type '{0}' does not exist".format(name)) print( "\nDo you want to select another device type [y/n]? Press <Enter> to exit: ", end='') option = input().lower() if option and str2bool(option): self.do_device_type('')
def do_device_type(self, line): """ List information of a selected device type from maps.yaml Option to select another device type Get a specific device type information: device_type <name> <name>: name of a device type in maps.yaml List all device before selecting name: device_type """ existed = False name = line if not name: self.get_device_type_descriptions() print("\nEnter a device type: ", end='') name = raw_input() for device_type in self._device_type_maps: if device_type.get('name', None) == name: existed = True print("\nDEVICE TYPE: {0}".format(device_type['name'].upper())) for k in device_type.keys(): if k is not 'name': print("{0:25} | {1}".format(k, device_type[k])) if not existed: print("Device type '{0}' does not exist".format(name)) print("\nDo you want to select another device type [y/n]? Press <Enter> to exit: ", end='') option = raw_input().lower() if option and str2bool(option): self.do_device_type('')
def get_existed_directory(self, dir, dir_type): """ Check if the directory exists, if not, option to change the directory. Return None if the directory does not exist, or the correct existed directory otherwise. Update self._device_type_maps if map_dir is changed. :param dir: directory :param dir_type: directory type (for examples: csv_dir, config_dir, map_dir) """ while True: if not os.path.isdir(dir): print("The directory {0} '{1}' does not exist".format( dir_type, dir)) print("Change to another directory [y/n]: ", end='') option = input().lower() if option and str2bool(option): print("Enter the new {0} directory: ".format(dir_type), end='') dir = input() else: return None else: if dir != self._directories[dir_type]: self._directories[dir_type] = dir if dir_type == 'map_dir': self._device_type_maps = self.set_device_type_maps() return dir
def do_delete_volttron_config(self, line): """ Delete a driver config from volttron (Make sure volttron is running). """ driver_name = line drivers = dict() for f in self._sh('volttron-ctl config list platform.driver').split('\n'): if f.startswith('devices'): drivers[f.split('/')[-1]] = f if not driver_name: print('\nList of all drivers in VOLTTRON platform.driver:') print("DRIVER NAME".ljust(16) + "| VOLTTRON PATH") for d in drivers.keys(): print("{0:15} | {1}".format(d, drivers[d])) print ("\nEnter driver name to delete: ", end='') driver_name = raw_input() if driver_name not in drivers: print("\nDriver name '{0}' does not exist".format(driver_name)) print("Do you want to select another driver to delete [y/n]? Press <Enter> to exit: ", end='') option = raw_input().lower() if option and str2bool(option): self.do_delete_volttron_config('') else: self._sh('volttron-ctl config delete platform.driver {0}'.format(drivers[driver_name])) self.list_volttron_config("Delete successful!")
def do_delete_volttron_csv(self, line): """ Delete a registry csv config from volttron (Make sure volttron is running). """ csv_name = line csv_files = list() for f in self._sh('volttron-ctl config list platform.driver').split('\n'): if f.endswith('csv'): csv_files.append(f) if not csv_name: print("\nList of all registry csv files in VOLTTRON platform.driver:") for csv in csv_files: print(csv) print("\nEnter driver name to delete: ", end='') csv_name = raw_input() csv_name = "{0}.csv".format(csv_name) if not csv_name.endswith('.csv') else csv_name if csv_name not in csv_files: print("\nRegistry CSV config '{0}' does not exist".format(csv_name)) print("Do you want to select another registry csv config to delete [y/n]? Press <Enter> to exit: ", end='') option = raw_input().lower() if option and str2bool(option): self.do_delete_volttron_csv('') else: self._sh('volttron-ctl config delete platform.driver {0}'.format(csv_name)) self.list_volttron_config("Delete successful!")
def do_delete_volttron_config(self, line): """ Delete a driver config from volttron (Make sure volttron is running). """ driver_name = line drivers = dict() for f in self._sh('volttron-ctl config list platform.driver').split( '\n'): if f.startswith('devices'): drivers[f.split('/')[-1]] = f if not driver_name: print('\nList of all drivers in VOLTTRON platform.driver:') print("DRIVER NAME".ljust(16) + "| VOLTTRON PATH") for d in drivers.keys(): print("{0:15} | {1}".format(d, drivers[d])) print("\nEnter driver name to delete: ", end='') driver_name = input() if driver_name not in drivers: print("\nDriver name '{0}' does not exist".format(driver_name)) print( "Do you want to select another driver to delete [y/n]? Press <Enter> to exit: ", end='') option = input().lower() if option and str2bool(option): self.do_delete_volttron_config('') else: self._sh('volttron-ctl config delete platform.driver {0}'.format( drivers[driver_name])) self.list_volttron_config("Delete successful!")
def get_existed_directory(self, dir, dir_type): """ Check if the directory exists, if not, option to change the directory. Return None if the directory does not exist, or the correct existed directory otherwise. Update self._device_type_maps if map_dir is changed. :param dir: directory :param dir_type: directory type (for examples: csv_dir, config_dir, map_dir) """ while True: if not os.path.isdir(dir): print("The directory {0} '{1}' does not exist".format(dir_type, dir)) print("Change to another directory [y/n]: ", end='') option = raw_input().lower() if option and str2bool(option): print("Enter the new {0} directory: ".format(dir_type), end='') dir = raw_input() else: return None else: if dir != self._directories[dir_type]: self._directories[dir_type] = dir if dir_type == 'map_dir': self._device_type_maps = self.set_device_type_maps() return dir
def get_default_value(self, datatype, str_value): """ Convert default value from str to the register type :param datatype: register type :param str_value: default value in str :type datatype: str :type str_value: str """ python_type = self.get_python_type(datatype) if str_value: if python_type is int: return int(str_value) elif python_type is float: return float(str_value) elif python_type is bool: return helpers.str2bool(str_value) elif python_type is str: return str_value else: raise ValueError("Invalid data type for point {}".format( self.point_name)) else: return None
def do_list_directories(self, line): """ List all set-up directories. Option to edit directories. """ dir_type_map = { 'map_dir': 'Map Directory', 'csv_dir': 'CSV Config Directory', 'config_dir': 'Diver Config Directory' } print("\n" + "DIRECTORY TYPE".ljust(23) + "| DIRECTORY PATH") for dir_key in self._directories.keys(): print("{0:22} | {1}".format(dir_type_map[dir_key], self._directories[dir_key])) print("\nDo you want to edit directories [y/n]? Press <Enter> to exit: ", end='') option = raw_input().lower() if option and str2bool(option): self.do_edit_directories('')
def do_list_directories(self, line): """ List all set-up directories. Option to edit directories. """ dir_type_map = { 'map_dir': 'Map Directory', 'csv_dir': 'CSV Config Directory', 'config_dir': 'Diver Config Directory' } print("\n" + "DIRECTORY TYPE".ljust(23) + "| DIRECTORY PATH") for dir_key in self._directories.keys(): print("{0:22} | {1}".format(dir_type_map[dir_key], self._directories[dir_key])) print( "\nDo you want to edit directories [y/n]? Press <Enter> to exit: ", end='') option = input().lower() if option and str2bool(option): self.do_edit_directories('')
def do_delete_volttron_csv(self, line): """ Delete a registry csv config from volttron (Make sure volttron is running). """ csv_name = line csv_files = list() for f in self._sh('volttron-ctl config list platform.driver').split( '\n'): if f.endswith('csv'): csv_files.append(f) if not csv_name: print( "\nList of all registry csv files in VOLTTRON platform.driver:" ) for csv in csv_files: print(csv) print("\nEnter driver name to delete: ", end='') csv_name = input() csv_name = "{0}.csv".format( csv_name) if not csv_name.endswith('.csv') else csv_name if csv_name not in csv_files: print( "\nRegistry CSV config '{0}' does not exist".format(csv_name)) print( "Do you want to select another registry csv config to delete [y/n]? Press <Enter> to exit: ", end='') option = input().lower() if option and str2bool(option): self.do_delete_volttron_csv('') else: self._sh('volttron-ctl config delete platform.driver {0}'.format( csv_name)) self.list_volttron_config("Delete successful!")
def parse_registry_config(self, old_registry_config_lst): """ Convert original modbus csv format to the new modbus_tk registry_config_lst :param old_registry_config_lst: list of all register dictionaries in old volttron csv format :type old_registry_config_lst: list """ new_registry_config_lst = [] for reg_dict in old_registry_config_lst: point_name = reg_dict.get('Volttron Point Name') register_name = reg_dict.get('Reference Point Name', point_name).replace(" ", "_").lower() address = reg_dict.get('Point Address') datatype = reg_dict['Modbus Register'] unit = reg_dict.get('Units') writable = reg_dict.get('Writable') default_value = reg_dict.get('Default Value', None) description = reg_dict.get('Note', '') mixed_endian = helpers.str2bool( reg_dict.get('Mixed Endian', 'False').lower()) new_registry_config_lst.append({ 'Volttron Point Name': point_name, 'Register Name': register_name, 'Address': address, 'Type': datatype, 'Units': unit, 'Writable': writable, 'Default Value': default_value, 'Mixed Endian': mixed_endian, 'Description': description }) return new_registry_config_lst
def _writable(self): return helpers.str2bool(self._reg_dict.get('Writable', 'False'))
def _op_mode(self): return helpers.OP_MODE_READ_WRITE if helpers.str2bool(self._reg_dict.get('Writable', 'False')) \ else helpers.OP_MODE_READ_ONLY
def _writable(self): return helpers.str2bool(self._reg_dict.get('Writable', 'False'))
def configure(self, config_dict, registry_config_lst): """ Parse driver and csv config to define client transport, add registers to ModbusTKRegister, and set default values for revert reading :param config_dict: dictionary of device configure :param registry_config_lst: the list of all register dictionary parsed from the csv file :type config_dict: dictionary :type registry_config_lst: list """ # Convert keys to lowercase config_dict = dict((k.lower(), v) for k, v in config_dict.items()) registry_config_lst = [ dict((k.lower(), v) for k, v in i.items()) for i in registry_config_lst ] # Log warning if registry_config_lst is empty if not registry_config_lst: _log.warning("Registry config csv is empty.") name = config_dict.get('name', 'UNKOWN') device_address = config_dict['device_address'] port = config_dict.get('port', None) slave_address = config_dict.get('slave_id', 1) baudrate = config_dict.get('baudrate', 9600) bytesize = config_dict.get('bytesize', 8) parity = parity_map[config_dict.get('parity', 'none')] stopbits = config_dict.get('stopbits', 1) xonxoff = config_dict.get('xonxoff', 0) addressing = config_dict.get('addressing', helpers.OFFSET).lower() endian = config_dict.get('endian', 'big') write_single_values = not helpers.str2bool( str(config_dict.get('write_multiple_registers', "True"))) # Convert original modbus csv config format to the new modbus_tk registry_config_lst if registry_config_lst and 'point address' in registry_config_lst[0]: registry_config_lst = self.parse_registry_config( registry_config_lst) # Get register map and convert everything to lowercase register_map = dict((reg['register name'], reg) for reg in [ dict((k.lower(), v) for k, v in i.items()) for i in config_dict.get('register_map', registry_config_lst) ]) # Log warning for ignored config fields ignored_config_keys = [ k for k in config_dict.keys() if k not in config_keys ] if ignored_config_keys: _log.warning("%s: Ignored config fields: %s", name, ','.join(ignored_config_keys)) try: # Log warning for ignored register map csv column ignored_register_map_csv_columns = [ c for c in list(register_map.values())[0].keys() if c not in register_map_columns ] if ignored_register_map_csv_columns: _log.warning("%s: Ignored register map csv columns: %s", name, ','.join(ignored_register_map_csv_columns)) except IndexError: # Log warning if register_map is empty if not register_map: _log.warning("Register map csv is empty.") # Get the list of selected register dictionary based on Register Name from registry_config_lst selected_registry_config_lst = list() for reg_dict in registry_config_lst: reg_name = reg_dict.get('register name') try: register_map[reg_name].update(reg_dict) selected_registry_config_lst.append(register_map[reg_name]) except KeyError: _log.warning("No register name matching found: %s", reg_name) # Log warning if selected_registry_config_lst is empty if not selected_registry_config_lst: _log.warning("The selected registry config list is empty.") # Generate the subclass of Client from the device config and register list modbus_client_class = Map( name=name, addressing=addressing, endian=endian, registry_config_lst=selected_registry_config_lst).get_class() self.modbus_client = modbus_client_class( device_address=device_address, port=port, slave_address=slave_address, write_single_values=write_single_values) # Set modbus client transport based on device configure if port: self.modbus_client.set_transport_tcp(hostname=device_address, port=port) else: self.modbus_client.set_transport_rtu(device=device_address, baudrate=baudrate, bytesize=bytesize, parity=parity, stopbits=stopbits, xonxoff=xonxoff) # Insert driver/interface registers for reg_dict in selected_registry_config_lst: register = ModbusTKRegister( reg_dict.get('volttron point name'), reg_dict.get('default value', None), self.modbus_client.field_by_name( reg_dict.get('register name'))) self.insert_register(register) if not register.read_only and register.default_value: self.set_default(register.point_name, register.default_value)
def _mixed(self): return helpers.str2bool(self._reg_dict.get('mixed', 'false').lower()) or \ helpers.str2bool(self._reg_dict.get('mixed endian', 'false').lower())
def do_add_driver_config(self, line): """ Add/Edit the driver config <config_dir>/<driver name>.config for selected driver Example format: { "driver_config": {"name": "watts_on_1", "device_type": "watts_on", "device_address": "/dev/tty.usbserial-AL00IEEY", "port": 0, "slave_id": 2, "baudrate": 115200, "bytesize": 8, "parity": "none", "stopbits": 1, "xonxoff": 0, "addressing": "offset", "endian": "big", "write_multiple_registers": True, "register_map": "config://watts_on_map.csv"}, "driver_type": "modbus_tk", "registry_config": "config://watts_on.csv", "interval": 120, "timezone": "UTC" } If any config info does not match existed options, it'll set to its default value Option to select driver if no selected driver found Press <Enter> to exit Add a specific driver config: add_driver_config <name> <name>: name of a new driver config to add to config_dir Select name after the cmd: add_driver_config """ # Select device type device_type = dict() device_type_name = line if not device_type_name: self.get_device_type_descriptions() print('\nEnter device type name: ', end='') device_type_name = raw_input().lower() for device in self._device_type_maps: if device.get('name', None) == device_type_name: device_type = device # If device type exist, add driver config if device_type: print("Enter driver name: ", end='') name = raw_input().lower() config_dir = self.get_existed_directory(self._directories['config_dir'], 'config_dir') if config_dir: cont = True while cont: cont = False for f in os.listdir(config_dir): if f.endswith('.config') and f.split('.')[0] == name: self.do_driver_config(name) print("Driver '{0}' already existed. Continue to edit the driver [y/n]: ".format(name), end='') option = raw_input().lower() if not option or not str2bool(option): print("Please choose a different driver name OR press <Enter> to quit: ", end='') name = raw_input().lower() if not name: self.do_quit('') cont = True print('Enter interval (default to 60 seconds): ', end='') try: interval = int(raw_input()) except ValueError: interval = 60 print('Enter device address: ', end='') device_address = raw_input().lower() print('Enter port (default to 5020 - 0 for no port): ', end='') try: port = int(raw_input()) except ValueError: port = 5020 print('Enter description: ', end='') description = raw_input() addressing = device_type.get('addressing', 'offset') endian = device_type.get('endian', 'big') print("Default endian for the selected device type '{0}' is '{1}'. Do you want to change it [y/n]: ".format( device_type_name, endian), end='') option = raw_input().lower() if option and str2bool(option): print('Enter new endian. Press <Enter> if no change needed: ', end='') new_endian = raw_input().lower() if new_endian in ('big', 'little', 'mixed'): endian = new_endian write_multiple_registers = str2bool(str(device_type.get('write_multiple_registers', 'True'))) csv_map = self.get_existed_file(self._directories['csv_dir'], device_type.get('file')) print('Enter CSV config file: ', end='') csv_config = raw_input() csv_config = csv_config if csv_config.endswith('.csv') else "{0}.csv".format(csv_config) csv_config = self.get_existed_file(self._directories['csv_dir'], csv_config) driver_config = { "driver_config": {"name": name, "device_type": device_type_name, "device_address": device_address, "port": port, "addressing": addressing, "endian": endian, "write_multiple_registers": write_multiple_registers, "register_map": "config://" + csv_map, "description": description}, "driver_type": "modbus_tk", "registry_config": "config://" + csv_config, "interval": interval, "timezone": "UTC" } # RTU transport if not port: print('Enter slave id (default to 1): ', end='') try: slave_id = int(raw_input()) except ValueError: slave_id = 1 print('Enter baudrate (default to 9600): ', end='') try: baudrate = int(raw_input()) except ValueError: baudrate = 9600 print('Enter bytesize (default to 8): ', end='') try: bytesize = int(raw_input()) except ValueError: bytesize = 8 print('Enter bytesize (default to none): ', end='') parity = raw_input() if parity not in ('none', 'even', 'odd', 'mark', 'space'): parity = 'none' print('Enter stopbits (default to 1): ', end='') try: stopbits = int(raw_input()) except ValueError: stopbits = 1 print('Enter xonxoff (default to 0): ', end='') try: xonxoff = int(raw_input()) except ValueError: xonxoff = 0 driver_config['driver_config'].update({ "slave_id": slave_id, "baudrate": baudrate, "bytesize": bytesize, "parity": parity, "stopbits": stopbits, "xonxoff": xonxoff }) with open("{0}/{1}.config".format(self._directories['config_dir'], name), 'w') as config_file: json.dump(driver_config, config_file, indent=2) else: print("Device type '{0}' does not exist".format(device_type_name))
def do_add_driver_config(self, line): """ Add/Edit the driver config <config_dir>/<driver name>.config for selected driver Example format: { "driver_config": {"name": "watts_on_1", "device_type": "watts_on", "device_address": "/dev/tty.usbserial-AL00IEEY", "port": 0, "slave_id": 2, "baudrate": 115200, "bytesize": 8, "parity": "none", "stopbits": 1, "xonxoff": 0, "addressing": "offset", "endian": "big", "write_multiple_registers": True, "register_map": "config://watts_on_map.csv"}, "driver_type": "modbus_tk", "registry_config": "config://watts_on.csv", "interval": 120, "timezone": "UTC" } If any config info does not match existed options, it'll set to its default value Option to select driver if no selected driver found Press <Enter> to exit Add a specific driver config: add_driver_config <name> <name>: name of a new driver config to add to config_dir Select name after the cmd: add_driver_config """ # Select device type device_type = dict() device_type_name = line if not device_type_name: self.get_device_type_descriptions() print('\nEnter device type name: ', end='') device_type_name = input().lower() for device in self._device_type_maps: if device.get('name', None) == device_type_name: device_type = device # If device type exist, add driver config if device_type: print("Enter driver name: ", end='') name = input().lower() config_dir = self.get_existed_directory( self._directories['config_dir'], 'config_dir') if config_dir: cont = True while cont: cont = False for f in os.listdir(config_dir): if f.endswith('.config') and f.split('.')[0] == name: self.do_driver_config(name) print( "Driver '{0}' already existed. Continue to edit the driver [y/n]: " .format(name), end='') option = input().lower() if not option or not str2bool(option): print( "Please choose a different driver name OR press <Enter> to quit: ", end='') name = input().lower() if not name: self.do_quit('') cont = True print('Enter interval (default to 60 seconds): ', end='') try: interval = int(input()) except ValueError: interval = 60 print('Enter device address: ', end='') device_address = input().lower() print('Enter port (default to 5020 - 0 for no port): ', end='') try: port = int(input()) except ValueError: port = 5020 print('Enter description: ', end='') description = input() addressing = device_type.get('addressing', 'offset') endian = device_type.get('endian', 'big') print( "Default endian for the selected device type '{0}' is '{1}'. Do you want to change it [y/n]: " .format(device_type_name, endian), end='') option = input().lower() if option and str2bool(option): print('Enter new endian. Press <Enter> if no change needed: ', end='') new_endian = input().lower() if new_endian in ('big', 'little', 'mixed'): endian = new_endian write_multiple_registers = str2bool( str(device_type.get('write_multiple_registers', 'True'))) csv_map = self.get_existed_file(self._directories['csv_dir'], device_type.get('file')) print('Enter CSV config file: ', end='') csv_config = input() csv_config = csv_config if csv_config.endswith( '.csv') else "{0}.csv".format(csv_config) csv_config = self.get_existed_file(self._directories['csv_dir'], csv_config) driver_config = { "driver_config": { "name": name, "device_type": device_type_name, "device_address": device_address, "port": port, "addressing": addressing, "endian": endian, "write_multiple_registers": write_multiple_registers, "register_map": "config://" + csv_map, "description": description }, "driver_type": "modbus_tk", "registry_config": "config://" + csv_config, "interval": interval, "timezone": "UTC" } # RTU transport if not port: print('Enter slave id (default to 1): ', end='') try: slave_id = int(input()) except ValueError: slave_id = 1 print('Enter baudrate (default to 9600): ', end='') try: baudrate = int(input()) except ValueError: baudrate = 9600 print('Enter bytesize (default to 8): ', end='') try: bytesize = int(input()) except ValueError: bytesize = 8 print('Enter bytesize (default to none): ', end='') parity = input() if parity not in ('none', 'even', 'odd', 'mark', 'space'): parity = 'none' print('Enter stopbits (default to 1): ', end='') try: stopbits = int(input()) except ValueError: stopbits = 1 print('Enter xonxoff (default to 0): ', end='') try: xonxoff = int(input()) except ValueError: xonxoff = 0 driver_config['driver_config'].update({ "slave_id": slave_id, "baudrate": baudrate, "bytesize": bytesize, "parity": parity, "stopbits": stopbits, "xonxoff": xonxoff }) with open( "{0}/{1}.config".format(self._directories['config_dir'], name), 'w') as config_file: jsonapi.dump(driver_config, config_file, indent=2) else: print("Device type '{0}' does not exist".format(device_type_name))
def _op_mode(self): return helpers.OP_MODE_READ_WRITE if helpers.str2bool(self._reg_dict.get('Writable', 'False')) \ else helpers.OP_MODE_READ_ONLY
def do_add_device_type(self, line): """ Add a new device type to maps.yaml Each entry look like: addressing: offset endian: big write_multiple_registers: False file: elkor_wattson.csv name: elkor wattson description: reading some selected registers from elkor wattson meter If addressing and endian do not match existed options, they will set to their default values Option to add more than one Add a specific device type: add_device_type <name> <name>: name of a device type want to add to maps.yaml Select name after the cmd: add_device_type """ edit = False device_type_name = line if not device_type_name: print('\nEnter device type: ', end='') device_type_name = input().lower() yaml_file = self.get_existed_file(self._directories['map_dir'], 'maps.yaml') if yaml_file: for device_type in self._device_type_maps: if device_type.get('name', None) == device_type_name: print("Device type {0} already existed. Edit it [y/n]: ". format(device_type_name), end='') option = input().lower() if option and str2bool(option): edit = True self.do_edit_device_type(device_type_name) else: print("Please choose another name: ", end='') self.do_add_device_type(input().lower()) if not edit: print('Endian (default to big): ', end='') endian = input().lower() if endian not in ('big', 'little', 'mixed'): endian = 'big' print('Addressing (default to offset): ', end='') addressing = input().lower() if addressing not in ('offset', 'offset_plus', 'address'): addressing = 'offset' print('Write multiple registers (default to True) [T/F]: ', end='') write_multiple_registers = False if input().lower() in ( "f", "false") else True print('CSV file: ', end='') csv_file = input() csv_file = csv_file if csv_file.endswith( '.csv') else "{0}.csv".format(csv_file) csv_file = self.get_existed_file(self._directories['csv_dir'], csv_file) print('Description: ', end='') description = input() # Add the new driver to self._device_type_maps self._device_type_maps.append( dict(name=device_type_name, endian=endian, addressing=addressing, write_multiple_registers=write_multiple_registers, file=csv_file, description=description)) # Option to add more print( '\nDo you want to add more device type [y/n]? Press <Enter> to exit: ', end='') option = input().lower() if option and str2bool(option): self.do_add_device_type('') else: # Add the new device type to maps.yaml when done adding self.write_to_map_yaml()
def _mixed(self): return helpers.str2bool(self._reg_dict.get('mixed', 'false').lower()) or \ helpers.str2bool(self._reg_dict.get('mixed endian', 'false').lower())
def do_add_device_type(self, line): """ Add a new device type to maps.yaml Each entry look like: addressing: offset endian: big write_multiple_registers: False file: elkor_wattson.csv name: elkor wattson description: reading some selected registers from elkor wattson meter If addressing and endian do not match existed options, they will set to their default values Option to add more than one Add a specific device type: add_device_type <name> <name>: name of a device type want to add to maps.yaml Select name after the cmd: add_device_type """ edit = False device_type_name = line if not device_type_name: print('\nEnter device type: ', end='') device_type_name = raw_input().lower() yaml_file = self.get_existed_file(self._directories['map_dir'], 'maps.yaml') if yaml_file: for device_type in self._device_type_maps: if device_type.get('name', None) == device_type_name: print("Device type {0} already existed. Edit it [y/n]: ".format(device_type_name), end='') option = raw_input().lower() if option and str2bool(option): edit = True self.do_edit_device_type(device_type_name) else: print("Please choose another name: ", end='') self.do_add_device_type(raw_input().lower()) if not edit: print('Endian (default to big): ', end='') endian = raw_input().lower() if endian not in ('big', 'little', 'mixed'): endian = 'big' print('Addressing (default to offset): ', end='') addressing = raw_input().lower() if addressing not in ('offset', 'offset_plus', 'address'): addressing = 'offset' print('Write multiple registers (default to True) [T/F]: ', end='') write_multiple_registers = False if raw_input().lower() in ("f", "false") else True print('CSV file: ', end='') csv_file = raw_input() csv_file = csv_file if csv_file.endswith('.csv') else "{0}.csv".format(csv_file) csv_file = self.get_existed_file(self._directories['csv_dir'], csv_file) print('Description: ', end='') description = raw_input() # Add the new driver to self._device_type_maps self._device_type_maps.append(dict( name=device_type_name, endian=endian, addressing=addressing, write_multiple_registers=write_multiple_registers, file=csv_file, description=description )) # Option to add more print('\nDo you want to add more device type [y/n]? Press <Enter> to exit: ', end='') option = raw_input().lower() if option and str2bool(option): self.do_add_device_type('') else: # Add the new device type to maps.yaml when done adding self.write_to_map_yaml()
def do_edit_device_type(self, line): """ Edit an existed device type in maps.yaml Press <Enter> if no change needed If addressing and endian do not match existed options, they will remain as existed setting values Edit a specific device type: edit_device_type <name> <name>: name of a device type in maps.yaml List all device before selecting name: edit_device_type """ device_type_name = line if not device_type_name: # Print all device types in maps.yaml self.get_device_type_descriptions() print('\nEnter a device type name you want to edit. Press <Enter> to exit: ', end='') device_type_name = raw_input().lower() existed = False edited = False # Edit the map if the driver name found if device_type_name: for device_type in self._device_type_maps: if device_type.get('name', None) == device_type_name: existed = True print('Change driver type name: ', end='') new_name = raw_input().lower() if new_name and new_name != device_type['name']: device_type['name'] = new_name edited = True print('Change endian: ', end='') new_endian = raw_input().lower() if new_endian in ('big', 'little', 'mixed') and new_endian != device_type['endian']: device_type['endian'] = new_endian edited = True print('Change addressing: ', end='') new_addressing = raw_input().lower() if new_addressing in ('offset', 'offset_plus', 'address') \ and new_addressing != device_type['addressing']: device_type['addressing'] = new_addressing edited = True print('Change write multiple registers option [T/F]: ', end='') new_write_multiple_registers = False if raw_input().lower() in ("f", "false") else True if new_write_multiple_registers != device_type.get('write_multiple_registers', "True"): device_type['write_multiple_registers'] = new_write_multiple_registers edited = True print('Change CSV file: ', end='') new_file = raw_input().lower() if new_file: new_file = self.get_existed_file(self._directories['csv_dir'], new_file) if new_file and new_file != device_type['file']: device_type['file'] = new_file edited = True print('Change Description: ', end='') new_description = raw_input() if new_description and new_description != device_type['description']: device_type['description'] = new_description edited = True # Write to maps.yaml if any information changed if edited: self.write_to_map_yaml() if not existed: print("Device type name '{0}' does not exist".format(device_type_name)) print("Do you want to edit another device [y/n]? Press <Enter> to exit: ", end='') option = raw_input().lower() if option and str2bool(option): self.do_edit_device_type('')
def configure(self, config_dict, registry_config_lst): """ Parse driver and csv config to define client transport, add registers to ModbusTKRegister, and set default values for revert reading :param config_dict: dictionary of device configure :param registry_config_lst: the list of all register dictionary parsed from the csv file :type config_dict: dictionary :type registry_config_lst: list """ name = config_dict.get('name', 'UNKOWN') device_address = config_dict['device_address'] port = config_dict.get('port', None) slave_address = config_dict.get('slave_id', 1) baudrate = config_dict.get('baudrate', 9600) bytesize = config_dict.get('bytesize', 8) parity = parity_map[config_dict.get('parity', 'none')] stopbits = config_dict.get('stopbits', 1) xonxoff = config_dict.get('xonxoff', 0) addressing = config_dict.get('addressing', helpers.OFFSET).lower() endian = endian_map[config_dict.get('endian', helpers.BIG)] write_single_values = not helpers.str2bool( str(config_dict.get('write_multiple_registers', "True"))) # Convert original modbus csv config format to the new modbus_tk registry_config_lst if registry_config_lst and 'Point Address' in registry_config_lst[0]: registry_config_lst = self.parse_registry_config( registry_config_lst) register_map = dict( (reg['Register Name'], reg) for reg in config_dict.get('register_map', registry_config_lst)) # Get the list of selected register dictionary based on Register Name from registry_config_lst selected_registry_config_lst = list() for reg_dict in registry_config_lst: try: reg_name = reg_dict.get('Register Name') register_map[reg_name].update(reg_dict) selected_registry_config_lst.append(register_map[reg_name]) except KeyError: _log.warning( "No register name matching found: {0}".format(reg_name)) # Generate the subclass of Client from the device config and register list modbus_client_class = Map( name=name, addressing=addressing, endian=endian, registry_config_lst=selected_registry_config_lst).get_class() self.modbus_client = modbus_client_class( device_address=device_address, port=port, slave_address=slave_address, write_single_values=write_single_values) # Set modbus client transport based on device configure if port: self.modbus_client.set_transport_tcp(hostname=device_address, port=port) else: self.modbus_client.set_transport_rtu(device=device_address, baudrate=baudrate, bytesize=bytesize, parity=parity, stopbits=stopbits, xonxoff=xonxoff) # Insert driver/interface registers for reg_dict in selected_registry_config_lst: register = ModbusTKRegister( reg_dict.get('Volttron Point Name'), reg_dict.get('Default Value', None), reg_dict.get('Mixed Endian', False), self.modbus_client.field_by_name( reg_dict.get('Register Name'))) self.insert_register(register) if not register.read_only and register.default_value: self.set_default(register.point_name, register.default_value)
def do_edit_device_type(self, line): """ Edit an existed device type in maps.yaml Press <Enter> if no change needed If addressing and endian do not match existed options, they will remain as existed setting values Edit a specific device type: edit_device_type <name> <name>: name of a device type in maps.yaml List all device before selecting name: edit_device_type """ device_type_name = line if not device_type_name: # Print all device types in maps.yaml self.get_device_type_descriptions() print( '\nEnter a device type name you want to edit. Press <Enter> to exit: ', end='') device_type_name = input().lower() existed = False edited = False # Edit the map if the driver name found if device_type_name: for device_type in self._device_type_maps: if device_type.get('name', None) == device_type_name: existed = True print('Change driver type name: ', end='') new_name = input().lower() if new_name and new_name != device_type['name']: device_type['name'] = new_name edited = True print('Change endian: ', end='') new_endian = input().lower() if new_endian in ( 'big', 'little', 'mixed') and new_endian != device_type['endian']: device_type['endian'] = new_endian edited = True print('Change addressing: ', end='') new_addressing = input().lower() if new_addressing in ('offset', 'offset_plus', 'address') \ and new_addressing != device_type['addressing']: device_type['addressing'] = new_addressing edited = True print('Change write multiple registers option [T/F]: ', end='') new_write_multiple_registers = False if input().lower( ) in ("f", "false") else True if new_write_multiple_registers != device_type.get( 'write_multiple_registers', "True"): device_type[ 'write_multiple_registers'] = new_write_multiple_registers edited = True print('Change CSV file: ', end='') new_file = input().lower() if new_file: new_file = self.get_existed_file( self._directories['csv_dir'], new_file) if new_file and new_file != device_type['file']: device_type['file'] = new_file edited = True print('Change Description: ', end='') new_description = input() if new_description and new_description != device_type[ 'description']: device_type['description'] = new_description edited = True # Write to maps.yaml if any information changed if edited: self.write_to_map_yaml() if not existed: print("Device type name '{0}' does not exist".format( device_type_name)) print( "Do you want to edit another device [y/n]? Press <Enter> to exit: ", end='') option = input().lower() if option and str2bool(option): self.do_edit_device_type('')