Prove the LAN loop
What you are proving
Section titled “What you are proving”Two LAN behaviours, both required before Act 2:
- Closed loop — BOOT on a zone →
gg-edge/sensor→GgEdgeLoop→gg-edge/actuator/<thing>→ that zone’s RGB green on press, off on release. Other zones stay dark. - Telemetry — each board publishes chip temperature every 10 s on
gg-edge/telemetry/<thing>. The local loop does not subscribe to it; Act 2 archives, alarms, and trains on it.
| Topic | Who publishes | Who consumes on the LAN |
|---|---|---|
gg-edge/sensor | ESP32-S3 (BOOT press / release) |
|
gg-edge/actuator/<thing> | GgEdgeLoop | That zone’s firmware (RGB) |
gg-edge/telemetry/<thing> | ESP32-S3 (every 10 s) | Nobody on the core yet — prove it on serial; Act 2 adds consumers |
RGB colors in this lab: green = button loop (this page), blue = cloud
command (Act 2), red = edge model (Act 2). GgEdgeLoop 1.0.1 does not
send a color field; the firmware defaults to green.
Board: button and RGB
Section titled “Board: button and RGB”Use an ESP32-S3
Espressif ESP32-S3 — Wi‑Fi microcontroller used here as the Greengrass client device (not a second core). DevKitC-1 (or equivalent).
- BOOTRight side, below RST — press for sense
GPIO 0 → gg-edge/sensor - RGB (actuator)White square, lower-left. Turns green on press, off on release. GPIO 48 (v1.0 default) or 38 (v1.1).
WS2812 → gg-edge/actuator - USBBottom right USB-C — flash / serial (USB Serial/JTAG)
Success path
Section titled “Success path”- Nucleus
Greengrass Nucleus — the edge runtime on the core device. Installs components, talks to AWS, and hosts the local client-device stack. healthy; Auth
aws.greengrass.clientdevices.Auth — Greengrass component that decides which client device certificates may connect to the local MQTT broker., Moquette
aws.greengrass.clientdevices.mqtt.Moquette — local MQTT broker on the core. Not Mosquitto; client devices connect here over mTLS., Bridge, IPDetector
aws.greengrass.clientdevices.IPDetector — publishes the core's LAN address so discovery returns a reachable host for Moquette., Cli,com.example.GgEdgeLoopRUNNING (1.0.1). - Each zone’s serial shows discovery →
mqtt connected to core→ subscribe to its actuator topic → atelemetryJSON line every ~10 s. - Press BOOT on one board.
- NUC loop log shows sensor + actuator for that thing only.
- That board’s RGB turns green on press, off on release. The other zone stays dark.
- Optional: IoT Core
AWS IoT Core — cloud MQTT and device identity service. Client devices use it for discovery; the MQTT bridge forwards zone topics here, where IoT rules route them to other AWS services. MQTT test client ongg-edge/sensorandgg-edge/actuator/+(current bridge maps those). Telemetry is not bridged to IoT Core until Deploy from the cloud. - Optional second board: press its BOOT — only that board’s RGB responds.
1. Core and component
Section titled “1. Core and component”Core HEALTHY
Section titled “Core HEALTHY”aws greengrassv2 list-core-devices --status HEALTHY \ --query "coreDevices[?coreDeviceThingName=='${CORE_THING_NAME}'].[coreDeviceThingName,status]" \ --output textgg-edge-wt-dev-core HEALTHYGgEdgeLoop 1.0.1 RUNNING (on the NUC)
Section titled “GgEdgeLoop 1.0.1 RUNNING (on the NUC)”sudo /greengrass/v2/bin/greengrass-cli component list | grep -A2 GgEdgeLoopComponent Name: com.example.GgEdgeLoop Version: 1.0.1 State: RUNNING2. Telemetry on the zone
Section titled “2. Telemetry on the zone”idf.py -p /dev/ttyACM0 monitor (or your port). Skip pasting the discovery
JSON’s CA PEM into tickets — the host:port line is enough. Example logs use
192.0.2.10 for the NUC; your discovery address will be the core’s real LAN IP.
I (257) gg-edge: RGB strip on GPIO 48 — boot blinkI (1007) gg-edge: RGB -> offI (2217) gg-edge: chip temperature sensor ready: 28.9 CI (3017) gg-edge: wifi connectedI (4197) gg-edge: discovered core 192.0.2.10:8883I (4197) gg-edge: mqtt connected to coreI (4197) gg-edge: subscribed gg-edge/actuator/gg-edge-wt-dev-esp32-1I (13207) gg-edge: telemetry {"thing":"gg-edge-wt-dev-esp32-1","tempC":28.90,"rssi":-29,"uptimeS":13,"rgb":"off"} msg_id=0I (23207) gg-edge: telemetry {"thing":"gg-edge-wt-dev-esp32-1","tempC":28.90,"rssi":-29,"uptimeS":23,"rgb":"off"} msg_id=0Pass criteria:
chip temperature sensor readyonce at boot- a
telemetryJSON line about every 10 s thingmatches the board’s Thing nametempCis a few degrees above room temperature (die sensor, coarse steps)rgbis"off"when the LED is clear
Repeat on the second zone if you have one — expect a different baseline
tempC (for example ~28.9 °C vs ~26.5 °C on the bench).
3. Button → green RGB
Section titled “3. Button → green RGB”NUC — component log
Section titled “NUC — component log”sudo tail -f /greengrass/v2/logs/com.example.GgEdgeLoop.logPress and release BOOT on esp32-1:
2026-10-09T19:50:36.780Z [INFO] (Copier) com.example.GgEdgeLoop: stdout. INFO:GgEdgeLoop:sensor event: {"event":"press","thing":"gg-edge-wt-dev-esp32-1"}. {scriptName=services.com.example.GgEdgeLoop.lifecycle.Run, serviceName=com.example.GgEdgeLoop, currentState=RUNNING}2026-10-09T19:50:36.785Z [INFO] (Copier) com.example.GgEdgeLoop: stdout. INFO:GgEdgeLoop:published actuator command on gg-edge/actuator/gg-edge-wt-dev-esp32-1: {'state': 'on', 'source': 'com.example.GgEdgeLoop', 'target': 'gg-edge-wt-dev-esp32-1', 'echo': {'event': 'press', 'thing': 'gg-edge-wt-dev-esp32-1'}}. {scriptName=services.com.example.GgEdgeLoop.lifecycle.Run, serviceName=com.example.GgEdgeLoop, currentState=RUNNING}2026-10-09T19:50:36.928Z [INFO] (Copier) com.example.GgEdgeLoop: stdout. INFO:GgEdgeLoop:sensor event: {"event":"release","thing":"gg-edge-wt-dev-esp32-1"}. {scriptName=services.com.example.GgEdgeLoop.lifecycle.Run, serviceName=com.example.GgEdgeLoop, currentState=RUNNING}2026-10-09T19:50:36.931Z [INFO] (Copier) com.example.GgEdgeLoop: stdout. INFO:GgEdgeLoop:published actuator command on gg-edge/actuator/gg-edge-wt-dev-esp32-1: {'state': 'off', 'source': 'com.example.GgEdgeLoop', 'target': 'gg-edge-wt-dev-esp32-1', 'echo': {'event': 'release', 'thing': 'gg-edge-wt-dev-esp32-1'}}. {scriptName=services.com.example.GgEdgeLoop.lifecycle.Run, serviceName=com.example.GgEdgeLoop, currentState=RUNNING}Pass criteria in those lines:
thing/targetmatch the board you pressed- topic is
gg-edge/actuator/<that-thing>(not a baregg-edge/actuator) stateisonfor press andofffor release- no
colorfield yet (firmware still paints green)
ESP32-S3 — serial (same press)
Section titled “ESP32-S3 — serial (same press)”I (45102) gg-edge: published sensor event=press msg_id=12I (45118) gg-edge: actuator msg on gg-edge/actuator/gg-edge-wt-dev-esp32-1: {"state": "on", "source": "com.example.GgEdgeLoop", "target": "gg-edge-wt-dev-esp32-1", "echo": {"event": "press", "thing": "gg-edge-wt-dev-esp32-1"}}I (45120) gg-edge: RGB -> green (on)I (45340) gg-edge: published sensor event=release msg_id=13I (45355) gg-edge: actuator msg on gg-edge/actuator/gg-edge-wt-dev-esp32-1: {"state": "off", "source": "com.example.GgEdgeLoop", "target": "gg-edge-wt-dev-esp32-1", "echo": {"event": "release", "thing": "gg-edge-wt-dev-esp32-1"}}I (45356) gg-edge: RGB -> offThe next telemetry line should show "rgb":"off" again after release. While you
hold BOOT it may show "rgb":"green".
Do not paste device certs or private keys into tickets or docs.
Second zone (optional)
Section titled “Second zone (optional)”Press BOOT on gg-edge-wt-dev-esp32-2. NUC log should show that thing only:
INFO:GgEdgeLoop:sensor event: {"event":"press","thing":"gg-edge-wt-dev-esp32-2"}INFO:GgEdgeLoop:published actuator command on gg-edge/actuator/gg-edge-wt-dev-esp32-2: {'state': 'on', 'source': 'com.example.GgEdgeLoop', 'target': 'gg-edge-wt-dev-esp32-2', 'echo': {'event': 'press', 'thing': 'gg-edge-wt-dev-esp32-2'}}esp32-1 serial must not show an actuator message for that press.
Checklist
Section titled “Checklist”| Check | Pass? |
|---|---|
| |
| |
| Discovery JSON lists core host:8883 | |
Serial: | |
Serial: | |
| BOOT press publishes sensor event for that thing | |
Component log publishes to | |
Onboard RGB green on press, off on release (that board only) | |
| Other zone RGB stays off for that press | |
IoT Core sees |
So far the cloud may mirror sensor/actuator, but nothing consumes telemetry. Act 2 · Wire into AWS starts next: deploy the stack from S3 (adds telemetry bridge routes + LogManager), archive readings, keep zone state, raise an alarm, drive the RGB blue from a Lambda, and run a SageMaker-trained model on the core (red RGB).
Next: Architecture.