<!-- Markdown copy of https://freshavlabs.com/docs/qr-jockey/ -->

PLUGIN MANUAL / v1.1.1

# QR Jockey

Q-SYS plugin that makes a UCI a support surface. A scannable trouble-report QR for offline systems, a one-press emailed trouble report for online ones, a component status sweep, and Wi-Fi, UCI link and custom QR codes.

## Introduction

QR Jockey is a Q-SYS plugin that makes a UCI a support surface. For a system with no network, it draws a QR code that opens a pre-filled trouble report on the phone that scans it. For a system with a network, one press of `Send Trouble Report` emails the full report through your SMTP relay. It also draws QR codes for Wi-Fi credentials, a UCI link and your own text.

Trouble Report QR

A scan opens an email to support, pre-filled with the site, design, Core and network details.

Send Trouble Report

One press emails the full report, with component status and an event timeline.

Status Sweep and Input

Reads the status of the design's components and takes one external status from a block or two pins.

QR Utilities

Wi-Fi credentials, a UCI link and up to nine custom QR codes.

## Requirements

| Component                   | Requirement                                                                                                                                                                                                 |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Q-SYS Designer              | Tested with Q-SYS Designer 10.4                                                                                                                                                                             |
| Q-SYS Core                  | Tested on a Core Nano                                                                                                                                                                                       |
| Network, QR codes           | None. The Core draws every QR code itself                                                                                                                                                                   |
| Network, email relay        | SMTP on TCP port 25 from the Core to the relay                                                                                                                                                              |
| Network, reachability check | Outbound HTTPS to `https://qrj.freshavlabs.com/health`. If a firewall refuses it, the check cannot pass and nothing else changes, see [Reachability](https://freshavlabs.com/docs/qr-jockey/#reachability). |
| License                     | One activation code per Core. See [Licensing](https://freshavlabs.com/docs/qr-jockey/#licensing)                                                                                                            |

## Installation

The QR Jockey package contains one plugin file:

| File               | Purpose              | License  |
| ------------------ | -------------------- | -------- |
| `QR_Jockey.qplugx` | The QR Jockey plugin | Licensed |

Step 1. Copy the plugin files

Copy each `.qplugx` file into `Documents\QSC\Q-Sys Designer\Plugins\`. A subfolder works; Designer scans the folder recursively. Double-clicking a file also installs it, into the Plugins folder itself. The plugin appears in Schematic Elements under Plugins, Fresh AV Labs.

Step 2. Add it to the design

Drag the plugin from Schematic Elements into the design.

Updating

Every release uses the same filename. Copy the new file over the old one. When you open the design, Designer offers the newer version, and the plugin's settings survive the update.

## Quick Start

To fill the external-status box, pick a status block or wire the two `StatusIn~` pins, see [Status input](https://freshavlabs.com/docs/qr-jockey/#status-input).

Step 1. Push the design

Push the design to the Core. The LICENSE box counts down, or reads `ACTIVATED`. Without a code the plugin runs a 10-minute demo, see [Licensing](https://freshavlabs.com/docs/qr-jockey/#licensing). The status bar reads `Compromised - SMTP not configured: SMTP Server, SMTP Username, SMTP Password, SMTP From`.

Step 2. Enter the site details

On the Setup page, fill `SITE NAME`, `ROOM NAME` and `SUPPORT EMAIL` in the SITE IDENTITY card. The QR Codes page now shows the trouble report QR in place of `SET SUPPORT EMAIL`.

Step 3. Enter the relay details

In the EMAIL RELAY (SMTP) card, fill `SERVER`, `USERNAME`, `PASSWORD` and `FROM ADDRESS`. The `PASSWORD` field shows `******`. When you fill the last field, the status bar reads `OK`.

Step 4. Send a test email

Press `Send Test Email`. `LAST RESULT` reads `Test handed to relay — check the Support Email inbox to confirm SMTP auth`. A mail titled `[<site> / <room>] QR Jockey test` arrives at the `SUPPORT EMAIL` address.

Step 5. Place the trouble report QR

Drag the trouble report QR from the plugin's QR Codes page onto a UCI page. The UCI shows the QR on a white square.

Step 6. Scan the QR

Scan the QR on the UCI with a phone. The phone opens a new email to `SUPPORT EMAIL`.

Q-SYS cannot report a wrong password, so wait for the test mail before you move on, see [Email relay](https://freshavlabs.com/docs/qr-jockey/#email-relay).

## Plugin Properties

| Property                 | Range / Choices     | Default  | Description                                                                                                                                                                                                                                                                    |
| ------------------------ | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Activation_Code`        | Text                | blank    | The activation code for this Core's Locking ID. Leave blank to run the demo. See [Licensing](https://freshavlabs.com/docs/qr-jockey/#licensing).                                                                                                                               |
| `Activation_Code_Backup` | Text                | blank    | The code for the other Core of a redundant pair. Leave blank on a single Core.                                                                                                                                                                                                 |
| `Show_Locking_ID`        | No / Yes            | No       | When Yes, shows the LOCKING ID box in the header.                                                                                                                                                                                                                              |
| `Custom_QR_Count`        | 1 - 9               | 1        | The number of slots on the Custom QR page, three to a row. See [Custom QR Page](https://freshavlabs.com/docs/qr-jockey/#custom-qr-page).                                                                                                                                       |
| `Status_Sweep`           | Off / 30s / 1m / 5m | 1m       | The time between status sweeps. At Off there is no periodic sweep, no watch for a changed network interface and no uptime reading. `Refresh` still runs a sweep. At Off, the Timeline panel changes yesterday's lines to `MM-DD HH:MM:SS` only at the next event or `Refresh`. |
| `Enable_Email_Relay`     | Yes / No            | Yes      | At No the plugin is a QR-only support surface. See [Email relay](https://freshavlabs.com/docs/qr-jockey/#email-relay).                                                                                                                                                         |
| `Debug_Level`            | Standard / Verbose  | Standard | Verbose adds repeating detail, such as each QR redraw, to the plugin's debug window.                                                                                                                                                                                           |

Properties apply at the next push

Push the design after you change a property. Moving `Custom_QR_Count` to or from 1 renames the custom pins, so wire them after you set the count.

## Configuration

### Email relay

Fill all four fields of the EMAIL RELAY (SMTP) card: `SERVER`, `USERNAME`, `PASSWORD` and `FROM ADDRESS`. Without all four, no send starts. Q-SYS always connects to port 25, so the card has no port field.

After you enter a password, the `PASSWORD` field shows `******`. The plugin keeps the password you entered and logs in with it. To change it, type the new password over the mask. To clear it, clear the field. The mask hides the password on the panel only.

Two settings limit access to the credential this plugin stores:

* In Core Manager, under Access Management, turn on Access Control.
* If no external control system reads or drives this block, set its Script Access to Script.

Press `Send Test Email` to check the setup. A result that starts with `Report handed to relay` or `Test handed to relay` means that the relay accepted the hand-off, and nothing more. Q-SYS reports connection errors to the plugin and no others. A wrong password therefore looks like a right one, and the relay discards the mail. Only a test mail in the inbox proves that the login works.

At `Enable_Email_Relay` No, one card reading `Email relay is off (Enable_Email_Relay = No). Support is by QR only.` replaces the relay and report cards on the Setup page, and the `Connected` LED leaves the header. The status bar never lists missing relay fields. A press of `Send Trouble Report` or `Send Test Email` from a pin is ignored, with a Warning in the debug window. The relay pins stay on the block, so wiring is unchanged.

### Send results

`LAST RESULT` shows the outcome of the last send:

| Last Result                                                                 | Cause                                                                                                                                                | Remedy                                                                                        |
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `Sending...`                                                                | A send is in progress. A relay that connects and then stalls leaves this text in place.                                                              | Wait. If the text stays, check the relay.                                                     |
| `Test handed to relay — check the Support Email inbox to confirm SMTP auth` | The relay accepted the test mail.                                                                                                                    | Confirm that the mail arrived. If it did not, correct `USERNAME` and `PASSWORD`.              |
| `Report handed to relay — scan QR if no reply`                              | The relay accepted the report.                                                                                                                       | If no reply comes, use the QR and run `Send Test Email`.                                      |
| `Send failed: <detail> — scan QR instead`                                   | The send did not reach the relay, for example because the name did not resolve or the connection timed out. `<detail>` is the error text from Q-SYS. | Check `SERVER` and the route from the Core to the relay on port 25.                           |
| `SMTP not configured — scan QR instead`                                     | A send was pressed with a relay field empty.                                                                                                         | Fill the fields that the status bar names.                                                    |
| `Support email invalid — check Identity`                                    | `SUPPORT EMAIL` is not a valid address.                                                                                                              | Correct `SUPPORT EMAIL` in the SITE IDENTITY card.                                            |
| `Cooldown: <M:SS>`                                                          | `Send Trouble Report` was pressed before the cooldown ended. `<M:SS>` is the time left.                                                              | Wait. See [Trouble report card](https://freshavlabs.com/docs/qr-jockey/#trouble-report-card). |
| `Email relay off`                                                           | `Enable_Email_Relay` is No.                                                                                                                          | None.                                                                                         |

| State       | Message                                  | Cause                                                                                                                                        | Remedy                                                                                                   |
| ----------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Compromised | `SMTP not configured: <fields>`          | A relay field is empty. `<fields>` names each empty one from `SMTP Server`, `SMTP Username`, `SMTP Password` and `SMTP From`, in that order. | Fill the named fields. The message clears when you fill the last one.                                    |
| Compromised | `Support email invalid — check Identity` | A send was pressed with an invalid `SUPPORT EMAIL`.                                                                                          | Correct `SUPPORT EMAIL`, then press `Send Test Email`. A send that the relay accepts clears the message. |
| Fault       | `Send failed: <detail>`                  | The last send failed, see `LAST RESULT`.                                                                                                     | Fix the cause. A send that the relay accepts clears the message.                                         |

### Reachability

`REACHABILITY` shows what the Core has proved about delivery. The check runs at design start, on `Refresh`, after a failed send, and when `HealthUrlOverride` changes. It never runs on a timer. A reading stays until the next check, so press `Refresh` for a current one.

| Reachability                      | Cause                                                                                                                                     | Remedy                                                                                                                             |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `Offline - scan the QR`           | The check has not passed yet, or one of its three tests failed, see [How It Works](https://freshavlabs.com/docs/qr-jockey/#how-it-works). | Check the Core's default route, then the name in `SERVER`, then HTTPS access to the health URL. `Send Trouble Report` still works. |
| `Reachable - mail not yet proven` | The Core reached the health URL, and no send has been accepted since.                                                                     | Press `Send Test Email`. This reading says nothing about port 25.                                                                  |
| `Relay accepted <HH:MM>`          | The relay accepted a send at that time. A failed send clears it.                                                                          | None. The reading does not prove delivery.                                                                                         |
| `Email relay off`                 | `Enable_Email_Relay` is No.                                                                                                               | None.                                                                                                                              |

### Status input

The external-status box on the Diagnostics page shows one status from outside the plugin, and the LED beside it lights for a fault. The status also appears in the Timeline and in the emailed report.

Two sources fill the box. Pick a block, or wire a source to both `StatusIn~External Status Text` and `StatusIn~External Status LED`. While a block is picked it wins over both pins. A pin write is then overwritten, and the debug window logs a Warning once per control until the design restarts. `--None--` hands the box back to the pins. With no block picked, the LED follows its pin.

`STATUS BLOCK` lists the native Status Combiners and the Roll Call blocks in the design. Set the block's Script Access to Script or All, or the list cannot show it. The list is read at design start and on `Refresh`. A picked block fills the box with its combined status and lights the LED when it reads Compromised, Fault or Missing. No `Refresh` is needed.

| Box text                                          | Cause                                                                                                                | Remedy                                                    |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| `Status block not found or not script-accessible` | A completed scan did not list the picked block. It was renamed or deleted, or its Script Access is None or External. | Set Script Access to Script or All, or pick the new name. |
| `Status block unreadable`                         | The block has no Status control, or the read failed.                                                                 | Pick a block that has a Status control.                   |

In both cases the LED lights and the pick stays. After a completed scan, the status bar also reads `Compromised` with the same message, unless a worse one shows, see [Status bar priority](https://freshavlabs.com/docs/qr-jockey/#status-bar-priority). Before the first scan completes, an unreadable block adds nothing to the status bar. Pick `--None--` to remove the pick.

## Licensing

The plugin reads `Activation_Code` and `Activation_Code_Backup` when the design starts.

Three license states

1. **Blank.** The plugin runs a 10-minute demo with every function. The LICENSE box counts down. Restart the design to start another demo.
2. **Valid code.** The LICENSE box reads `ACTIVATED`. There is no time limit.
3. **Wrong code.** The plugin runs the same demo and the LICENSE box reads `DEMO (invalid code): M:SS remaining`, so a mistyped code is visible. Correct or clear the code before the demo ends.

### What demo expiry stops

Every QR button, `Send Trouble Report` and `Send Test Email` grey out at expiry. Each QR button shows `LICENSE REQUIRED` in place of its QR. `Send Trouble Report` and `Send Test Email` do nothing, and a press from a pin logs a Warning. The status sweep, `Refresh` and the whole Diagnostics page keep running.

### Activate

Step 1. Read the Core's Locking ID

Set `Show_Locking_ID` to Yes and push the design. The Locking ID appears in the LOCKING ID box. Core Manager also shows it under Licensing, for any Core, with no design change. The Designer emulator reports `EMULATOR` or `*100000000000000`. The plugin marks it as not a Core ID. No code can be made for it.

Step 2. Get a code for that Locking ID

Buy or request an activation code at [freshavlabs.com](https://freshavlabs.com), quoting the Locking ID exactly.

Step 3. Enter the code and push the design

Paste the code into `Activation_Code` and push the design. The LICENSE box reads `ACTIVATED`. The plugin compares only the digits of the code, so punctuation and spaces do not matter. A code entered on a running design applies at the next design start.

Redundant Core pairs

Each Core has its own Locking ID and needs its own code. Put the primary Core's code in `Activation_Code` and the backup Core's code in `Activation_Code_Backup`. Read the backup Core's Locking ID from its own Core Manager; no failover is needed. Either code matching the running Core licenses the plugin, so a failover stays licensed.

### License status

Q-SYS prefixes the LICENSE box text with its own status word, so the box reads `OK - ACTIVATED` or `Compromised - DEMO: 9:59 remaining`.

| Status                              | Color  | Meaning                                                                           |
| ----------------------------------- | ------ | --------------------------------------------------------------------------------- |
| ACTIVATED                           | Green  | A code validated against this Core. No time limit.                                |
| DEMO: M:SS remaining                | Yellow | No code entered. Counting down.                                                   |
| DEMO (invalid code): M:SS remaining | Yellow | A code was entered and did not validate against this Core's Locking ID.           |
| DEMO EXPIRED - Activation Required  | Red    | The demo ran out. "What demo expiry stops" above says what the plugin still does. |

At expiry the plugin's `Status` control also reads `Fault - License required - demo expired`, so a Status Combiner sees the fault.

Codes are bound to one Core

An activation code works only on the Core whose Locking ID it was made for. It cannot move to another Core.

## Setup Page

The Setup page holds the site identity, the email relay and the trouble report. The header and the status bar are on all four pages. The LICENSE box is in the header's right column. At `Show_Locking_ID` Yes, the LOCKING ID box sits above it.

### Header

| Control                           | Range    | Description                                                                                                                                                                                                                                                                                    |
| --------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LOCKING ID` (`LicenseLockingID`) | Text     | The Core's Locking ID. See [Licensing](https://freshavlabs.com/docs/qr-jockey/#licensing).                                                                                                                                                                                                     |
| `LICENSE` (`LicenseStatus`)       | Text     | The license state. See [Licensing](https://freshavlabs.com/docs/qr-jockey/#licensing).                                                                                                                                                                                                         |
| `Refresh`                         | Trigger  | Draws every QR again, reads the Core's network interfaces again, runs the reachability check, rescans for status blocks and runs a sweep now.                                                                                                                                                  |
| `Connected` (LED)                 | On / off | Lights when the relay accepts a send. Goes out when a send fails, or when a send is pressed with a relay field empty. Off after every design start until a send is accepted. It does not prove delivery. Absent when `Enable_Email_Relay` is No.                                               |
| Status bar (`Status`)             | Status   | `OK` in normal operation. It also shows the messages in [Send results](https://freshavlabs.com/docs/qr-jockey/#send-results) and [Status input](https://freshavlabs.com/docs/qr-jockey/#status-input), and the expiry fault in [Licensing](https://freshavlabs.com/docs/qr-jockey/#licensing). |

The status bar reads `Firmware lacks QRCode library (upgrade Q-SYS)` as Compromised when the Core's firmware has no QR library. A QR button then shows `QR unavailable`, see [QR legends](https://freshavlabs.com/docs/qr-jockey/#qr-legends). A write to `Status` from outside the plugin is reverted at once, with a Warning in the debug window.

### Site identity card

| Control                          | Range | Description                                                                                                                                                                      |
| -------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SITE NAME` (`SiteName`)         | Text  | Names the site in the report subject and body. A blank name falls back as described in [What a Trouble Report Contains](https://freshavlabs.com/docs/qr-jockey/#trouble-report). |
| `ROOM NAME` (`RoomName`)         | Text  | Names the room in the same places.                                                                                                                                               |
| `SUPPORT EMAIL` (`SupportEmail`) | Text  | The address that receives the report, from the QR and from the email. The trouble report QR needs a valid address.                                                               |

### Email relay card

The card holds the relay login, the test button and two readouts. [Email relay](https://freshavlabs.com/docs/qr-jockey/#email-relay), [Send results](https://freshavlabs.com/docs/qr-jockey/#send-results) and [Reachability](https://freshavlabs.com/docs/qr-jockey/#reachability) explain them.

| Control                           | Range   | Description                                                                                 |
| --------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
| `SERVER` (`SmtpServer`)           | Text    | The relay's host name or address.                                                           |
| `USERNAME` (`SmtpUsername`)       | Text    | The relay login.                                                                            |
| `PASSWORD` (`SmtpPassword`)       | Text    | The relay password, see [Email relay](https://freshavlabs.com/docs/qr-jockey/#email-relay). |
| `FROM ADDRESS` (`SmtpFrom`)       | Text    | The sender address.                                                                         |
| `Send Test Email` (`SendTest`)    | Trigger | Sends a test mail to `SUPPORT EMAIL`.                                                       |
| `LAST RESULT` (`EmailLastResult`) | Text    | The outcome of the last send.                                                               |
| `REACHABILITY` (`ReachState`)     | Text    | What the Core has proved about delivery.                                                    |

### Trouble report card

| Control                              | Range             | Description                                                                                                                                                                                    |
| ------------------------------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `OPERATOR NOTES` (`OperatorNotes`)   | Text              | Free text for the emailed report only. It becomes the `Notes:` line and never changes a QR.                                                                                                    |
| `Send Trouble Report` (`SendReport`) | Trigger           | Runs a sweep and emails the report, see [What a Trouble Report Contains](https://freshavlabs.com/docs/qr-jockey/#trouble-report).                                                              |
| `COOLDOWN (MINUTES)` (`Cooldown`)    | 0 - 30, default 2 | The minutes after a report starts sending during which `Send Trouble Report` refuses another, even if that send fails. 0 turns the cooldown off. `Send Test Email` ignores it and starts none. |
| `LAST SENT` (`LastSent`)             | Text              | The date and time, as `YYYY-MM-DD HH:MM:SS`, of the last report or test mail that the relay accepted.                                                                                          |

## QR Codes Page

The QR Codes page holds three cards. Each QR redraws half a second after the last change to the fields that feed it.

### Trouble report QR card

| Control                         | Range  | Description                                                                                                                                                                                                          |
| ------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Trouble report QR (`QRTrouble`) | Button | Scan to open a pre-filled email to `SUPPORT EMAIL`. It needs no network on the Core, see [Requirements](https://freshavlabs.com/docs/qr-jockey/#requirements). `SITE NAME`, `ROOM NAME` and `SUPPORT EMAIL` feed it. |

### Wi-Fi QR card

| Control                         | Range                                 | Description                                       |
| ------------------------------- | ------------------------------------- | ------------------------------------------------- |
| Wi-Fi QR (`QRWiFi`)             | Button                                | Scan to join the network.                         |
| `SSID` (`WiFiSSID`)             | Text                                  | The network name.                                 |
| `PASSPHRASE` (`WiFiPassphrase`) | Text                                  | The network passphrase. Open networks carry none. |
| `ENCRYPTION` (`WiFiEncryption`) | WPA/WPA2, WEP, Open; default WPA/WPA2 | The network's security type.                      |
| `Hidden` (`WiFiHidden`)         | Toggle                                | Marks the network as hidden.                      |

### UCI link QR card

| Control                           | Range                       | Description                                                                                                                                                                    |
| --------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| UCI link QR (`QRUci`)             | Button                      | Scan to open the UCI.                                                                                                                                                          |
| `DIRECT LINK (PASTE)` (`UciLink`) | Text                        | The UCI's direct link. It accepts a full URL, a path that starts with `/`, or a bare token. The plugin keeps the path and takes the address from `INTERFACE`.                  |
| `INTERFACE` (`UciInterface`)      | `Auto` or an interface name | The Core interface whose address goes in the link. `Auto` uses the first interface that has a link and an address. The list comes from the Core, and `Refresh` reads it again. |
| `BUILT URL` (`UciUrl`)            | Text                        | The link that the QR holds, as `https://<address><path>`.                                                                                                                      |

The plugin cannot check that a link still works. Scan the QR again after you redeploy the UCI.

`BUILT URL` and the QR button report what stops the QR:

| BUILT URL                        | QR button      | Cause                                                                     | Remedy                               |
| -------------------------------- | -------------- | ------------------------------------------------------------------------- | ------------------------------------ |
| `no UCI link set`                | `SET UCI LINK` | `DIRECT LINK (PASTE)` is empty or holds none of the three accepted forms. | Paste the UCI's direct link.         |
| `no network interface available` | `NO NIC`       | `Auto` found no interface with a link and an address.                     | Connect and address an interface.    |
| `<interface> not on this Core`   | `NIC GONE`     | The chosen interface is not on this Core.                                 | Choose another interface, or `Auto`. |
| `<interface>: link down`         | `NIC DOWN`     | The chosen interface has no link.                                         | Connect the cable.                   |
| `<interface>: no usable IP`      | `NIC DOWN`     | The chosen interface has a link and no usable address.                    | Address the interface.               |

### QR legends

A QR button shows a legend in place of a QR when it cannot draw one. The UCI link legends are in the table above.

| Legend              | Cause                                                                     | Remedy                                                                                        |
| ------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `SET SUPPORT EMAIL` | `SUPPORT EMAIL` is empty or not a valid address.                          | Enter a valid address.                                                                        |
| `SET ENCRYPTION`    | `ENCRYPTION` holds none of the three choices.                             | Choose WPA/WPA2, WEP or Open.                                                                 |
| `NO DATA`           | A custom slot's text is empty.                                            | Enter the text.                                                                               |
| `QR ERROR`          | The renderer could not draw the text, for example because it is too long. | Shorten the text.                                                                             |
| `QR unavailable`    | The Core's firmware has no QR library.                                    | Update the Core's firmware.                                                                   |
| `LICENSE REQUIRED`  | The demo has expired.                                                     | See [What demo expiry stops](https://freshavlabs.com/docs/qr-jockey/#what-demo-expiry-stops). |

## Custom QR Page

The page holds `Custom_QR_Count` slots, three to a row. Each slot has a text box and a QR drawn from that text.

| Control                             | Range  | Description                                                                                                            |
| ----------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------- |
| `TEXT / URL <n>` (`CustomText <n>`) | Text   | The text or URL that the slot encodes.                                                                                 |
| Custom QR (`QRCustom <n>`)          | Button | The slot's QR. A blank text box shows `NO DATA`, see [QR legends](https://freshavlabs.com/docs/qr-jockey/#qr-legends). |

With one slot the control names carry no number: `CustomText` and `QRCustom`. Keep the text short. A longer text draws a denser code, which scans only with the phone held closer.

## Diagnostics Page

### Status sweep card

The sweep sees only components whose Script Access is Script or All. It reads the first of these names that is a Status control: `status`, `Status`, `input.status`, `output.status`, `config.status`, `call.status` and `script.status`. A component with none counts as having no status control, and that is not an error. `Status_Sweep` sets the interval, and `Refresh` runs a sweep now. While a block is picked and found, the sweep leaves it out: the visible count and the report's `!` and `~` lines skip it. Its changes reach the Timeline as `External status:` lines, and its status reaches the report on the `External status:` line.

| Control                               | Range | Description                                                                                                                                        |
| ------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VISIBLE COMPONENTS` (`SweepVisible`) | Text  | The visible count, then in brackets `<n> read`, `<n> no status` and `<n> err`, each only when it applies. For example `27 (20 read, 7 no status)`. |
| `LAST SWEEP` (`SweepLast`)            | Text  | The time the last sweep finished, as `HH:MM:SS`.                                                                                                   |

### Status input card

[Status input](https://freshavlabs.com/docs/qr-jockey/#status-input) explains the card.

| Control                                                     | Range                      | Description                                  |
| ----------------------------------------------------------- | -------------------------- | -------------------------------------------- |
| `STATUS BLOCK (PICK ONE, OR WIRE THE PINS)` (`StatusBlock`) | `--None--` or a block name | Picks the status block.                      |
| `EXTERNAL STATUS TEXT` (`ExtStatusText`)                    | Text                       | The external status. Read-only on the panel. |
| `LED` (`ExtStatusLed`)                                      | On / off                   | Lit for a fault.                             |

### Event timeline card

| Control                                     | Range | Description                                                     |
| ------------------------------------------- | ----- | --------------------------------------------------------------- |
| `EVENT TIMELINE (MOST RECENT)` (`Timeline`) | Text  | The newest ten events, newest first. A report carries up to 50. |

The Timeline survives a script restart and a Core reboot. Each event is one line that starts with its time. The panel shows `HH:MM:SS` for today's lines and `MM-DD HH:MM:SS` for older ones. The emailed report and the log file show the full date and time.

| Line                                                                            | Event                                                                                                                                                  |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `<component>: <old status> → <new status>`                                      | A swept component changed status. A component's first reading adds no line.                                                                            |
| `NIC change: <old count> → <new count>`                                         | An interface was added or removed, or changed its address, netmask or link. The two counts can match.                                                  |
| `External status: <old text> → <new text>`                                      | The external-status text changed.                                                                                                                      |
| `report handed to relay` and `test handed to relay`                             | The relay accepted a send.                                                                                                                             |
| `report send failed: <detail>` and `test send failed: <detail>`                 | A send failed.                                                                                                                                         |
| `QR Jockey v<version> started; <n> events restored; design '<name>'`            | The script started. The middle part reads `store empty` when there was nothing to restore.                                                             |
| `License: activated`                                                            | The script started with a valid activation code. A licensed block adds this line at every start. A match on the backup code adds `(backup core code)`. |
| `Reach: <old> → <new> (<reason>)`                                               | The reach check's result changed between `offline` and `reachable`. `<reason>` names the tier.                                                         |
| `Status block picked: '<name>' (<state>)` and `Status block cleared (--None--)` | The picked status block changed.                                                                                                                       |
| `Warning: <message>` and `Error: <message>`                                     | The plugin logged a warning or an error. A repeat while the first line is among the newest ten folds into it as `(x<n>, last HH:MM:SS)`.               |

### API availability card

| Control                                        | Range | Description                                                                                                                                                                                                                                                                                                                   |
| ---------------------------------------------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `API AVAILABILITY / HEALTH URL` (`ApiReadout`) | Text  | Two lines. The first reads `QRCode=yes rapidjson=yes Email=yes Crypto=yes Network=yes Component=yes HttpClient=yes`. A `no` names a library the Core's firmware lacks, and the feature that needs it stops working. Without `rapidjson` the plugin uses its own encoder instead. The second reads `Health: <url> (<source>)`. |

`<source>` is `default`, `override`, or `override ignored - not https`. See `HealthUrlOverride` in [Control Pins](https://freshavlabs.com/docs/qr-jockey/#control-pins).

## What a Trouble Report Contains

The email goes to `SUPPORT EMAIL` with the subject `[<site> / <room>] Trouble Report`. A blank site or room falls back to the Core's name or location in the subject, and then to `unknown`. The body holds these lines in order:

1. `Site: <site> / <room>`, with `unknown` for a blank name. The body does not use the Core fallback.
2. `Design: <name> (<platform>, <state>)`.
3. `Core: <name> @ <location> FW: <firmware>`.
4. One line per network interface, `<interface>: <address>`.
5. `Time: <date and time> Uptime: <uptime>`.
6. `Components visible to sweep: <n>`, followed by `(<n> read)`, `(<n> no status control)` and `(<n> unreadable)` where each applies. The picked status block is not counted.
7. `Note: component list unreadable at send time; figures are from the sweep at <HH:MM:SS>`, or `Note: component list unreadable at send time; no sweep has completed yet`, only when the component list could not be read.
8. `External status: <text> (<source>)`, only when the external-status box holds text. `<source>` is the picked block's name or `pin`.
9. One line per faulty component other than the picked status block, which line 8 reports. `! <component>: <status>` covers Fault, Missing and Compromised. `~ <component>: <status>` covers Not Present and Initializing. A status Value outside the six Q-SYS states counts as a fault. A component whose status cannot be read gets no line and is counted in `(<n> unreadable)`. Each group is in name order.
10. `Notes: <text>` from `OPERATOR NOTES`, only when it holds text.
11. `Log file: Core Manager > Files > QRJockey > <CodeName>.log`, or `Log file: not written (<reason>)`. The emulator reads `not written (emulator)`.
12. The Timeline events, newest first, each with its date and time. When they do not all fit, the oldest are dropped and a line `(<n> older events not shown; see the log file)` follows them. Without a log file it reads `(<n> older events not shown)`.
13. `--- Describe the issue: `.

The QR carries lines 1 to 5 and line 13, and nothing else. See [How It Works](https://freshavlabs.com/docs/qr-jockey/#how-it-works). It holds them as they stood at its last redraw, and a new interface address does not redraw it. Press `Refresh` after a network change.

Uptime is how long the design has run, counted in sweep intervals. It is not the Core's uptime. A design push starts it again. It reads `unknown` until the first periodic sweep, and always at `Status_Sweep` Off. `Refresh` does not advance it. A body longer than 14,336 bytes is cut and ends with `[truncated]`.

## Control Pins

Each panel control is also a pin, named `Group~Name`. The Features tables give each control's script name beside its legend. With two or more custom slots, each slot pin carries the slot number after the name, such as `Custom~Text 2`. With one slot it has no number.

### Connection and license pins

| Pin                    | Type    | Direction |
| ---------------------- | ------- | --------- |
| `Connection~Status`    | Status  | Output    |
| `Connection~Connected` | LED     | Output    |
| `Connection~Refresh`   | Trigger | Input     |
| `License~Status`       | Status  | Output    |
| `License~Locking ID`   | Text    | Output    |

The `License~Locking ID` pin carries that name only at `Show_Locking_ID` Yes, and `Connection~Connected` only at `Enable_Email_Relay` Yes. Otherwise each carries its control name, `LicenseLockingID` or `Connected`.

### Email and report pins

| Pin                          | Type    | Direction            |
| ---------------------------- | ------- | -------------------- |
| `Identity~Site Name`         | Text    | Both                 |
| `Identity~Room Name`         | Text    | Both                 |
| `Identity~Support Email`     | Text    | Both                 |
| `Email~SMTP Server`          | Text    | Both                 |
| `Email~SMTP Username`        | Text    | Both                 |
| `Email~SMTP Password`        | Text    | Both, reads `******` |
| `Email~From Address`         | Text    | Both                 |
| `Email~Send Test Email`      | Trigger | Input                |
| `Email~Last Result`          | Text    | Output               |
| `Email~Reachability`         | Text    | Output               |
| `Report~Operator Notes`      | Text    | Both                 |
| `Report~Send Trouble Report` | Trigger | Input                |
| `Report~Cooldown`            | Integer | Both                 |
| `Report~Last Sent`           | Text    | Output               |

At `Enable_Email_Relay` No, the `Email~` and `Report~` pins stay on the block under their control names, such as `SmtpServer`.

### QR pins

| Pin                 | Type      | Direction |
| ------------------- | --------- | --------- |
| `QR~Trouble Report` | Momentary | Output    |
| `QR~WiFi`           | Momentary | Output    |
| `QR~UCI Link`       | Momentary | Output    |
| `QR~Custom`         | Momentary | Output    |
| `WiFi~SSID`         | Text      | Both      |
| `WiFi~Passphrase`   | Text      | Both      |
| `WiFi~Encryption`   | Text      | Both      |
| `WiFi~Hidden`       | Toggle    | Both      |
| `UCI~Link`          | Text      | Both      |
| `UCI~Interface`     | Text      | Both      |
| `UCI~Built URL`     | Text      | Output    |
| `Custom~Text`       | Text      | Both      |

### Status input and diagnostics pins

| Pin                             | Type | Direction |
| ------------------------------- | ---- | --------- |
| `StatusIn~Status Block`         | Text | Both      |
| `StatusIn~External Status Text` | Text | Input     |
| `StatusIn~External Status LED`  | LED  | Input     |
| `Diagnostics~Sweep Visible`     | Text | Output    |
| `Diagnostics~Last Sweep`        | Text | Output    |
| `Diagnostics~Timeline`          | Text | Output    |
| `Diagnostics~API Readout`       | Text | Output    |

### Pin-only control

| Pin                 | Type | Direction |
| ------------------- | ---- | --------- |
| `HealthUrlOverride` | Text | Both      |

`HealthUrlOverride` has no panel control. A blank value uses the built-in health URL. Only a value that starts with `https://`, in lower case, is used. Any other value is ignored and the API readout says so. A change runs the reachability check again.

## Troubleshooting

#### A QR button shows text instead of a QR

* The text names the cause. See [QR legends](https://freshavlabs.com/docs/qr-jockey/#qr-legends) and [UCI link QR card](https://freshavlabs.com/docs/qr-jockey/#uci-link-qr-card).

#### The test mail never arrives

* The likely cause is a wrong `USERNAME` or `PASSWORD`. [Email relay](https://freshavlabs.com/docs/qr-jockey/#email-relay) explains why Q-SYS cannot report it.
* Correct the login, then press `Send Test Email` again.

#### The status bar is not OK

* Every message that the plugin writes there is listed in [Send results](https://freshavlabs.com/docs/qr-jockey/#send-results), [Status input](https://freshavlabs.com/docs/qr-jockey/#status-input) and [Header](https://freshavlabs.com/docs/qr-jockey/#header).

#### Send Trouble Report does nothing

* Read `LAST RESULT` first. See [Send results](https://freshavlabs.com/docs/qr-jockey/#send-results).
* If the QR buttons read `LICENSE REQUIRED`, the demo has expired. See [What demo expiry stops](https://freshavlabs.com/docs/qr-jockey/#what-demo-expiry-stops).
* With `Enable_Email_Relay` at No, the button is not on the panel.

#### Reachability reads Offline

* See [Reachability](https://freshavlabs.com/docs/qr-jockey/#reachability).

#### The UCI QR scans but the page does not open

* A revoked, expired or regenerated UCI link still scans, see [UCI link QR card](https://freshavlabs.com/docs/qr-jockey/#uci-link-qr-card). Paste the current link into `DIRECT LINK (PASTE)`.

#### A QR does not scan on a panel

* A long text makes a dense code. Shorten the text, see [Custom QR Page](https://freshavlabs.com/docs/qr-jockey/#custom-qr-page).

#### The sweep sees fewer components than the design holds

* See [Status sweep card](https://freshavlabs.com/docs/qr-jockey/#status-sweep-card). Set Script Access to Script or All on each missing component, then press `Refresh`.

#### A picked status block shows an error

* See [Status input](https://freshavlabs.com/docs/qr-jockey/#status-input).

#### Uptime reads unknown

* Uptime needs the periodic sweep, see [What a Trouble Report Contains](https://freshavlabs.com/docs/qr-jockey/#trouble-report). At `Status_Sweep` Off, set an interval and push the design.

## Known Issues

### After you clear a pick, the external-status box can show an old value

Versions 1.1.0 and 1.1.1. After you pick `--None--`, the external-status box and its LED can show the pins' earlier value. They show nothing if the design has restarted since the pins last changed. `Refresh` does not correct it. While a block is picked, a pin change to the value already on display goes unseen.

**Workaround:** change the status that the `StatusIn~` pins carry. The box and the LED then follow the pins again.

## How It Works

### Reachability tiers

The check asks whether the Core can deliver a report, and it claims no more than it proved. Networks often allow web traffic and block outbound SMTP, so web access says nothing about mail.

| Tier | Test                                                                            | What it may claim                                     |
| ---- | ------------------------------------------------------------------------------- | ----------------------------------------------------- |
| 0    | Some interface has a default gateway that is neither blank nor `0.0.0.0`.       | A negative only. With no gateway the Core is offline. |
| 1    | The name in `SERVER` resolves in DNS. A blank `SERVER` skips this tier.         | The name resolves.                                    |
| 2    | An HTTPS request to the health URL returns the expected reply within 5 seconds. | Web access works.                                     |

Tier 2 accepts only status 200 with the expected body, because a captive portal answers every URL with a page that looks like success. A failure in any tier reads `Offline - scan the QR`. Passing all three reads `Reachable - mail not yet proven`. Only a send that the relay accepts reads `Relay accepted <HH:MM>`, and that reading outranks the tiers until a send fails. The QR always draws. One check runs at a time, and a check that gets no reply ends after 15 seconds.

### Sweep and Timeline

A sweep reads ten components every 0.1 seconds, so a large design does not hold the Core's shared script thread. The plugin compares each component's status with the one from the previous sweep. A change adds a Timeline line, and a component's first reading adds none. A clear or a pick of another block gives the picked block back to the sweep. The sweep starts it from the picker's last reading, so only a later change adds a line. A sweep whose result differs from the last also redraws the trouble report QR. `Refresh` and `Send Trouble Report` read up to 200 components at once.

Each new Timeline line is also appended to a file on the Core, at Core Manager > Files > `QRJockey` > `<CodeName>.log`. A folded repeat is written when its count reaches 10, 100, 1000 and so on. At 512 KB the file becomes `<CodeName>.prev.log`, so the two files hold at most 1 MB. The files are named by the block's Code Name. Each byte other than an ASCII letter, a digit, `_` or `-` is written as `~` and two hex digits. An encoded name longer than 64 characters keeps its last 64. A block with a different Code Name starts a new pair, and the plugin never deletes an old pair. The plugin never reads the file back. The startup banner and the report's `Log file:` line name the exact file.

### Status bar priority

When the picker and the rest of the plugin both post a status-bar message, the more severe shows, and the picker loses a tie.

### Why the email carries more than the QR

A touch panel truncated a large QR image that Designer and a web UCI drew whole, so only the panel showed the failure. A QR that held the full report drew with its lower rows blank. The QR therefore holds only the identity header, which scans at once. The email has no such limit and holds the rest. If the whole encoded link exceeds 2400 characters, the QR carries the address and the subject and no body.

## Support

* Support tickets: [freshavlabs.com/support](https://freshavlabs.com/support/)
* Website: [freshavlabs.com](https://freshavlabs.com)
* Email: <support@freshavlabs.com>

Include with a request:

* Q-SYS Designer version
* Core model and firmware version
* Plugin version, shown under the plugin name in the header
* The emailed report, or the text of the `API AVAILABILITY / HEALTH URL` box
* The Locking ID, for a license question
* Debug output captured with `Debug_Level` set to Verbose
* The block's log file, `<CodeName>.log`, from Core Manager > Files > `QRJockey`
