How to read properties of existing device connection - Example Code

I had often been disappointed that not all device connection properties for existing devices were easily available through supported scripting (system.device.listDevices()) . I recently had cause to develop a methodology to create/update/remove devices, UDTs (definitions/instances), tags and tag alarms based on an Excel workbook. Without scripted access to device connection properties it was difficult to determine whether a device required an update so I dug in and finally found a way to retrieve all device connection properties.

Disclaimers:

  • This methodology is not officially supported in that it uses classes and functions that are not guaranteed to stay consistent between minor/major Ignition versions. However I expect it will continue to work for all future Ignition v8.1.x releases.
  • This methodology was developed in Ignition 8.1.50, do not expect it to work in Ignition v8.3.x
  • The code provided must run in the Gateway context (run from Gateway message handler, Gateway event script, or Perspective script)
  • As far as scripted update of device properties, probably the most advisable option is to read the existing properties for the device, organize it in such a way that it can can be used to create a new device using system.device.addDevice(), apply whatever modification is needed, then delete/remove the existing device and add a new one with the modified properties.

Credit
This methodology was developed through examination and extrapolation of hints left in other forum posts but none of those threads provided a functioning example. I’ll attempt to leave a list of referenced forum threads here.

Example Code:

import traceback
def getDeviceConfigurations():
	"""Returns a list of dictionaries, each dictionary containing device configuration.
	This methodology is not officially supported in that it uses classes and functions 
	that are not guaranteed to stay consistent between minor/major Ignition versions. 
	However I expect it will continue to work for all future Ignition v8.1.x releases.
	"""
	logger = system.util.getLogger("getDeviceConfigurations")
	session = IgnitionGateway.get().getPersistenceInterface().getSession()
	try:
		# Query the Ignition Internal Database for the names of tables containing device connection settings/properties
		# It appears these tables end in either "DEVICESETTINGS" or "DRIVERSETTINGS"
		# but it is possible some relevant tables have been overlooked.
		logger.info("Table Names | performing query...")
		sql = "SELECT name FROM sqlite_master WHERE type='table' AND ( name LIKE '%DEVICESETTINGS' OR name LIKE '%DRIVERSETTINGS' )"
		flush=True
		params=[]
		result = session.rawQueryMaps(sql, flush, params)
		tableNames = [item["name"] for item in result]
		logger.infof("Table Names | Count: %d | Result: %s", len(result), tableNames)
		
		# Query each table for device connection settings/properties
		deviceConfigs = {}
		for tableName in tableNames:
			logger.infof("Table '%s' | performing query...", tableName)
			sql = "SELECT * FROM %s" % tableName
			flush=True
			params=[]
			result = session.rawQueryMaps(sql, flush, params)
			logger.infof("Table '%s' | Count %d devices | Result: %s", tableName, len(result), str(result))
			
			for deviceConfig in result:
				# Determine the device setting ID
				# This ID is used to associate the "DEVICESETTINGS" table with the relevant device driver table
				# "DEVICESETTINGS_ID" is used in the "DEVICESETTINGS" table
				# "DEVICESETTINGSID" is used in the relevant device driver tables
				if "DEVICESETTINGS_ID" in deviceConfig:
					deviceSettingsId = deviceConfig["DEVICESETTINGS_ID"]
				else:
					deviceSettingsId = deviceConfig["DEVICESETTINGSID"]
				for propertyKey, propertyValue in deviceConfig.items():
					logger.infof("Table: %s Key: %s Value: %s", tableName, propertyKey, propertyValue)
					if propertyKey in ["DEVICESETTINGSID", "DEVICESETTINGS_ID"]:
						continue
					else:
						# Table "DEVICESETTINGS" contains the standard/common device properties
						# Other tobles contains the driver specific device properties
						deviceConfigs.setdefault(deviceSettingsId, {})[propertyKey]=propertyValue
		for deviceId, deviceConfig in deviceConfigs.items():
			logger.infof("Device ID: %d | Name: %s | Config: %s", deviceId, deviceConfig["NAME"], deviceConfig)
		return deviceConfigs.values()
	except:
		logger.error(traceback.format_exc())
		raise
	finally:
		session.close()

Bonus:
Found out late in the game that the Ignition gateway provides a URL (http://localhost:8088/web/status/sys.internaldb) with interface that can be used to query the internal database.

2 Likes
1 Like

OK, I thought you were joking but I tried it and it works! Apparently I am not cultured enough to recognize that from the world of video games; had to look up what it is, assuming it was a cheat code with historical significance (see Konami Code). I blame my ignorance on never having had an NES. Of course now I am wondering what other hidden Ignition features I am unaware of.

2 Likes