Device Search on running perspective project

With the site getting bigger, it's difficult to locate a particular instrument/device on the process pages.

Has anyone achieve the function to bring up a search box, by typing the device tag name/select the tag name from dropdown list, then click search button, it can bring you to the exact process page where the device is located?

My amateur thought is:

  1. create a data table with tag name and page name
  2. on the pressed script of the search button, create a lookup script to look for the page name based on the entered tag name
  3. call page navigation script to open the process page from the result of the lookup script.

Any better ideas?

This wouldn't be toooo hard I don't think. I would have a function called periodically that created/updated your dataset in step 1 by reading all view json in the project looking for udt instance name / tag paths and producing your dataset automatically. I always pass in a deviceParentPath and deviceName to my template views, so this wouldn't be too hard to read from my view json and find in a list of udt instances

1 Like

If I'm understanding correctly, I have something like this set up.

A few notes:
As the names are very short and quite similar, the exact name has to be typed, though partial matches could be implemented for longer/more distinctive names (maybe even update the tree to filter it depending on what has been typed so far)
The devices pages look like site_url/device_type/device_name, so I can just navigate to that page using what was typed if it a valid name.
I check that it is indeed a valid name before attempting navigation:

Does that look like what you're looking for ?

1 Like

If the information can be obtained by script, just time-consuming, then I would use a script module top-level dictionary or list to cache the results. Then your search box just has to iterate through that top-level python object. (Top-level script module variables persist until the module is reloaded by a project save.)

1 Like

You mentioned that technic in another thread recently, and I was wondering how you'd read that dictionary ? Would it be only readable through scripts - as in, even a property binding would ultimately have to use a script transform to access it - or do you have technics I haven't though about ?

I'm thinking of using something like that to store and cache data that's pulled from tags, but I'm afraid it would make using the data more complicated than what I'm using right now. Not that I'm scared of implementing it, but I'll have to pass that project to someone else soon and I'm trying to tidy things up to make it as simple as possible.

Yes, or runScript() or objectScript() expressions. runScript() should delegate to a function in that same script module for best performance. (objectScript() is most efficient with one-liners, which can still use args, unlike runScript.)

Any time Ignition calls a script, there's some overhead. Balance that overhead against the time saved by having cached values available. Caching often wins. Sometimes wins big, with an overall gateway CPU usage improvement.

Thanks. I have absolutely no doubt the overhead would be negligible compared to the gains here.

Just to make sure I'm getting this right:

  • In a project library script, create a dictionary.
  • populate the initial data through a gateway startup script or the initialChange of a gateway event tag change script (any reason to use one or the other ?)
  • add a gateway event tag change script that monitors all concerned tags to update dictionary
  • read from the dictionary instead of tags

What am I missing ?

Basically right, but I wouldn't do this for tag values. Tag bindings (including indirect) are already the fastest way to deliver values to UIs. Use tag bindings instead of*() calls anywhere, and instead of this kind of caching.

When you do this kind of thing, include a function that will initially populate the cache, and call it from the top level at the end of your project script. This will ensure the cache is re-populated any time the project is saved.

Or, if the contents of the cache are native jython or java objects, you can put the cache in the system.util.getGlobals() dictionary. Then you only need something to refresh it occasionally.

Really ? I guess I'm not touching anything then !

Thank you all for the comments.
I will get this function programmed next week.

Just got time this week to complete this task.

When you mentioned, "Reading all view json", is there any ignition script I can use to directly search through all views under the "Views" folder, or I have to go to the project folder on the gateway to go through each view? Like the project views path below:

C:\Program Files\Inductive Automation\Ignition\data\projects\PROJECT_NAME\com.inductiveautomation.perspective\views\

Also my views are embedded, the core process view are programmed using "coordinate view" and then it's embedded to "Flex View" for better display on the phone. It will add up some complexity on locating the items. My thought is to allocate the items from the core views first, then by using prefix to allocate the actual view URL.

what's the script you use to search the perspective html file?

I'm not touching the html. The search is done in the same source the tree uses.

The search is done in the same source the tree uses.

Not sure what you meant by this.

I am thinking reading each view file from the gateway and then find out the cfgTagName been defined for each dynamo. But I am not sure whether I can call a gateway script to read the view file from the gateway. It should be ok, I will test it out tmr.

What I mean is that there's something populating the tree. In my case, it's a session.custom property.
The search is done on that property.

What's your use case exactly ?

Here's more details about my particular use case:

  • session.custom.devices: This is the base source. How it's built doesn't matter here.
  • in the view, there's a tree. The items property of that tree is bound to session.custom.devices, and it has this script transform:
def transform(self, value, quality, timestamp):
	return [
			'label': "Zone {}".format(z.zone_num),
			'data': "",
			'items': [
					'items': [],
					'expanded': False
				} for tcu in z.tcu_list
			'expanded': False
		} for z in value
  • There's also a text field, which has a custom property custom.tcu_list bound to session.custom.devices and this script transform (it simply lists all the devices of type 'tcu'):
def transform(self, value, quality, timestamp):
	return [ for z in value for tcu in z.tcu_list]
  • The text field's text property is bound to the tree's selection, so that it displays the currently selected device
  • The text field has a keyboard onKeyDown event script, that checks when the user presses enter if the entered device name exists in the list stored in custom.tcu_list:
def runAction(self, event):
	if event.key == "Enter":
		tcu = self.props.text
		if tcu in self.custom.tcu_list:
			self.parent.parent.getChild("info_message").props.text = "This TCU doesn't exist"
  • the button's onActionPerformed event has a similar script.

Thanks for the detailed description.

How do you build the custom.tcu_list?
How do you search all configured tcu and link the view page name to each tcu?

It's already explained.

search in the list, navigate to the proper page if the tcu is found, otherwise display an error message:

1 Like