Skip to main content
Share:
Link is copied

Examples and Use Cases for Pebble Language in evalink talos

The topics below list several common use cases for the use of Pebble in evalink talos.

Inspecting Available Data in a Workflow Step​

When you use Pebble in any context in evalink talos, it is important to know what data is available inside each context, for example, in a workflow step. Pebble templates can only reference variable that are available in each particular working scenario.

There are several ways to find which Pebble entities are available to use:

  1. Navigate to Three-dot-menu > Advanced Settings

    This makes Step Reference panel of the workflow step available.

This panel shows:

  • All variables available to the step

  • Device and alarm fields

  • Step-specific inputs and previous outputs

  • Data structures with nested properties (e.g., callList, schedule, form, etc.)

  1. Execute a workflow, open its Event Log and select the workflow step you want to inspect and then click info More Details

This opens a JSON dialog window with the step result. For example:

"result": {
"responder": {
"name": "John Snow",
"phone": "+41123456789",
"outcome": "VERIFIED"
}
}

Both of these methods show you which entities can be accessed in this workflow step through the use of Pebble.

In this particular case it can be:

{{ callList.responder.name }}
{{ callList.responder.phone }}
{{ callList.responder.outcome }}
info

In this case, callList is the name of the step in a workflow. You can substitute it with your own workflow step name.

Using dump() to Return Entire Object Data​

Using Pebble, you can reference available object data directly and, for example, send it in an email, Slack message or a Twilio SMS text.

{{ dump(device) }}
{{ dump(alarm) }}
{{ dump(callList) }}

This prints full JSON representation of the objects.

Conditional Logic for Alarm Handling​

Pebble templates in evalink talos support conditional logic, allowing workflow authors to create dynamic call descriptions, SMS messages, email notifications, and webhook payloads based on the properties of the alarm, device, or workflow state.

This enables workflows to adapt their behavior based on:

  • alarm code, type or definition

  • user actions

  • zone and / or partition

  • action repetition count

  • schedule

  • presence or absence of fields

  • tags, attributes, or metadata

Below are real examples taken from active evalink talos workflows.

Conditional text based on alarm code

You can use this example if you need to:

  • Provide different operator instructions depending on the event type

  • Change SMS or other message content based on alarm category

  • Generate legally required descriptions for intrusion vs. fire events

{% if alarm.alarmCode == 'E205' %}
Unauthorized disarming or partition '{{ alarmPartition }}' by user '{{ alarm.user }}'.
{% elseif alarm.alarmCode == 'E220' %}
Partition '{{ alarmPartition }}' was not armed within the allowed limit by the user '{{ alarm.user }}'.
{% endif %}
Send the surveillance! Inform the guards about the situation.

Conditional logic based on call attempts (repetition)

You can use this example for escalation policies, automated fallback logic or handling unreachable contacts.

{% if call.repetition >= '3' %}
Call the police!
{% elseif call.repetition == '2' %}
Last attempt before calling the police...
{% elseif call.repetition == '1' %}
Try calling twice; Call the police in the 3rd attempt
{% endif %}

Conditionals combined with workflow objects

You can reference nested fields such as:

callList.responder...

dispatchCall.success...

twilioCall.acknowledged...

info

Only include responder info if the call was acknowledged

{% if callList.responder is not empty %}
Responder: {{ callList.responder.name }} ({{ callList.responder.phone }})
{% endif %}

Only if there was responder in the call, then we will see the following text as example:

Responder: John Smith (+41779988555)

Checking if a field is empty

You can use is empty operator when you need to display fallback values, handle missing metadata or make sure that templates don't show blank fields.

For example, the Pebble code below calls onto the device.customerCompany value and if it's not specified, returns evalinkDeviceId instead.

{% if device.customerCompany is empty %}
{{ device.evalinkDeviceId }}
{% else %}
{{ device.customerCompany }}
{% endif %}

Conditional routing and dynamic values

These conditions can also be used in Form steps, Twilio messages, Emails, SMS etc.

Examples:

{% if alarm.alarmType == 'FIRE' %}
πŸ”₯ Fire alarm at {{ device.customerCompany }}
{% elseif alarm.alarmType == 'BURGLARY' %}
🚨 Intrusion detected at {{ device.customerCompany }}
{% endif %}

Referencing Alarm Headers​

Alarm headers in evalink talos allow panels, integrations, receivers, or upstream systems to attach additional metadata to incoming alarms. evalink talos lists available headers in Alarm Details and when processing alarms in workflows you can reference these headers in Pebble templates.

Headers are commonly used for:

  • routing alarms in the Dispatcher

  • selecting dynamic account numbers

  • extracting virtual receiver information (e.g., Surgard, FlexC, Generic Receiver)

  • attaching file URLs or payloads

  • passing integration-specific data

Pebble exposes alarm headers through the alarm.headers object.

To read a header, use:

{{ alarm.headers['header-name'] }}

Examples:

{{ alarm.headers['x-receiver'] }}
{{ alarm.headers['attachment.url'] }}
info

If the header exists, Pebble outputs its value. If not, Pebble returns an empty string.

Alarm Supervision Rules​

Supervision rules frequently use header values to identify receivers or channels.

Expected Alarm: 602 { headers.x-receiver = generic-surgard:1001 }
Restore Alarm: E709 { headers.x-receiver = generic-surgard:1001 }

This instructs evalink talos to apply the rule only when the alarm header matches a specific receiver.

Use this if you need to:

  • differentiate multiple receivers under the same panel

  • route events from different IP paths

  • treat supervision signals differently depending on source

Extracting URLs from header values​

Some alarm systems embed file URLs inside headers (such as attachments from panels or integrations). This is often used in SMS, email, or webhook templates.

Example:

{{ alarm.headers['attachment.url'] }}

Combined with filters:

{{ alarm.headers['attachment.url'] | urlEncode }}

For Twilio SMS:

Alarm {{ alarm.alarmCode }} β€” File: {{ alarm.headers['attachment.url'] }}

Combining header values with other Pebble features​

You can use Pebble to decode, parse or split headers into more readable formats.

The example below allows you to decode a Base64 prefix, append a deviceID and URL-encode spaces. You can use this for Twilio, webhooks, etc.

{{ alarm.alarmCode }} { headers.attachment.url = {{ 
'aHAgAljaAHJJHglkjlkjAhjHgpeeroHGKSJD8786dm8vc3RyZWFtaW5nL3NpdGUv'
| decodeBase64 | toString }}{{ device.evalinkDeviceId | replace({' ': '%20'}) }} }

Loops: Listing Responders or Acknowledgements​

Pebble supports looping through arrays and lists, which is useful in evalink talos because many workflow steps return collections inside their result object.

For example:

  • lists of people who need to be called

  • lists of responders who can acknowledge an action

  • lists of successful notifications

  • arrays of form fields

  • arrays inside JSON payloads

Loops let you dynamically create call descriptions, emails, Slack messages, or webhook payloads based on the number of people involved.

Looping over acknowledged responders (Twilio Call example)

{% for person in Twilio_Call_Step.acknowledged %}
{{ person.name }},
{% endfor %}

An output for this can be a string of names taken from the contacts that need to acknowledge a step result.

You can use this inside Pebble templates for email notifications, slack messages, operator call descriptions, etc.

Listing acknowledged people and total count

Pebble allows combining loops with filters and inline values:

{{ Twilio_Call_Step.acknowledged | length }} people acknowledged.

They are:
{% for person in Twilio_Call_Step.acknowledged %}
- {{ person.name }} ({{ person.phone }})
{% endfor %}

Example output:

2 people acknowledged.

They are:
- Anonymous (+4179 111 22 44)
- Anonymous (+4179 444 22 33)

Looping through β€œcalled”, β€œsuccess”, and other arrays

A Twilio step result (visible in Event Logs β†’ step β†’ info (i)) typically contains:

{
"called": [
{ "name": "A", "phone": "+41..." }
],
"acknowledged": [
{ "name": "A", "phone": "+41..." }
],
"success": [
{ "name": "A", "phone": "+41..." }
]
}

Any of these can be looped:

{% for person in callList.called %}
Called: {{ person.name }} ({{ person.phone }})
{% endfor %}

or:

{% for person in callList.success %}
Successfully notified: {{ person.name }}
{% endfor %}

This allows you to automatically generate accurate audit messages without hardcoding anything.

Looping over form fields (Form Step)

Form Steps return an array of fields inside form.fields.

{% for field in fromJson(form.fields) %}
{{ field.label }}: {{ field.value }}
{% endfor %}

Looping in webhook payloads

Pebble loops can be used even inside JSON payloads.

Example:

{
"responders": [
{% for person in callList.acknowledged %}
{ "name": "{{ person.name }}", "phone": "{{ person.phone }}" }{% if not loop.last %},{% endif %}
{% endfor %}
]
}

This produces JSON array without trailing commas.

Extracting Form Data​

When you use a Form Step in a workflow, evalink talos stores all submitted responses inside form.fields as a JSON string.

To work with this data in Pebble templates, you typically need to:

  • Parse the JSON

  • Select a specific field by its label

  • Extract its value

Pebble in evalink talos provides two tools for this:

fromJson() β€” converts the JSON string into a usable object

get() β€” selects values using a JSONPath expression

This allows you to insert form responses into call descriptions, emails, SMS, or webhook payloads.

Below is a basic example:

Every form field is stored with a structure like:

{
"label": "Customer Name",
"value": "John Doe"
}

To extract a specific field:

{{ (fromJson(form.fields) | get('$[?(@.label=="Customer Name")].value'))[0] }}

Explanation:

fromJson(form.fields) β†’ translates an input data array to JSON

get(...) β†’ selects only items whose label matches

[0] β†’ returns the first (and usually only) value

You can find more information no how to use JSONpath here: https://jsonpath.com/.

Example to generate a message for a technician:

𝐍𝐚𝐦𝐞: {{ (fromJson(form.fields) | get('$[?(@.label=="Customer Name")].value'))[0] }}
π“πžπ₯𝐞𝐩𝐑𝐨𝐧𝐞: {{ (fromJson(form.fields) | get('$[?(@.label=="Customer Contact details")].value'))[0] }}
π‚π¨π¦π¦πžπ§π­π¬: {{ (fromJson(form.fields) | get('$[?(@.label=="Comments")].value'))[0] }}

The example output of this:

Name: John Doe  
Telephone: +41790000000
Comments: Please call before arriving

Example for use inside a Twilio Call (phone number field)

{{ (fromJson(form.fields) | get('$[?(@.label=="Customer Contact details")].value'))[0] }}

You can use this in the Twilio Call workflow step to dynamically set the phone number the system should call.

Pebble inside a Twilio Call Step

Extracting all fields dynamically (for reports)

{% for field in fromJson(form.fields) %}
{{ field.label }}: {{ field.value }}
{% endfor %}

This example can generate a complete readable summary for operator handovers, reports, slack notifications, etc.

Example output:

Customer Name: John Doe
Address: Industriestrasse 6
Phone: +4179...
Comments: Please check fire panel

Extracting non-text values (numbers, checkboxes, selects)

Form fields may contain:

  • numbers

  • booleans (true / false)

  • dropdown selections

Example:

{{ (fromJson(form.fields) | get('$[?(@.label=="Temperature")].value'))[0] | toFloat }}

Handling a missing form

If a form field is optional, you can add a fallback.

{% set name = (fromJson(form.fields) | get('$[?(@.label=="Customer Name")].value'))[0] %}
{% if name is empty %}
Name not provided
{% else %}
{{ name }}
{% endif %}

Formatting Dates & Times​

Working with timestamps is one of the most common tasks when building Pebble templates in evalink talos.

Pebble provides several filters and functions that allow you to:

  • format timestamps

  • apply timezones

  • calculate dates in the future or past

  • generate human-readable date strings

  • combine date math with workflow logic

evalink talos extends Pebble with additional helpers such as toTime, numberOfDays, and more.

The most common scenario is converting a Unix timestamp (e.g., alarm.timestamp) into a readable date.

{{ alarm.timestamp | date("dd.MM.yyyy HH:mm:ss") }}

Output:

07.09.2023 13:23:25

Using time zones

By default, evalink talos uses UTC unless a timezone is specified. You can use the following example to set a specific time zone in customer-facing messages, region-specific notifications, etc.

{{ alarm.timestamp | date("dd.MM.yyyy HH:mm:ss", timeZone="Europe/Zurich") }}

Formatting β€œtoday” using now

now produces the current timestamp.

{{ now | date("dd.MM.yyyy") }}

You can use this in messages like report generated on ... or notification sent on...

Generating future times (e.g., +1 day, +2 days)

n evalink talos, date arithmetic and time-of-day selection are handled by the toTime filter. There is no standalone numberOfDays filter.

The toTime filter allows you to:

  • set a specific time of day

  • add a day offset

  • specify a timezone

{{ baseTimestamp | toTime("HH:mm", numberOfDays, "TimeZone") }}

Example: tomorrow at 13:00

{{ now | toTime("13:00", 1, "UTC") }}

You can use this for reminders, escalation deadlines, etc.

Formatting alarm timestamps

Alarm triggered at:
{{ alarm.timestamp | date("dd.MM.yyyy HH:mm:ss", timeZone="Europe/Zurich") }}

When an alarm attribute is missing or empty

Use this code to prevent broken messages when some alarm details are missing or empty.

{% if alarm.alarmZoneName is empty %}
Zone information not available
{% else %}
Zone: {{ alarm.alarmZoneName }}
{% endif %}

Using Pebble to Configure Alarm Dispatcher​

You can user Pebble to configure Monitoring Stations and their Account Templated for Alarm Dispatcher on the company level.

For example:

{{ alarm.headers['dispatch-account'] }}

This routes the alarm to the Alarm Dispatcher account in the alarm header.

ARC-{{ alarm.headers['dispatch-account'] }}

This adds the ARC as a prefix to the previous string.

{% if alarm.headers['dispatch-account'] is not empty %}
{{ alarm.headers['dispatch-account'] }}
{% else %}
9999
{% endif %}

This creates a fallback if the dispatch-account is missing in the alarm headers.

Pebble in Alarm Supervision Logic​

Alarm Supervision in evalink talos allows you to monitor whether a device or panel sends expected signals within a specified interval. You can use Pebble to configure dynamic alarm supervison rules.

Matching Supervision Signals Using Alarm Headers

SurGard Supervision
Expected Alarm: 602 { headers.x-receiver = generic-surgard:1001 }
Expected Interval: Every 5m
Timeout Alarm: E708 { headers.x-receiver = generic-surgard:1001 }
Restore Alarm: E709 { headers.x-receiver = generic-surgard:1001 }

This shows that a supervision rule can:

  • Look for an Expected Alarm code (602)

  • Only consider alarms whose header matches a specific receiver: headers.x-receiver = generic-surgard:1001

  • Trigger a Timeout Alarm (e.g., E708), including the receiver type and account in the headers

  • Trigger a Restore Alarm (e.g., E709), including the receiver type and account in the headers

This demonstrates how alarms originating from multiple receivers can be distinguished by evalink talos.

Sanitizing URL parameters with encodeURL()​

Some workflow steps send webhook requests that include parameters coming from devices, sensors, or zones. If a value contains characters that are not valid in a URL (for example spaces, +, &, etc.), the request may fail.

evalink talos provides the urlEncode filter to safely escape such values.

info

urlEncode is a filter, not a function. It must be used with the pipe (|) syntax.

https://api.example.com/jobs/search?zone={{ step.zone.name | urlEncode }}


If the zone name is: "Entrance + Parking", the URL becomes https://api.example.com/jobs/search?zone=Entrance%20%2B%20Parking

This ensures the webhook executes correctly even when zone names contain special characters.

Was this page helpful?