# Device Search on running perspective project

**URL:** <https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [October 26, 2022, 4:58am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689 "2022-10-26T04:58:31Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [October 26, 2022, 4:58am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/1 "2022-10-26T04:58:31Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [October 26, 2022, 7:35am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/2 "2022-10-26T07:35:01Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 26, 2022, 9:05am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/3 "2022-10-26T09:05:02Z")

</div>

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

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/c/c/cc984f6f76576a3b620416ed14145af2ae00252f.png)

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:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/5/9/5910888926e277294b2b75c998b423856665c44b.png)

Does that look like what you're looking for ?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 26, 2022, 12:49pm UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/4 "2022-10-26T12:49:01Z")

</div>

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.)

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 26, 2022, 1:07pm UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/5 "2022-10-26T13:07:10Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 26, 2022, 1:09pm UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/6 "2022-10-26T13:09:41Z")

</div>

> [@pascal.fragnoud](#):
>
> have to use a script transform

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.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 26, 2022, 1:19pm UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/7 "2022-10-26T13:19:08Z")

</div>

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 ?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 26, 2022, 1:39pm UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/8 "2022-10-26T13:39:19Z")

</div>

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 `system.tag.read*()` 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.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 26, 2022, 1:46pm UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/9 "2022-10-26T13:46:47Z")

</div>

> [@pturmel](#):
>
> I wouldn't do this for tag values. Tag bindings (including indirect) are already the fastest way to deliver values to UIs

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

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [November 2, 2022, 5:45am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/10 "2022-11-02T05:45:21Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [November 28, 2022, 2:48am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/11 "2022-11-28T02:48:05Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [December 15, 2022, 4:59am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/12 "2022-12-15T04:59:51Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [December 15, 2022, 6:46am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/13 "2022-12-15T06:46:13Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [December 15, 2022, 8:19am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/14 "2022-12-15T08:19:17Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [December 15, 2022, 8:33am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/15 "2022-12-15T08:33:06Z")

</div>

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 ?

edit:  
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:

```python
def transform(self, value, quality, timestamp):
	return [
		{
			'label': "Zone {}".format(z.zone_num),
			'data': "",
			'items': [
				{
					'label': tcu.name,
					'data': tcu.name,
					'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'):

```python
def transform(self, value, quality, timestamp):
	return [tcu.name 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`:

```python
def runAction(self, event):
	if event.key == "Enter":
		tcu = self.props.text
		if tcu in self.custom.tcu_list:
			system.perspective.navigate("/tcu/{}".format(tcu))
		else:
			self.parent.parent.getChild("info_message").props.text = "This TCU doesn't exist"

```

- the button's `onActionPerformed` event has a similar script.

---

<div class="post-metadata">

**Author:** ![chaoliang](https://avatars.discourse-cdn.com/v4/letter/c/ba8739/32.png) [@chaoliang](https://forum.inductiveautomation.com/u/chaoliang)\
**Post date:** [December 15, 2022, 11:02pm UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/16 "2022-12-15T23:02:37Z")

</div>

> [@pascal.fragnoud](#):
>
> custom.tcu\_list

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?

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [December 16, 2022, 7:42am UTC](https://forum.inductiveautomation.com/t/device-search-on-running-perspective-project/65689/17 "2022-12-16T07:42:41Z")

</div>

It's already explained.  
`custom.tcu_list`:

> [@pascal.fragnoud](#):
>
> - 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'):
> 
> ```auto
> def transform(self, value, quality, timestamp):
> return [tcu.name for z in value for tcu in z.tcu_list]
> 
> ```

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

> [@pascal.fragnoud](#):
>
> - 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`:
> 
> ```auto
> def runAction(self, event):
> if event.key == "Enter":
> tcu = self.props.text
> if tcu in self.custom.tcu_list:
> system.perspective.navigate("/tcu/{}".format(tcu))
> else:
> self.parent.parent.getChild("info_message").props.text = "This TCU doesn't exist"
> 
> ```
