Skip to main content

Gateway Button Panel

This example shows how a Gateway can act as a central button command processor.

A common setup is:

Left Hand Button
|
v
Gateway
|
v
Local Action or Broadcast Command

This is useful when buttons, switches or sensors on one module should control behavior across the whole ArmorLink network.

For more information about Commands, see Commands.

What This Example Does

This example uses two modules:

  • A Left Hand module that sends button Commands
  • A Chest Gateway that receives those Commands and reacts to them

The Gateway can then:

  • Execute local behavior
  • Play a sound
  • Stop audio
  • Broadcast a Command to multiple modules
  • Trigger synchronized behavior across the network

Hand Module

The hand module reads a local button and sends a Command to the Gateway.

#include <ArmorLink.h>

#define BUTTON_PIN 4

ArmorLinkModule module(
"Left Hand",
ArmorLinkModuleType::Hand
);

bool lastButtonState = HIGH;

void setup()
{
Serial.begin(115200);
delay(500);

pinMode(BUTTON_PIN, INPUT_PULLUP);

ArmorLinkOptions options;
options.enableGateway = false;
options.enableEspNow = true;
options.enableBle = false;
options.enableSerialLogging = true;

ArmorLink.begin(module, options);

ArmorLink.info("Left Hand module started");
}

void loop()
{
ArmorLink.loop();

bool currentButtonState = digitalRead(BUTTON_PIN);

if (lastButtonState == HIGH && currentButtonState == LOW) {
handleButtonPress();
}

lastButtonState = currentButtonState;
}

void handleButtonPress()
{
ArmorLink.info("Left hand button pressed");

ArmorLink.sendCommand(
"Chest",
"BTN_L1",
"SINGLE_CLICK"
);
}

Gateway Module

The Gateway receives the Command from the hand module and reacts to it using an Action.

#include <ArmorLink.h>

ArmorLinkModule chestModule(
"Chest",
ArmorLinkModuleType::Chest
);

void stopAudio()
{
ArmorLink.info("Stopping audio");
}

void setup()
{
Serial.begin(115200);
delay(500);

chestModule.actions()
.add("leftBtn1SingleClick")
.label("Left BTN1 Single Click")
.command("BTN_L1", "SINGLE_CLICK")
.onExecute([]{
stopAudio();
});

ArmorLinkOptions options;
options.enableGateway = true;
options.enableEspNow = true;
options.enableBle = true;
options.enableSerialMenu = true;
options.enableSerialLogging = true;
options.bleName = "ArmorLink Gateway";

ArmorLink.begin(chestModule, options);

ArmorLink.info("Chest Gateway started");
}

void loop()
{
ArmorLink.loop();
}

Command Flow

The button module sends:

ArmorLink.sendCommand(
"Chest",
"BTN_L1",
"SINGLE_CLICK"
);

This means:

PartValue
TargetChest
EntityBTN_L1
CommandSINGLE_CLICK

The Gateway has a matching Action:

chestModule.actions()
.add("leftBtn1SingleClick")
.label("Left BTN1 Single Click")
.command("BTN_L1", "SINGLE_CLICK")
.onExecute([]{
stopAudio();
});

When the Command arrives, ArmorLink executes the Action locally on the Gateway.

Gateway Broadcast Example

The Gateway can also react to a button Command by broadcasting another Command to all modules.

Example:

chestModule.actions()
.add("leftBtn1SingleClick")
.label("Left BTN1 Single Click")
.command("BTN_L1", "SINGLE_CLICK")
.onExecute([]{
ArmorLink.broadcastCommand(
"Flaps",
"toggle"
);
});

Any module with a matching Action can react:

module.actions()
.add("toggleFlaps")
.label("Toggle Flaps")
.command("Flaps", "toggle")
.onExecute([]{
toggleFlaps();
});

This allows one button press to trigger behavior across multiple modules.

Broadcast Flow

Left Hand Button
|
v
sendCommand("Chest", "BTN_L1", "SINGLE_CLICK")
|
v
Chest Gateway Action
|
v
broadcastCommand("Flaps", "toggle")
|
v
All modules receive Command
|
v
Matching Actions execute

Modules without a matching Action ignore the Broadcast Command.

Multiple Button Actions

The Gateway can define multiple button Actions.

chestModule.actions()
.add("leftBtn1SingleClick")
.label("Left BTN1 Single Click")
.command("BTN_L1", "SINGLE_CLICK")
.onExecute([]{
ArmorLink.broadcastCommand("Flaps", "toggle");
});

chestModule.actions()
.add("leftBtn1DoubleClick")
.label("Left BTN1 Double Click")
.command("BTN_L1", "DOUBLE_CLICK")
.onExecute([]{
ArmorLink.broadcastCommand("Lights", "toggle");
});

chestModule.actions()
.add("leftBtn1LongPress")
.label("Left BTN1 Long Press")
.command("BTN_L1", "LONG_PRESS")
.onExecute([]{
ArmorLink.broadcastCommand("System", "shutdown_effects");
});

This pattern works well for glove buttons, hidden switches, magnetic reed switches and other local inputs.

Local Behavior and Network Behavior

A button handler can perform local behavior and send a Command.

Example:

void handleButtonPress()
{
ArmorLink.info("Button pressed");

// Local behavior
flashStatusLed();

// Network behavior
ArmorLink.sendCommand(
"Chest",
"BTN_L1",
"SINGLE_CLICK"
);
}

The local behavior remains normal firmware logic.

ArmorLink handles the network communication.

When to Use This Pattern

Use this pattern when:

  • A hand controller should control other modules
  • A hidden button should trigger a global effect
  • A Gateway should centralize button logic
  • Multiple modules should react to one event
  • You want to keep button mapping in one central place

Next Steps

Continue with: