--- title: "Perspective Session Event Scripts" --- # Perspective Session Event Scripts > Perspective offers a collection of Session Events designed to allow the Gateway to track and interact with the Session at critical moments. Specifically, they are scripts that run in the Gateway when a Session starts up, shuts down, or runs a Perspective App action. There are nine configurable Session events in Perspective: - Startup - Shutdown - Page Startup (new in 8.1.0) - Authentication Challenge Completed (new in 8.1.16) - Message - Keystroke - Barcode - Bluetooth - Accelerometer - NFC :::note Although they are designed to handle Session Events, the scripts that you write will be run in a Gateway scope, not a Session scope ::: ## Configuring Session Events To start working on a Session event script: 1. In the Project Browser, double-click on the **Session Events** section: ![](perspective-session-event-scripts/1-2019-04-05_10-18-14.png) 2. The **Session Events** dialog will appear: ![](perspective-session-event-scripts/2-image-2023-11-9_7-20-56.png) 3. Configure a script by selecting one of the events on the left-hand side. ## Startup and Shutdown Event Scripts **Startup** and **Shutdown** events run, naturally, whenever a Session starts or ends. In each case, the Gateway will have access to the **session** object associated with the section, complete with all Session properties. When designing a startup or shutdown event script, custom Session properties can be used to pass any additional information to the Gateway, or, in the case of a startup script, to pass information to the newly opening Session. You can configure custom Session properties from the Page Configuration dialog, by clicking on the **Settings** - ![]() icon in the Designer. A shutdown event script will run specifically when a Session is ending. This happens specifically when any of the following events occur: - The Session closes due to a timeout. Session timeout is configurable in the **Perspective** > **General** section of [Project Properties](ignition-modules\perspective\perspective-project-properties.md) in the Designer - The user is no longer authorized to run the Session. - The redundancy system determines that the Gateway is inactive. - The licensing system no longer permits the user to run the Session. - The project is no longer runnable. - The project is deleted. :::note Closing the browser tab with the Session will not immediately close the Session; the Session must first time out. ::: ### Startup and Shutdown Example This example will record the Session start and end time to the database. 1. For this example, we need to set up a few queries that we can use to write our data to the database. 2. Make a new named query called **Startup Query**. 1. Set the Query Type to **Update Query**. 2. Set up a single Value type parameter with a name of **SessionID** and a datatype of string. 3. Add the query: ```sql INSERT INTO sessions (session_id, start_time) VALUES (:SessionID, CURRENT_TIMESTAMP) ``` 3. Make a second new named query called **Shutdown Query**. 1. Set the Query Type to **Update Query**. 2. Set up a single Value type parameter with a name of **SessionID** and a datatype of string. 3. Add the query: ```sql UPDATE sessions SET end_time = CURRENT_TIMESTAMP WHERE session_id = :SessionID ``` 4. Next, we need to add Session Events so that Perspective knows to run those queries on startup and shutdown. 5. Under the **Project** tab, select **Session Events**. ![](perspective-session-event-scripts/4-2019-04-05_10-18-14.png) 6. On the **Session Events** screen, click the **Startup** ![](perspective-session-event-scripts/5-2019-06-03_15-29-27.png) icon. 7. Add the following script to the page: ```python # This script will record the time when the Session is opened. # Create the parameters queryParams = {'sessionID':session.props.id} # Run the query system.db.runNamedQuery('My Project', 'Startup Query', queryParams) ``` ![](perspective-session-event-scripts/6-image-2023-11-9_7-22-55.png) 8. Click **Apply** and then click the **Shutdown** ![](perspective-session-event-scripts/7-2019-06-03_15-28-54.png) icon. ![](perspective-session-event-scripts/8-image-2023-11-9_7-23-32.png) 9. Add the following script to the page: ```python # This script will record the time when the Session times out. Note that after the Session is closed, # the Session won't time out until the time out period is reached. # Create the parameters. queryParams = {'sessionID':session.props.id} # Run the query. system.db.runNamedQuery('My Project', 'Shutdown Query', queryParams) ``` 10. Click **OK**. 11. Save your project. ### Test the Example To test the example, open the Perspective App on your mobile device and load the project. 1. You should see a new entry in the database table with the time the time the Session was started as well as the session ID. 2. After the Session times out (such as after it is closed) you should see the original entry get updated to include the new shutdown time. ## Page Startup This script runs in the Gateway when a Perspective page starts in a new tab or window. :::note Navigating to a page configuration in a tab that's already opened (such as using [system.perspective.navigate](appendix\scripting-functions\system-perspective\system-perspective-navigate.md)) will not trigger this event. ::: ![](perspective-session-event-scripts/9-image-2023-11-9_7-23-59.png) ### Parameters #### `page` A reference to the newly created page. Note that other page props will not return a valid value on page startup. Accessing properties under this argument requires that you include `.props.` along the path. Demonstrations are included below: ### Props Demonstrations | Property | Description | Example | | -------- | --------------------------------------------------------------- | ------------------------------------------------------------- | | pageId | Identifier associated with the target page. |
# Provides the page id.pageId = page.props.pageId
| | path | Represents the Page URL of the page, for example: / or /myPage. |
# Provides a path to the page.pagePath = page.props.path
| In addition to the arguments above, the Session is available from this event: ```python # For example, we can access the session id with the following: sessionId = page.session.props.id ``` ## Authentication Challenge This event is fired when an authentication challenge is completed by the user. ![](perspective-session-event-scripts/10-image-2023-11-9_7-24-23.png) ### Authentication Challenge Parameters #### `session` An object that references the Project Session that triggered the authentication challenge. Use this to identify the specific Session that triggered the authentication challenge. #### `payload` The opaque payload provided by the initial Authentication Challenge Action or Scripting function invocation. #### `result` A [Result object](#result-objects) that can be parsed by the result functions below. #### Result Functions | Function | Description | | -------------- | ----------------------- | | isSuccess() | Returns true if the authentication challenge was a success. If true, optionally call **getAsSuccess()** to get the result as a **Result.Success** object for further parsing. If false, optionally call **getAsError()** to get the result as a **Result.Error** object for specific details pertaining to the error. | | getAsSuccess() | Returns the result as a **Result.Success** object if the result is successful, otherwise throws an **UnsupportedOperationException** if the result is an error. Check **isSuccess()** or **isError()** before calling this function to ensure you get the correct result type.**Note**: It is not necessary to call **getAsSuccess()**. If **isSuccess()** returns true, the result type is **Result.Success**, so all of the properties and functions of a **Result.Success** object are available on the original result reference. | | isError() | Returns true if the authentication challenge resulted in an error. If true, optionally call **getAsError()** to get the result as a **Result.Error** object for specific details pertaining to the error. | | getAsError() | Returns the result as a **Result.Error** object if the result is an error, otherwise throws an **UnsupportedOperationException** if the result is successful. Check **isSuccess()** or **isError()** before calling this function to ensure you get the correct result type.**Note**: It is not necessary to call **getAsError()**. If **isError()** returns true, the result type is **Result.Error**, so all of the properties and functions of a **Result.Error** object are available on the original result reference.| #### Result Objects This object contains different properties depending on whether the authentication challenge result is a success or an error. ##### Result.Success An object that represents a successful authentication challenge result. Call getContext() to return a WebAuthUserContext object with the following properties: | Property | Description | | --- | --- | | idp | The name of the IdP which challenged the user. | | securityZones | A string array containing the names of the security zones associated with the challenged user. | | user | A **WebAuthUser** object that contains the properties in the User Properties table below. | | securityLevels | An array of **SecurityLevelConfig** objects representing all of the security levels associated with the challenged user. | ###### User Properties | Property | Description | | --------- | --------------------------------------------------------------------------------- | | id | The unique identifier associated with the challenged user | | userName | The challenged user’s username. | | firstName | The challenged user’s first name, or null / None if not defined for this user. | | lastName | The challenged user’s last name, or null / None if not defined for this user. | | email | The challenged user’s email address, or null / None if not defined for this user. | | roles | The challenged user’s roles as a string array. | ##### Result.Error An object that represents an error authentication result. It can be parsed by the following functions: | Function | Description | | ---------------- | ----------------- | | isGeneric() | Returns true if the error is not related to a timeout or user cancellation. Optionally call **getAsGeneric()** to get the **Result.Error** as a **Result.Error.Generic** object for specific details pertaining to the generic error. | | getAsGeneric() | Returns the result as a **Result.Error.Generic** object if the error is generic, otherwise throws an **UnsupportedOperationException**. Check isGeneric() before calling this function to ensure you get the correct result type.**Note**: It is not necessary to call **getAsGeneric()**. If **isGeneric()** returns true, the result type is **Result.Error.Generic**, so all of the properties and functions of a **Result.Error.Generic** object are available on the original result reference. | | isTimeout() | Returns true if the error is due to a timeout. Optionally call **getAsTimeout()** to get the **Result.Error** as a **Result.Error.Timeout** object for specific details pertaining to the timeout error. | | getAsTimeout() | Returns the result as a **Result.Error.Timeout** object if the error is due to a timeout, otherwise throws an **UnsupportedOperationException**. Check **isTimeout()** before calling this function to ensure you get the correct result type.**Note**: It is not necessary to call **getAsTimeout()**. If **isTimeout()** returns true, the result type is **Result.Error.Timeout**, so all of the properties and functions of a **Result.Error.Timeout** object are available on the original result reference. | | isCancelled() | Returns true if the error is due to user cancellation. Optionally call **getAsCancelled()** to get the **Result.Error** as a **Result.Error.Cancelled** object for specific details pertaining to the cancellation error. | | getAsCancelled() | Returns the result as a **Result.Error.Cancelled** object if the error is due to user cancellation, otherwise throws an **UnsupportedOperationException**. Check **isCancelled()** before calling this function to ensure you get the correct result type.**Note**: It is not necessary to call **getAsCancelled()**. If **isCancelled()** returns true, the result type is **Result.Error.Cancelled**, so all of the properties and functions of a **Result.Error.Cancelled** object are available on the original result reference. | ###### Result.Error Objects This object contains different properties depending on the cause of the authentication error: | Object | Description | | ---------------------- | --------------- | | Result.Error.Generic | An object representing a generic error authentication result. Call **getMessage()** to return a diagnostic message pertaining to the error, or null if such a message does not exist. | | Result.Error.Timeout | An object representing a timeout error authentication result. Call **getTimeout()** to return the integer timeout value (in minutes) that that was used to configure the timeout. | | Result.Error.Cancelled | An object representing an error result due to user cancellation. This object has no functions or properties. | ### Authentication Challenge Example This example script will determine whether to proceed with a specified action after a completed [Authentication Challenge Action](../working-with-perspective-components/component-events-and-actions.md#authentication-challenge-action). In this case, the action is permitted only if the second user's roles include 'supervisor', If the action is not permitted, or the authentication challenge result is an error, a message box will pop up with relevant context. ```python if result.isSuccess(): # Parse information about the successful result success = True context = result.getAsSuccess().getContext() user = context.user roles = user.roles # Determine if the e-signature is valid: if 'supervisor' in roles: # If the user is a supervisor, proceed with the specified action: proceedWithSomeAction() else: # If the user is not a supervisor, write to a logger: logger = system.util.getLogger("Authentication Challenge") logger.info("%s is not authorized"% user.userName) # If the result is an error, write to a logger: else: success = False error = result.getAsError() # Change the content of the logger message based on the type of error: if error.isGeneric(): message = error.getAsGeneric().getMessage() logger = system.util.getLogger("Authentication Challenge") logger.info(message) elif error.isTimeout(): timeout = error.getAsTimeout().getTimeout() logger = system.util.getLogger("Authentication Challenge") logger.info("Authentication challenge timed out after %d minutes."% timeout) elif error.isCancelled(): logger = system.util.getLogger("Authentication Challenge") logger.info("Authentication challenge cancelled.") else: logger = system.util.getLogger("Authentication Challenge") logger.info("Unknown error occurred.") ``` ## Message The Message Handler scripts will run whenever the Session receives a message from [system.util.sendMessage](appendix\scripting-functions\system-util\system-util-sendMessage.md) or [system.util.sendRequest](appendix\scripting-functions\system-util\system-util-sendRequest.md). :::note These types of message handlers are different than [component-based message handlers](component-message-handlers.md), which are accessed with [system.perspective.sendMessage](appendix\scripting-functions\system-perspective\system-perspective-sendMessage.md). Session Message Handlers can not be called by system.perspective.sendMessage. ::: ![](perspective-session-event-scripts/31-image-2023-11-9_8-4-6.png) :::tip An efficient way to use this message handler in cases with user driven operations is by incorporating [system.perspective.getSessionInfo](../../../appendix/scripting-functions/system-perspective/system-perspective-getSessionInfo.md) to lookup all sessions and then filter the sessions to target specific users. ::: ### Message Parameters #### `session` The Perspective Session that is handling this message. #### `payload` Retrieve them with a subscript, e.g., `myObject = payload['argumentName']` ### Message Example This example shows how to set up a message handler script to send a simple log message to the Gateway. We will use a button component to run the [system.util.sendMessage](appendix\scripting-functions\system-util\system-util-sendMessage.md) command. 1. Under the Project tab, select **Session Events**. 2. On the Session Events screen, click the **Message** ![](perspective-session-event-scripts/32-image-2023-2-15_8-29-54.png) icon. 3. Click the **Add** ![]() icon. 4. Enter **myMessage** in the Message Handler Settings Name field. 5. Click **OK**.![](perspective-session-event-scripts/33-image-2023-11-9_8-5-25.png) 6. We will first define the define the message and assign the sessionId to our current Perspective session. Then, we will use Logger functions to return a logger object to log message with level info. Add the following script to the page to complete these functions: ```python def handleMessage(session, payload): message = payload['message'] sessionId = session.props.id logger = system.util.getLogger("myLogger") logger.info("Your session "+str(sessionId)+" received the message: "+str(message)) ``` ![](perspective-session-event-scripts/34-image-2023-11-9_8-7-56.png) 7. Click **OK**. 8. Add a Button component onto a view. 9. Right-click on the Button component and choose **Configure Events**. 10. On the Event Configuration screen, select **Component Events** > **onActionPerformed**. 11. Click the **Add** ![]() icon and select **Script** action. 12. For this example, we will use system.util.sendMessage, which means we need to add our project name, the message handler we created, the payload message we want to send, and limit the scope to Session. Add the following script to the page: ```python def runAction(self, event): system.util.sendMessage("samplequickstart", "myMessage", {"message":"Hello World"}, "S") ``` ![](perspective-session-event-scripts/35-image-2023-2-24_6-44-47.png) 13. Click **OK**. 14. Save your project. ### Test the Example To test the example, launch your Perspective Session and click the button component we created. 1. After clicking the button, the script will send the "Hello World!" message to your session id. 2. Access your Gateway Status > Diagnostics > Logs page to confirm the message was received.![](perspective-session-event-scripts/36-image-2023-2-15_8-7-25.png) ## Keystroke Keystroke scripts will run when the session detects a KeyboardEvent matching either a single key or a regex pattern. A single key match can be made on either a key press (keyDown) or on a key release (keyUp). A regex match is always made on a key release. Key Event scripts can be triggered by keyboards and any other device that is capable of generating a KeyboardEvent, such as an HID barcode scanner. Keystroke detection is only active inside of a Perspective session and is not active inside of the Designer. :::note Note: The device being used to trigger key event scripts must be able to generate a KeyboardEvent. HID barcode scanners will generate KeyboardEvents because they mimic a user typing keys on a physical keyboard. Scanners and other input devices that do not create KeyboardEvents will not trigger this logic. ::: ### Keystroke Parameters #### `page` An object that contains information about the current page. | Argument | Description | | -------- | -------------------------------------------------------------- | | props | Properties of the "page" object. | | session | An object that contains information about the current session. | #### `event` An object that contains information from the Key Event. | Argument | Description | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | altKey | Returns a boolean that is true if the Alt (Option or ? on OS X) key was active when the key event was generated. | | code | Returns a string with the code value of the physical key represented by the event. | | ctrlKey | Returns a boolean that is true if the Ctrl key was active when the key event was generated. | | isComposing | Returns a boolean that is true if the event is fired after "[compositionstart](https://developer.mozilla.org/en-US/docs/Web/API/Element/compositionstart_event)" and before "[compositionend](https://developer.mozilla.org/en-US/docs/Web/API/Element/compositionend_event)". | | key | Returns a string representing the key value of the key represented by the event. | | location | Returns a number representing the location of the key on the keyboard or other input device. | | metaKey | Returns a boolean that is true if the Meta key (on Mac keyboards, the ? Command key; on Windows keyboards, the Windows key) was active when the key event was generated. | | repeat | Returns a boolean that is true if the key is being held down such that it is automatically repeating. | | shiftKey | Returns a boolean that is true if the Shift key was active when the key event was generated. | | matches | Returns a list where the first entry of the list is the exact text which registered as a match for the regex, and all subsequent entries in the list are the content which fell into capture groups. | ### Single Key For single key matches, the match can be a physical key typed or the code generated by the key. **Modifiers** are additional keys that can be held down during a KeyboardEvent and are detectable in the event data. These include Alt, Control, Shift, and Command/Meta. ![]() In addition, the resulting Key Event that is used for match detection has the following advanced features: - **Capture Phase** - Allows execution during event capturing, which will let the resulting script execute **before** other interface events that may be in place. By default, events execute during an event bubbling phase which is dictated by the position of the event binding in the Document Object Model (DOM). In the case of Key Events, these are bound to the `document` layer of the DOM and will execute **after** other interface events if this option is unchecked. - **Prevent Default** - Prevents any default browser functionality that would be associated with the event binding. This can be toggled on if there is any functionality that **should not** be run when a `keyDown/keyUp` event has been fired at the `document` level when a key match is made. - **Stop Propagation** - Prevents the event from propagating beyond the point in the DOM where it is bound (the `document` level). This can be useful if combined with the **Capture Phase** option as it will prevent any interface `keyDown/keyUp` events from running that are bound deeper in the DOM than the `document` level. ### Regex Match For a regular expression (regex) pattern match, a match will be based on a supplied regex pattern and a series of keys stored in a match buffer. This buffer will always be the most recently typed characters and should be the length of a "correct match" to the supplied regex pattern. #### Regex Example This example will update a custom Session property when a regex pattern match is found. 1. For this example, place a Label component onto a view. 2. Add a custom Session property called scannerInput. 3. Bind the text value of the Label to the custom Session property. 4. Under the **Project** tab, select **Session Events**. 5. On the **Session Events** screen, select **Key Events**.![](perspective-session-event-scripts/38-image-2023-11-9_8-9-54.png) 6. Click on the **Add** ![]() icon and select **regex match**.![]() 7. Enter the regex pattern you want the Session to watch for. In the above example, a match occurs for any sequence of 12 numeric characters followed by an "@" 8. Enter the length of the match buffer. The match buffer should equal the minimum number of characters required for a pattern match. 9. Add the following script: ```python page.session.custom.scannerInput = "Match found" ``` 10. Click **OK**. 11. Save your project. #### Test the Example To test the example, launch a Perspective session and open the view containing your Label. Type a string of characters matching the regex pattern you configured above. You should see the Label's text change: ![](perspective-session-event-scripts/40-9rnUTCPfp4.gif) ## Perspective App Event Scripts When the Perspective App is running on a mobile device, it enables users to use tools available on the device, such as GPS location data, the camera, or the accelerometer. The remaining Session events are designed specifically to handle the Perspective App Actions.. ### Barcode The scanned barcode action can make use of a mobile device's built in camera. #### Barcode Parameters `session` An object that references the project Session that called the Barcode Scanned event. Use this to identify the specific Session that scanned the barcode. `data` The data returned from the barcode scan. Access the underlying barcode data using: ```python # The value that was scanned data.text # An integer representing a unix timestamp of when the barcode was scanned data.timestamp ``` Version 0.98 of the Perspective Mobile App added the following property: ```python # The type of barcode that was scanned. data.barcodeType ``` `context` The user defined context object that can be defined on the action. #### Barcode Example This example will scan a barcode, and write its value to a tag. 1. For this example, drag a Button component and a Label component onto a view. 2. Create a new Memory tag with a data type of String. Set the value to **Please scan a barcode**. ![]() 3. Bind the text of the Label to the new tag. ![](perspective-session-event-scripts/12-2019-04-04_16-57-50-a.png) 4. Right-click on the Button component and choose **Configure Events**. 5. On the Event Configuration screen, select **Mouse Events** > **onClick**. 6. Click the **Add** ![]() icon and select **Scan Barcode** action. ![](perspective-session-event-scripts/14-2021-02-16_15-47-25.png) 7. Click **OK**. Next we need to set up a session event so that Perspective knows how to interpret the scanned barcode data. 8. Under the **Project** tab, select **Session Events**. ![](perspective-session-event-scripts/15-2019-04-05_10-18-14.png) 9. On the Session Events screen, select the **Barcode** ![](perspective-session-event-scripts/16-2019-06-03_15-26-45.png) icon. 10. Add the following script to the page: ```python system.tag.writeAsync(['[default]New Tag 5'], [data.text]) ``` :::note We used the tag created for this example, New Tag 5. You can enter your own tag name if different. ::: ![](perspective-session-event-scripts/17-image-2023-11-9_7-27-6.png) 11. Click **OK** and save your project. #### Test the Example To test the example, open the Perspective App on your mobile device and load the project. 1. Click **Scan Barcode**.![](perspective-session-event-scripts/18-2019-04-05_14-54-03.png) 2. If this is the first time scanning a barcode, you'll get a message requesting permission for Perspective to take pictures and record.![](perspective-session-event-scripts/19-2019-04-04_13-01-44.png) 3. Click **Allow**. 4. You can now use the camera on the mobile device to scan the barcode.![](perspective-session-event-scripts/20-2019-04-04_13-02-15.png) 5. Ignition scans the barcode. Once it recognizes the barcode, the script will run and the text is written to the tag. The Label then shows the new tag value.![](perspective-session-event-scripts/21-2019-04-04_13-02-42.png) ### Bluetooth This Session event script sends received Bluetooth advertising data to Perspective. It supports iBeacon and Eddystone formats. - Eddystone will work on iOS and Android - iBeacon on iOS requires user to specify the specific region (iBeacon UUID) located on Session props bluetooth.config.iBeaconRegion. :::note Bluetooth "advertising data" is the name of the communication data according to the Bluetooth spec. There is no connection to advertising as an industry. ::: ![](perspective-session-event-scripts/22-image-2023-11-9_7-27-38.png) #### Bluetooth Parameters `session` An object that references the Project Session. `data` List of buffered advertising data. The data comes in as a data object, which has various parts. The following is example output. ```json { "values": [ { "rssi":-48, "timestamp":1570147485167, "manufacturerData":{ "companyId":6, "dataBase64Encoded":"AQkgAl_edccdnHClMvecMCiM--aAkLHAPibd" } }, { "rssi":-48, "timestamp":1570147486012, "serviceUUIDs":[ "FEAA" ], "serviceData":{ "uuid":"FEAA", "dataBase64Encoded":"AOyqqqqqqqqqqqqqAAAAAAAA" }, "eddystoneUID":{ "txPower":-20, "namespaceID":"AAAAAAAAAAAAAAAAAAAA", "instanceID":"000000000000" } }, { "rssi":-54, "timestamp":1570147485919, "manufacturerData":{ "companyId":76, "dataBase64Encoded":"AhV88isfQjVLY4VnXXfYqpTyAAAAAL8=" }, "iBeacon":{ "uuid":"7CF22B1F-4235-4B63-8567-5D77D8AA94F2", "major":0, "minor":0, "txPower":-65 } }, { "rssi":-54, "timestamp":1570147485987, "manufacturerData":{ "companyId":65535, "dataBase64Encoded":"vqwSNFZ4EjQSNBI0EjRWeJASAAAAAOwA" }, "AltBeacon":{ "manufacturerId":65535, "uuid":"12345678-1234-1234-1234-123456789012", "instance":"00000000", "txPower":-20, "manufacturerReserved":"00" } } ] } ``` ### Accelerometer The Accelerometer event is only used when data is coming in from a batched [Accelerometer Action](ignition-modules\perspective\working-with-perspective-components\component-events-and-actions.md#accelerometer-action). #### Accelerometer Properties `session` An object that references the Project Session that called the Accelerometer Data Received event. Use this to identify the specific Session that triggered the batching of accelerometer data. `data` The data returned from the batched accelerometer. The data comes in as a data object, which has various parts. Access the various parts like: ```python logger = system.util.logger('accelerometer') for row in data.values.data: logger.info('X:' + str(row['x'])) logger.info('Y:' + str(row['y'])) logger.info('Z:' + str(row['z'])) ``` `context` The user defined context object that can be defined on the action. #### Accelerometer Example This example will write accelerometer data to the Gateway logs. 1. For this example, put a Button component onto a view. 2. Next right-click on the Button component and choose **Configure Events**. 3. On the Event Configuration screen, select **Mouse Events** > **onClick**. 4. Click the **Add** ![]() icon and select **Accelerometer** action. 1. Select **Batch** mode. 2. Set a **Sample Rate** of 400. 3. Set a **Duration** of 2000.![](perspective-session-event-scripts/23-2020-05-08_14-49-02.png) 5. Click **OK**. Next we need to set up a Session Event so that Perspective knows how to interpret the accelerometer data. 6. Under the **Project** tab, select **Session Events**.![](perspective-session-event-scripts/24-2019-04-05_10-18-14.jpg) 7. On the **Session Events** screen, click the **Accelerometer** ![](perspective-session-event-scripts/25-2019-06-03_15-25-19.png) icon.![](perspective-session-event-scripts/26-image-2023-11-9_7-32-3.png) 8. Add the following script to the page: ```python # This script will take the accelerometer data and print it to the Gateway logs. # Create the logger. logger = system.util.logger('accelerometer') # Loop through the list of batched events and pull out the x, y, and z values to print to the Gateway logs. for row in data.values.data: logger.info('X:' + str(row['x']) + ', Y:' + str(row['y']) + ', Z:' + str(row['z'])) ``` 9. Click **OK**. 10. Save your project. #### Test the Example To test the example, open the Perspective App on your mobile device and load the project. 1. Click the **Accelerometer** button. 2. The script will record accelerometer data for the next two seconds, so move the phone around. 3. After the two seconds, you should see the logged information appear in the Gateway logs. ### NFC The NFC event is used when the [NFC Action](../working-with-perspective-components/component-events-and-actions.md#scan-ndef-nfc-action) is used and the mobile device scans an NFC tag. #### NFC Properties `session` An object that references the Project Session that called the NFC Ndef Scanned event. Use this to identify the specific Session that scanned the NFC tag. `data` The data returned from the NFC tag scan. The data object is a list which can contain multiple records from a single NFC tag. Access the underlying NFC data using: ```python logger = system.util.logger('NFC') for row in data: logger.info('Type:' + str(row['type'])) logger.info('Type Name Format:' + str(row['typeNameFormat'])) logger.info('Payload:' + str(row['payload'])) logger.info('String:' + str(row['string'])) logger.info('Bytes:' + str(row['bytes'])) ``` `context` The user defined context object associated with the NFC scan event. #### NFC Compatibility NFC tag types must be NDEF-formatted as one of the following types: * NFC_FORUM_TYPE_1 based on ISO14443A * NFC_FORUM_TYPE_2 based on ISO14443A * NFC_FORUM_TYPE_3 based on JIS X 6319-4 * NFC_FORUM_TYPE_4 based on ISO14443A/B #### NFC Example This example will write the NFC tag data to the Gateway logs. 1. For this example, place a Button component onto a view. 2. Right-click on the Button component and choose **Configure Events**. 3. On the Event Configuration screen, select **Mouse Events** > **onClick**. 4. Click the **Add** ![]() icon and select **Scan Ndef NFC** action. 5. Select **Single** mode, then click **OK**.![](perspective-session-event-scripts/27-2020-05-08_15-00-28.png) 6. Next we need to set up a Session Event so that Perspective knows how to interpret the NFC data. Under the Project tab, select **Session Events**.![](perspective-session-event-scripts/28-2019-04-05_10-18-14.png) 7. On the Session Events screen, click the **NFC** ![](perspective-session-event-scripts/29-2019-06-03_15-26-04.png) icon.![](perspective-session-event-scripts/30-image-2023-11-9_8-3-27.png) 8. Add the following script to the page: ```python # This script will take the NFC data and print it to the Gateway logs. # Create the logger. logger = system.util.logger('NFC') # Loop through the list of records stored in the NFC tag and pull out the type, type name format, payload, string data, and raw byte data from each record and print it to the Gateway logs. for row in data: logger.info('Type:' + str(row['type']) + ', Type Name Format:' + str(row['typeNameFormat']) + ', Payload:' + str(row['payload']) + ', String:' + str(row['string']) + ', Bytes:' + str(row['bytes'])) ``` 9. Click **OK**. 10. Save your project. #### Test the Example To test the example, open the Perspective App on your mobile device and load the project. 1. Click the **NFC button**. * After clicking the button, the script will pass the next NFC tag scanned to the script to be handled. 3. After scanning an NFC tag, you should see the logged information appear in the Gateway logs.