Workaround to access Perspective user source from Gateway

i need a workaround to be able to access the Perspective project's user source from the Gateway scope. i'm tasked with building a granular alarm roster and i'm boned because none of the Perspective project stuff is available from the Gateway scope (as i understand from support). so i can't help but wonder if someone has come up with a clever workaround for this problem. not having the depth of Ignition knowledge i'd like yet, i'm not familiar with what can and can't be accessed from the Gateway scope that the Perspective project can write to. my thinking is the project can write to some Gateway-accessible maguffin so when i build my alarm roster, i can get that user source name and data.

Can you expand upon what you mean a bit more?
The gateway and perspective are both running on the same JVM, meaning the same memory, etc - sharing information is "easy" between the two. From some arbitrary gateway context you can't directly run (most) Perspective scripting, because your script doesn't have the implicit contextual info to know what Perspective "thing" to talk to. You can still pass that Perspective info manually using kwargs on the functions, though, and they'll still work.

if i run system.tag.readBlocking('[System]Client/System/UserSource')[0].value in a project, i get the name of the user source: SpankytownRacers. if i run the same thing building a custom alarm roster, i get None. according to tech support this only works in Vision because Gateway doesn't have access to the Perspective project's session objects.

That's a pretty poor explanation of what's going on here.

I would explain it as "all of the tags in the Client folder, under the System tag provider, are provided by the Vision module, and only exist in its scope".

But I'm still confused. You mention alarm rosters (Gateway scoped, user sources) and then Perspective session objects (Gateway/Perspective scoped, identity providers) - I don't see how you're trying to tie the two together. You don't even use user sources (directly) in Perspective, so anything you're doing is going to ultimately be fragile (what if you change your project to a non-Ignition IdP?)

If you're actually asking "given a particular project's name, how can I retrieve the user source assigned in it's general properties" - that's a fair question, and answerable. I think that's what you're asking, but all the Perspective stuff is throwing me off.

okay. more detail:

we have a very granular, per-asset permission system. it included notification settings for each asset in a project so some people are notified only for their assigned assets. to that end, we need to build a custom roster for asset alarms that are assigned. in other words, a project handles data for 6 assets. 2 of those assets are assigned to one guy, 3 to another, and all 6 to yet a third. when an alarm pipeline is triggered, an alarm notification needs to go ONLY to the assigned guy. and as you can see, there's some overlap.

so. i built a script that generates that email roster based on the granular permissions of each asset. works perfectly in a Perspective view. when i translocate it to the Pipeline Block Editor's Notification block, the script generates an empty list because the code that points to the user source doesn't return the name of the project's user source, it returns None. so nothing gets sent out; an empty list means no emails/SMS messages. and since this is on a Master project, i am unable to hardcode the user source because each leaf (?) needs to define it's own user source.

from my conversation with tech support, the reason i get None is because the Gateway apparently cannot access the project's Perspective attributes. basically the same reason the Script Console is functionally useless for Perspective testing.

so, okay, software limitation. time for a workaround, because this is critical for our clients. which brings us to the question i posted.

does that clarify better? :crossed_fingers:

EDIT: a (better) screenshot to help visualize what i'm talking about ↓ and this is per user:

Sort of? I understand the problem you're describing, but still not quite why it's a problem.

What are you retrieving/doing/whatevering in this script that actually requires Perspective? Just the user source piece? Could you elevate this generated list to a tag somewhere, so you can easily read/bind to it in Perspective and alarm pipelines?

From the outside looking in, with no knowledge of actual operational complexities (my preferred place to be :smile:) it really sounds like this data should either be calculated once and stored somewhere (a database, or failing that, in the tag system in Ignition) or if it has to be calculated repeatedly, there should be a single project library script that relies on no implicit context and is "pure" - it should take user source, asset identifier, etc as inputs, and return your list of users (or whatever) as the sole output.

Basically, my stumbling block is these two sentences:

i built a script that generates that email roster based on the granular permissions of each asset. works perfectly in a Perspective view.

Because I don't see how calculating the "granular permissions of each asset" should have any reliance on anything provided by Perspective at all.

i'm still digesting... and please know i've had basically 2wks of ramp on Ignition before just being thrown into the mix, so i fully admit to being functionally stupid a lot of times as to things Ignition. but i do have a fair amount of developer experience. so forgive me if my terms are not from the Ignition lexicon. :stuck_out_tongue_winking_eye: i promise i'm not trying to be obtuse! :slight_smile:

so. it feels like i'm missing something important, and it's niggling in the back of my brain... but until it pops, let me explain a bit more.

because our end-user is bascially on par with a box of rocks in terms of computer literacy, we have to make everything (every. damn. thing) retard-proof. to that end, we have, from what i understand, 2 user data 'sources': 1 is Ignition, which provides authentication and overarching roles (basically a global permission). then each project also has a set of datasets in the user source that provide the granular permissions per asset and per user. see hopefully useful image ↓
Screenshot 2024-01-29 103347

so. from the Alarm pipeline's Custom Roster, which as i understand is Gateway scoped, i need to access that Project's User Source to then pull the data from the dataset for determining who gets the notification. which apparently is NOT doable because, so i was told, the Gateway cannot see those datasets because they are in a scope it can't access. if this is not the correct way, i'm all ears, believe me. with my limited knowledge and going by what i've inherited, this seemed the best way to go.

any clearer? :crossed_fingers: :crossed_fingers: :pray:

Tags are Gateway Global.

They can be reached from anywhere. The exception are tags located in the Vision Client Tags, which are only available in Vision Client Scope.

What you have indicated as a "User Source" is not a User Source, it is a Tag Provider. Tag Providers are found on the Gateway Webpage at Config > Tags > Realtime Tag Providers

User Sources would be found under Config > Security > UserSources


You should also be able to 'back into' a tag provider from an alarm by examining the path.

1 Like

oh! okay. so the guys here are using the wrong terms. great. :poop: but that does help explain why my question was confusing. i will amend moving forward as well as browbeat the dudes here.

... interval with tech support's callback ...

okay. turns out i'm just looking for love in all the wrong places. using the event.source, i can parse the resultant string and get the prov: from that. solved my problem. which i believe is what you, @PGriffith, were saying about 'backing into a tag provider'.

please accept my apologies for bad term use, which resulted in a lot of unnecessary confusion. and i offer my thanks for your incredible patience. you're all champs, and i appreciate all your help. :100:

EDIT: event.source yields a lovely mess: prov:Whitewater:/tag:Alarms/debugAlarmTrip:/alm:Alarm. no spaces. random colons. so fun to parse. :fork_and_knife:

I'm not sure what type you're getting back, but there may be a "better" way to get the provider than by string parsing.

i just edited my last post. yeah. i wish there was a better way, but it doesn't look like it. :face_with_spiral_eyes:

This is in an alarm pipeline? Where is this script being called from? Trying to figure out what event.source is.

It's a QualifiedPath, which there's helpfully a static method to parse:

But to @lrose' point, may still not be necessary.

Okay, looks like the object is a QualifiedPath.

So you can just use:


Which will return the first component of the path, in this case the provider.

For instance this code:

from com.inductiveautomation.ignition.common import QualifiedPath

path = QualifiedPath.parse('prov:Whitewater:/tag:Alarms/debugAlarmTrip:/alm:Alarm')

print path.firstPathComponent

returns Whitewater

If you would like it to be more explicit then you could use:


The first will be more performant though.

To go one step further you could then use it to build a tagPath for your call to get the dataset:

from com.inductiveautomation.ignition.common import QualifiedPath
from com.inductiveautomation.ignition.common.tags.paths import BasicTagPath

path = QualifiedPath.parse('prov:Whitewater:/tag:Alarms/debugAlarmTrip:/alm:Alarm')

tagPath = BasicTagPath(path.firstPathComponent,['Users','allassets'])

print tagPath.toStringFull()



okay. that's friggin' awesome. :100: :partying_face: that's exactly what i needed. cannot express how awesome this is.

dammit. imma have to learn Kotlin...

1 Like