Skip to main content

Global variable groups

Global variable groups share values between the active locks of selected wearers. The owner manages the groups; each group has its own values. Ordinary workspace variables and saved memory keep their existing scope.

For example, two wearers can contribute to a shared score. Each connected program reads the same value and can react when either wearer changes it. A second group can also have a score, with an independent value. Disabling one wearer's connection leaves the value and the other wearer's access intact.

Where a value belongsWho shares it
Ordinary workspace variableExecutions of that PLE workspace in the current session.
Saved memoryLinked workspaces for the same wearer and controlling account, including later sessions.
Global variable groupConnected wearers in that owner-managed group.

See Variables for ordinary variables and saved memory. Start with the eight-wearer simulator without extra accounts, or follow the two-wearer live test below.

Create a group and connect wearers​

  1. As the owner, open the live PLE editor, then Group variables → Manage global variable groups. The Global variable groups guide link in the manager opens this page in a new tab.
  2. Choose Create group, optionally entering a name. Select it under Manage group.
  3. Add a variable with a unique key, type, and starting value. For example, score, Integer, 0. Keys start with an ASCII letter and contain only letters, numbers, and underscores (up to 64 characters). Types are Boolean, Number, Integer, Text, Date and time, Color, and Number list.
  4. Add wearers from your active shared locks. A wearer belongs to one group at a time; adding them to another group moves them. A group's first wearer establishes its original template owner, and later members must have locks from that same original template owner. This keeps unrelated template families separate; you still need to use compatible variable keys, types, and program logic.
  5. Use the Wearer connections matrix to enable or disable each variable for each wearer. Connections start enabled, including variables added later. An unchecked cell blocks reads, writes, and change events for that wearer and variable.

The group panel saves changes immediately, independently of saving the Blockly workspace. Change value updates the shared value and emits a change event when the value differs. Refresh groups and values loads the latest values. Renaming a group preserves its values. Deleting a group disconnects its wearers; deleting a variable makes its key unavailable to programs until a variable is created again.

The manager is also available under Variables → Manage variables → Global variable groups. The direct button opens your real owner-managed groups; use Test with 8 wearers for simulated groups.

Groups and values are not included in workspace exports. Importing or copying a program does not create memberships or grant access.

Blocks​

BlockBehavior
group variableReads the current shared value for the entered key.
group variable connected?Returns true when this wearer has an enabled connection to that key.
group variable connected countCounts distinct wearers with an enabled connection to this variable in this group, including the current wearer.
set group variable … toReplaces the shared value, enforcing its declared type.
increase group variable … byAtomically adds a number to a Number or Integer variable. Negative amounts subtract.
when a group variable changesRuns in enabled PLE workspaces of connected active group members, including the source lock when it has this handler.
when a group variable connection count changesReports the previous and new connected counts to the currently connected wearers.

Use connected? before accessing an optional variable. A disconnected variable is unavailable, not a false Boolean or zero counter; an unguarded read/write stops that run with an error. For concurrent counters, use increase group variable rather than reading the value and setting value + 1.

Automatic values such as button visibility can read group values. A returning function used there must remain a calculation; writing group variables requires normal event execution. Functions called from buttons can combine group operations with dialogs.

Change events​

Use Events → when group variable [score] changes for a separate handler per variable. Enter the exact, case-sensitive key, such as score or bonus. It runs only for that key. The overall when a group variable changes block is still available and already includes the changed variable's name and its previous/new values, so it never needs local copies to detect which value changed. If both handlers match, both run.

Both value-change handlers expose source username, source user ID, and source lock ID. Owner edits identify the owner; program writes identify the originating lock's wearer, including automatic runs. This identifies the source lock's wearer, not necessarily the person who clicked a button. Username is captured at the time of the change; use the stable user ID for comparisons. Owner edits have an empty source lock ID. Older queued events have empty source identity fields; a missing user has an empty username. If a handler writes another variable, the new event identifies that handler's own lock as the source.

on.globalVariableChangedFor({ key: "score" }, (event) => {
print(text(event.variableSourceUsername, " changed score: ", event.variablePreviousValue, " → ", event.variableValue));
});
on.globalVariableChangedFor({ key: "bonus" }, (event) => {
print(text("Bonus changed to ", event.variableValue));
});

In Test with 8 wearers, source names are Wearer 1 through Wearer 8 (user IDs sandbox-wearer-1 through sandbox-wearer-8, lock IDs sandbox-lock-1 through sandbox-lock-8). A value edited in the tester's group controls reports Owner, user ID sandbox-owner, and no lock ID. Add score and bonus, then change each separately: only its matching handler should print. Disabling a wearer's score connection stops that wearer receiving score events, while enabled bonus events continue.

The value-change event provides variable name, previous value, new value, connected count, and change source (owner or program). Filter by variable name. Values retain the declared type. Setting the same value again does not emit an event. Creation, deletion, membership changes, and checkbox changes do not emit value-change events.

When a group variable connection count changes provides variable name, previous connected count, and connected count. It responds to joining, leaving, moving groups, enabling/disabling that variable, and losing access through ownership or active-lock changes. It does not change the variable's value. Disabled or disconnected wearers do not receive the event; remaining connected wearers do, and newly enabled wearers can receive the event for joining.

Counts refer to distinct wearers with active, enabled connections to that specific variable, including yourself. They are not counts of PLE workspaces, logged-in users, or all members regardless of their checkbox. A second group with the same key is independent; there is currently no owner-wide variable shared across groups. With all connections enabled, the count equals the group's wearer count.

Use globals.connectedCount({ key: "score" }) for a live count. Guard it with globals.connected: disconnected count reads fail, just like value reads. Event counts are snapshots of the occurrence and can differ from a later live read. Existing groups establish their initial count silently when this feature starts; value events already queued by an older server can have a missing count (null).

Count delivery is asynchronous. Reconciliation recovers interruptions and deleted locks. Concurrent changes or changes accumulated during a backlog can be combined into one observed count transition; this is not a member-by-member audit log. Replacing one wearer with another without changing the observed count does not emit a count-change event.

Events run in the background, so they cannot wait for confirmations, input prompts, menus, wheels, or other interactive dialogs. Use ordinary actions, notifications, or variables to respond. A later button can ask for confirmation. Printed output belongs to the execution history and does not open a live dialog for an absent wearer.

Delivery is asynchronous. Previous/new values describe that specific change; reading the variable during its handler may return a newer value. Changes are ordered per variable and receiving workspace. Connection changes invalidate queued events and paused group-using runs for that wearer, including events for the wearer's other variables. Reconnecting does not replay old events.

The server retains delivery records for seven days and recovers pending work after a queue outage. If an executing handler is interrupted, its completed effects are not rolled back and it is not automatically replayed. The group panel reports failed/interrupted deliveries; inspect the affected lock's PLE history before repeating effects.

Owner changes​

An ownership change removes the wearer's group connection. The group's values and other wearers remain intact. Returning to the original owner does not restore access automatically: the owner must add the wearer to a group again. This creates fresh, enabled connections. Ended, archived, abandoned, or unlocked locks cannot use group variables.

Once disabling, removing, moving, or disconnecting a connection completes, an unfinished write using the old connection cannot commit or create a change event. Changes already committed before disconnection are preserved. Checking connected? earlier in a run does not guarantee that access will still be available at a later step.

Example and testing​

Set up two wearers​

Use two active shared locks, Wearer A and Wearer B, with the same current owner and original template creator. Both need a saved, enabled PLE program. These steps verify live delivery. To try the same program without accounts or live locks, use Test with 8 wearers.

  1. As the owner, create a group named Test team in Group variables → Manage global variable groups.
  2. Add score, type Integer, starting value 0.
  3. Assign A and B to the group. Leave both score connections checked.
  4. Open the Code editor in each PLE workspace and add the program below. Save the changes in both workspaces before testing. If a workspace already has a program, keep a copy before replacing it.

The example changes only the shared score and prints results; it contains no lock-time or device actions.

button("Read score", () => {
if (globals.connected({ key: "score" })) {
print(text("Shared score: ", globals.get({ key: "score" })));
print(text("Connected wearers: ", globals.connectedCount({ key: "score" })));
} else {
print("Score is disconnected.");
}
});

button("Add one point", () => {
if (globals.connected({ key: "score" })) {
globals.increment({ key: "score", value: 1 });
print("Added one point.");
} else {
print("Score is disconnected. Nothing changed.");
}
});

on.globalVariableChanged((event) => {
if (event.variableName == "score") {
print(text(
"Score changed: ",
event.variablePreviousValue,
" → ",
event.variableValue,
" / source: ",
event.variableChangeSource,
" / connected: ",
event.variableConnectedCount
));
}
});

Add this handler to both programs to see membership and connection changes:

on.globalVariableConnectionsChanged((event) => {
if (event.variableName == "score") {
print(text("Connected wearers: ", event.variablePreviousConnectedCount, " → ", event.variableConnectedCount));
}
});

Check sharing, events, and disconnection​

Follow these steps in order. Wait for each change event to be delivered before continuing. Open each lock's Execution log and use Refresh log to inspect the background event output. The owner can inspect the log when the wearer's history visibility is disabled. Event output does not open a live dialog.

ActionExpected result
A and B each click Read score.Both see Shared score: 0 and Connected wearers: 2.
A clicks Add one point.Score becomes 1. Both programs receive Score changed: 0 → 1 / source: program / connected: 2.
B clicks Add one point.Score becomes 2. Both programs receive the change from 1 to 2.
The owner unchecks B's score cell in Wearer connections.Score stays 2. A receives Connected wearers: 2 → 1; B receives no count event. A's live count is now 1.
B clicks Read score, then Add one point.Both report disconnection. Score stays 2; neither program receives a new change event.
A clicks Add one point.Score becomes 3. A receives the change from 2 to 3; B receives no event.
The owner rechecks B's score cell, then B clicks Read score.B reads score 3 and count 2. Both receive Connected wearers: 1 → 2. The missed value event is not replayed.
B clicks Add one point.Score becomes 4. Both programs receive the change from 3 to 4.

Use Refresh groups and values in group management to independently check the stored score. You can also use Change value to set it to a different number: connected programs receive an event with source owner. Setting the same value again produces no event.

Verify that access is enforced​

The main example checks the connection before using it. To check what happens without that guard, temporarily add these buttons to B's program:

button("Test unguarded read", () => {
print(text("Score: ", globals.get({ key: "score" })));
});

button("Test unguarded count", () => {
print(globals.connectedCount({ key: "score" }));
});

button("Test unguarded write", () => {
globals.increment({ key: "score", value: 1 });
});

Uncheck B's score connection, then run each test button. All three executions must fail with a disconnected-variable error. The score must remain unchanged, and these failed executions must not emit value-change events. A may receive the count-change event caused by unchecking B's connection. A disconnected read must not return 0 or false. Remove the three test buttons afterward.

Check group isolation and ownership changes​

  • Create another group with its own Integer score, starting at 100. Move B to that group. B reads 100; A still reads the first group's value. Each group's score count is now 1, and remaining members receive the count decrease in the original group. Incrementing either group's score leaves the other group unchanged.
  • Transfer a test lock to another owner, then back. Its connection stays unavailable until the original owner manually adds the wearer to a group again. Other members retain their connections and the group's values, and receive a reduced count when the lock leaves.

Test with eight virtual wearers​

Open the PLE editor's Simulator (or Test runtime on a live lock) and choose Test with 8 wearers. This separate group test always simulates actions. It needs no extra accounts, email addresses, subscriptions, or live locks, and never reads or changes your real groups.

Each virtual wearer has an independent copy of the current program, ordinary variables, simulated lock state, and dialog continuation. All eight start in one empty test group with connections enabled. Add typed variables under Shared test groups. Up to eight independent test groups let you try separate teams with the same variable keys.

Try sharing and disconnection​

  1. Put the Read score / Add one point example and its connection-count handler in the editor. Apply the code, then open Test with 8 wearers.
  2. Under Shared test groups, enter score, choose Integer, enter initial value 0, then click Add variable. Typing the key alone does not create it. All eight wearers are connected by default.
  3. Select Wearer 1, choose Add one point under Control or event, and click Run as Wearer 1. The shared value becomes 1; the Combined log shows the value-change handler for all eight wearers with connected count 8.
  4. Uncheck Wearer 2 in the score connection column. The value remains 1. The other seven receive a count change from 8 to 7; Wearer 2 receives no count event.
  5. Select Wearer 2 and run Read score, then Add one point. Both report disconnection and the shared value stays 1. The unguarded test buttons instead produce a disconnected-variable error.
  6. Run Add one point as Wearer 1 again. The value becomes 2. Only the seven enabled wearers receive the value-change event.
  7. Recheck Wearer 2's connection. All eight receive the count change from 7 to 8. Wearer 2 can read 2; earlier value events are not replayed.

Change value acts as the simulated owner and emits a value event with source owner. Equal-value writes emit no event. Assign a wearer to another group to check isolation. Simulate owner change disconnects that wearer and cancels paused work; Return to original owner leaves them disconnected until you choose a group again. Ending a simulated lock also disconnects it.

Programs, dialogs, and reset​

After editing your program, use Load current program for all or Load current program for this wearer. Loading clears the selected wearers' runtime state and pending dialogs, while keeping groups, values, and connections. This allows different programs to interact in one scenario. Copies are not updated automatically as you edit.

For a button that opens a confirmation or input, click Answer dialog to respond. You can leave it waiting and select another wearer. Events for a paused wearer wait; events for other wearers continue. Answering resumes from the pause without repeating earlier actions, and subsequent reads see the current shared value. Connection or owner changes cancel that wearer's paused run and invalidate its queued events. Background group handlers cannot open interactive dialogs, just as in live execution.

Reset test state restores shared values to their original creation values, clears each wearer's variables and simulated lock state, and empties the queue and log. It keeps program copies, groups, and connection choices. A wearer disconnected by an owner change or ended lock still needs manual assignment. The scenario is saved in this browser tab for the current account and editor. Closing and reopening the editor or reloading the page restores program copies, groups, values, connections, runtime state, paused dialogs, queue, and log. Restoration validates the saved state without executing queued events or answering dialogs. Use Process queued events or Answer dialog when ready. Closing the browser tab clears the saved scenario; it is not synchronized across devices or exported. If tab storage is unavailable or full, a warning tells you to keep the editor open. If restoration fails, Start group test replaces the saved scenario. Escape closes only the top dialog, keeping the editor open when closing the group tester.

Latest output beside the run controls shows the selected wearer’s recent output and status. View log jumps to the combined log filtered to that wearer. The loaded-handler summary shows whether value-change and connection-count handlers are present in that wearer’s program copy. Newly created groups are selected automatically.

The combined log includes wearer, event type, printed text, simulated actions, value changes, count changes, and errors. Routine completion entries are hidden by default; enable Show completion entries to see them. Errors and printed output remain visible. You can filter it by wearer; shared changes remain visible. It retains the latest 200 entries within 64 KiB. A request processes up to 64 event deliveries; use Process queued events if more remain. Paused wearers' events wait until you answer or cancel their run. The queue is limited to 512 deliveries and event-write chains to 12 levels.

What the simulator does not verify​

Only group value/count events are generated automatically. Other event types must be selected and run manually; time and scheduled events do not advance automatically. One program represents each wearer's virtual lock. Actions use the existing draft action simulation, so no real device, notification, payment, or live lock is affected. The simulator exercises shared-variable logic but does not verify production authentication, subscriptions, database concurrency, worker delays/recovery, or real device/service delivery. Live group throttling and production queue behavior still need a live test.

Single-wearer draft inputs​

Single-wearer draft tests never access live groups. The test panel exposes Group variable: score; enable it and choose the appropriate input type/value to simulate a connection, or leave it unchecked to simulate disconnection. Simulated writes persist until Reset test state. After changing mock connection inputs, reset the test state to start from those inputs. For a count block, Connected wearers: score sets the mock count (default 1, minimum 1 for a connected variable). Run either event block separately with mock event values; single-wearer draft writes do not fan out to other workspaces; use Test with 8 wearers for automatic group interactions.

Limits and troubleshooting​

Limits are 30 groups per owner, 50 variables and 200 wearers per group, and 4 KiB per value. A group accepts up to 60 actual value changes per minute with at most 100 value/count events waiting to be distributed. Event-triggered write chains stop after 12 levels. Guard handlers with conditions and avoid feedback loops between locks.

SymptomWhat to check
A wearer cannot be added.Their lock must be active, shared, currently controlled by the group owner, and from the same original template creator as the group's other locks.
A button reports disconnection.Check group membership, the variable's exact key, its connection checkbox, and whether ownership or active-lock status changed.
Both wearers have a score, but the values differ.Check that they belong to the same group. Matching keys in separate groups do not share values.
No change event appears.Check that both saved PLE programs are enabled, the receiving connection is checked, the handler filters the correct key, and the write actually changed the value. Wait for asynchronous delivery and refresh the execution log.
A background handler fails at a dialog.Change handlers cannot use interactive dialogs, including dialogs inside called functions. Move that interaction to a button.
Single-wearer draft testing does not affect another wearer.Open Test with 8 wearers, add the shared variable, and check membership and connection cells. For production delivery, use the live-lock walkthrough.