Tracking perspective app coordinates

For my project, I need to periodically (say, once every 30 seconds) track the GPS coordinates of a number of mobile devices (running a perspective app) and insert their timestamped location in a database located on the gateway. I don’t mind whether the script runs on the client or on the gateway, as long as I can get the job done. Now, I’m not able to find a place where I can schedule a script to run periodically in perspective. In Vision we had a “timer” in the client events, but I see no such thing in perspective’s session events.

Any advice is welcome.

Two things:

  1. When it comes to Perspective don’t think of scripts as running on the device or in the browser; ALL Perspective scripts are run on the Gateway. This means that you also need to pay attention to anything that says “scope” in the documentation. If you see something that is only available in the “Client” scope, then you can’t use it, and if it says “Gateway” scoped, it will work in Perspective, but it runs on the Gateway (so something like system.net.getIPAddress() can be used in Perspective, but it will return the Gateway IP because that’s where the script is running).

  2. What you could try is Using a Gateway Timer script (Click “Project > Gateway Events” in the top menu of the Designer) to “ping” active Perspective Sessions for their GPS coordinates. This requires a couple of things be in place to work:

  • Devices must have enabled location tracking for the application.
  • Sessions will need to have some sort os Session startUp event which records the new SessionId with the Gateway in some manner (and also a Session shutDown event which removes the SessionId from your registry)

Thanks. Unfortunately that begs even more questions.

  1. How does the gateway “ping” a client? I need access to the perspective session properties for each client (which is where the GPS info is stored), or alternatively, ask the client to send them down. Either way, I haven’t found anything in the scripting reference.

  2. How does a client register an id with the gateway, or, for that matter, send any information to the gateway?

  3. Speaking of ids, ideally I’d want to use something that uniquely identifies a device, eg the IMEI. Does perspective provide access to this kind of information?

  4. If everything runs on the gateway, how can I handle client disconnections? Ideally, if the devices becomes disconnected it should keep recording its location periodically, and send the batch of data to the gateway as soon as it’s back online. It seems to me that if everything is managed from the gateway this becomes impossible.

  1. You’d probably want to use something like system.perspective.sendMessage() (and you’d need to specify the typically optional sessionId param) to send a request to each registered session, which is why you MUST have each Session register their ID on startup. Each Session would then have a configured Listener, but here’s the catch: in Perspective, the basic rule for whether or not a Listener “exists” is if it’s present in the browser/application DOM, so you’d need to configure a Listener on some root container which is ALWAYS 100% present in the DOM (but you can make it invisible). That Listener would then use system.util.sendMessage() to send a message which contains its current GPS info back to the Gateway.

  2. Click “Project > Session Events” in the Designer’s top menu, and use the Session Startup Script to call something like
    system.util.sendMessage(project=<project_name>,messageHandler=<name_of_handler>,payload={newSessionId:session.props.id})

  3. You should be able to use session.props.device.identifier for a unique device ID.

  4. If your device is offline, I can tell you that NO scripts will be executing in the browser/application. It doesn’t matter where you set them up or what they do - all Perspective scripts run Gateway-side, so (for the foreseeable future) if you’re not connected to the Gateway, any functionality built on scripting will not function.

Also, you’ll want to incorporate logic into the timed Gateway script to unregister Session IDs which fail to ping after so many attempts, otherwise you’ll just have an ever-expanding list of Sessions which won’t even be accurate.

1 Like

Thanks, I had overlooked the sendMessage() functions.

Regarding 1., does the gateway have some sort of “session” or “global” variables (ie, always visible in the gateway events message handlers) where to store the active sessions or must one save them in a database or other external location?

Regarding 4., if it were a hard requirement, I suppose something could be knocked together using javascript (which the client surely does run), does ignition provide some way to use custom JS code in the client?

You would have to create a custom module. Perspective (deliberately) does not expose any frontend code to the designer.

EDIT: Although, if I understand the initial concern correctly, it might be a moot point. I know that we "bundle" accelerometer data clientside in order to send it back once the connection has resumed - I don't know for sure that GPS data works the same way, but I wouldn't be surprised.

I think barcode scans also work that way, that’s why I initially thought that GPS could somehow be managed in the same way (buffered while disconnected, then sent bundled when connection is resumed).

It seems to me that there will be no real "ping" (eg request/response), since the system.perspective.sendMessage() call doesn't really return anything that indicates whether the client has received the message or not, so the "n failed ping attempts" condition really is not simple to detect, since the client replies are received in another part of the code (the gateway message handler that is triggered when the client sends back the coordinates). That could perhaps be solved by embedding unique IDs in the gateway requests and have the clients echo it back in their replies to correlate them, and assume that if the client has not sent back a reply for a given ID or IDs it's because it's disconnected.
However, if the client remains disconnected for too much (very likely since they will be moving in rural zones), ignition's own timeout may kick in and generate an end_session event, which will then have to be invalidated or otherwise updated when the client subsequently reconnects.

Also, is there a way to share state among various gateway-side scripts? I understand tags are a possibility, are there other/better ways?

No, they're intended to be independent and not reliant on each other. As you said, Tag reading is the best way to communicate info across scripts.

Don't invalidate, just treat it as a new Session, because that's how Perspective/Ignition will treat it.

In whatever registry you create for the session IDs (probably a dataset tag somewhere), you could include a column which is just an Int. On session_begin, initialize the column to zero and on any update from a session, set that value BACK to zero. Include a Timed Verification Gateway script which checks that number every x seconds, and increments the value. After incrementation, if the value is greater than or equal to (<latency_wait>/2), then the session has failed to reply in time and should be removed (this step COULD conceivably just be handled by the session_end code if you prefer).

Makes sense. Now I wonder what would happen if the gateway is restarted with active sessions. I guess memory tags are not persistent, so perhaps I could use a gateway shutdown script to persist the current sessions (eg to a database) and a startup script to reload them.

Okay, it’s definitely a bug on our end, and we’re looking into it. The reason it “worked” for me, was because I was not actually using a Session StartUp event, I was just populating a property and saw the value I expected to see.

From looking at the code, it looks like we’re expressly setting the device ID to an empty string during Session Startup, but the reasoning is not clear at this time. I’ve reached out to some Devs and we’ll address the ticket as necessary.

In the meantime, you can add logic into the Gateway receipt of a Session’s response to insert the device ID if it does not already exist (or if it doesn’t match what was just supplied) as the property is correctly applied shortly after session startup.

They absolutely should be persistent, and if you find that they're not we have a problem. Session properties are not persistent, but tags are forever (until they're expressly modified in some way).

Ah cool, so I don’t even need the workaround. Thanks!

1 Like

Another alternative/workaround to getting the device ID is to move the Session startUp script into the View startUp script for your project’s PERMANENT home page. This is dangerous however, as if a device ever reaches your project through browser history or a shared link which doesn’t hit the home page first you will fail to fire the event.

Does this mean sending another request from the gateway to the client just after the start_session message is received?

Yes and no.

My recommendation was to send out a timed ping/request from the Gateway (every n seconds on a timer). As of right now, you won’t have the Device ID after the first response, but you will on subsequent responses. So you’ll need a second request/response phase, but if you’re okay with waiting just waiting until the second request to register the ID, you can just wait until then.

So your logic wold look like

  1. On Session Start, SESSION sends session_start message to Gateway (including SessionId and DeviceId, even though it’s not in place).
  2. GATEWAY receives session_start message, and registers the SessionId along with the empty DeviceId.
  3. After n seconds, the GATEWAY sends an update_coordinates message.
  4. All SESSIONS respond to the update_coordinates message by sending a session_coordinates message to the Gateway which contains their SessionId, DeviceId (which is now in place), and GPS information.
  5. GATEWAY receives updates from all SESSIONS, and updates the registry. During this phase, if the DeviceId does not match what is already registered for a SessionId, replace the DeviceId with what was received.
1 Like

Ok, makes sense. Including the device id in all messages sent from the session also helps to follow the same device when its session id changes (because of disconnection timeout or other causes).

It looks like the device ID needs about 3 seconds to become available. My initial attempt was to send a request for the device ID immediately after the start_session event was received on the gateway. This way, the session doesn’t even receive the device ID request message (may this be a bug?)

Then I slept for 1 second before sending the device ID request, and this time the session does get the message, but the device ID in the reply is still empty.

Sleeping for 3 seconds before requesting the device ID finally makes it appear.

Is this time normal?

I don’t know the determining factor in when that ID becomes part of the Session, but I do know there is active work being done to make the DeviceId available on Session StartUp. By Tuesday or Wednesday you should get it as part of the first response.

1 Like

This doesn't seem to have been implemented yet, am I missing something?