Charter 26 · read · reserve project

Turnstile Tally

Shared Count Display

Turn another device’s event stream into a resilient physical public tally.

Difficulty
★★☆
Prefix
tt
Zone
entrance
Type
tally
Device
tt-01
Build time
7 hours

Mission

Build this

Build a legible display for Gate Keeper’s newest count, with clear waiting, current, stale, and recovered states.

One kit, one team repository.

Borrowed parts are labelled below and have a fallback. The registered device ID is fixed; sensing and behaviour decisions remain yours.

Bill of materials

Parts

SourcePartFallback
● kitFour-digit TM1637 display—
● kitRGB LED and 220 Ω resistors ×3—
● kitPush button—

Disconnect USB before rewiring. Motors, the relay, and the servo need appropriate power and a shared ground. Never drive an actuator from the ESP32 3V3 pin.

Backup assignment · your invitation

Turn a distant event stream into a trustworthy public object

The Turnstile Tally does not count passages. Gate Keeper does. Your device receives that shared count, remembers what it knows about it, and makes freshness visible beside the number.

This sounds like a display project, but its real subject is distributed truth. What should the digits show before the first message arrives? What if Wi-Fi disappears? What if the source restarts at zero? A resilient reader distinguishes all of those stories.

The authority rule

Gate Keeper owns the count. Your button, display, restart, and recovery may acknowledge or present it, but they never alter the authoritative total.

Meet the idea

A number without its age is only half a message

MQTT delivers messages while devices are connected. After your tally boots, it may need to wait for Gate Keeper’s next event unless you deliberately and correctly preserve the last accepted count locally.

Store two pieces of information in memory: the newest accepted count and when it arrived. The digits answer “what was the value?” while the light answers “how much should I trust it now?”

A real zero, no value yet, and an old remembered zero are different states. Designing distinct outputs for them prevents a neat display from making a false claim.

Value

The newest valid cumulative count received from Gate Keeper.

Freshness

Time since that valid message arrived, compared with your written stale threshold.

Authority

The device allowed to create or change the underlying fact. Here, that is Gate Keeper.

Signal chainHow another device’s fact reaches the display
  1. in the worldA passage occursGate Keeper decides whether the distance story is one event.
  2. the partGate KeeperThe source increments its cumulative accepted count.
  3. electricalMQTT messageA count arrives now, later, twice, or not at all.
  4. in the codeValue + arrival timeThe tally validates and remembers both.
  5. on the spineDisplay statusDigits present the count; the tally publishes its own state.

The tally adds presentation and freshness, never a second competing count.

The lovely trick

Waiting, current, stale, and recovered are four different stories

Before the first valid count, dashes are more truthful than zero. While messages are recent, the display is current. After silence exceeds your threshold, the last value may remain visible only if the light clearly marks it stale.

Recovery deserves a brief state of its own. It tells a nearby viewer that the old number has just regained fresh evidence, especially if the source count changed or reset while disconnected.

Decision flowThe life of a shared count
  1. 01WaitingNo accepted count has arrived; show dashes or another non-number.
    then, first valid message,
  2. 02CurrentShow the newest count with the fresh colour.
    then, freshness expires,
  3. 03StaleKeep or hide the remembered value, but mark its age unmistakably.
    then, new valid message,
  4. 04RecoveredA new valid count arrived after staleness; reconcile before returning current.

Back to the start: After a short visible recovery, return to current and continue measuring age.

The display is a small state machine driven by message arrival and elapsed time.

A count can move backwards for a real reason.

Gate Keeper may restart or establish a new baseline. Do not silently add an offset to make the public number look continuous. Show a recovery or reset indication and preserve the source value exactly.

Wiring

Make four display states before subscribing to live data

Start with a local rehearsal: show waiting, current, stale, and recovered using fixed example values. Ask another person what each means. Only then connect the states to message arrivals and clocks.

The power rule: The reference TM1637 module uses 3V3. Each RGB channel needs its 220 Ω resistor. The button closes to ground and uses the ESP32 internal pull-up.

Bench referenceOpen the exact wiring map
WiringShared count display, freshness light, and local acknowledgement
ESP323V3TM1637 displayVCCGNDTM1637 displayGNDGPIO 18TM1637 displayCLKGPIO 19TM1637 displayDIOGPIO 25RGB LEDR via 220 ΩGPIO 26RGB LEDG via 220 ΩGPIO 27RGB LEDB via 220 ΩGNDRGB LEDcommon cathodeGPIO 14Push buttonone sideGNDPush buttonother side
ESP32 pinPartPart markingCarries
3V3TM1637 displayVCC3V3 power — verify the module pin order
GNDTM1637 displayGNDGround
GPIO 18TM1637 displayCLKDigital in/out
GPIO 19TM1637 displayDIODigital in/out
GPIO 25RGB LEDR via 220 ΩDigital in/out — common-cathode reference
GPIO 26RGB LEDG via 220 ΩDigital in/out
GPIO 27RGB LEDB via 220 ΩDigital in/out
GNDRGB LEDcommon cathodeGround
GPIO 14Push buttonone sideDigital in/out — configure INPUT_PULLUP; local acknowledgement only
GNDPush buttonother sideGround

Verify the TM1637 module pin order before power. A bare seven-segment display is not pin-compatible and needs appropriate current limiting and a verified driver circuit.

  • 3V3 power
  • Ground
  • Digital in/out

The button acknowledges a local message or explanation. It must never publish a replacement count or send a command that changes Gate Keeper.

Give it character

What should honesty look like from three metres away?

Digits may carry the exact value while colour carries trust. You can choose another redundant cue, but a visitor should never need colour vision alone to distinguish waiting from stale.

Your team decides:

  • How long may a count remain current after its last event message?
  • What appears before the first valid value: dashes, a word-like pattern, or a blank with a labelled light?
  • Does stale data remain visible, blink slowly, or disappear?
  • How are reset, overflow beyond four digits, malformed input, and recovery shown?

Write these decisions in plain language before turning them into code. A clear rule is easier to test, explain, and change.

Your field adventure

Can first-time viewers tell what the display really knows?

Test interpretation, not just wiring. Use a fixed rehearsal in which the digits sometimes show zero, sometimes show an old value, and sometimes have no value at all.

  1. Define the four outputs.

    Draw waiting, current, stale, and recovered before coding. Include a genuine current zero.

  2. Rehearse message history.

    Run cold boot, first message, several updates, planned silence, backward reset, overflow, and recovery.

  3. Invite five fresh viewers.

    Ask what the number means and whether it is current. Do not explain until each answer is recorded.

  4. Repair the hardest distinction.

    Change one label, light, blink, or digit pattern, then repeat that scene with new trials.

SceneDigitsFreshness cueViewer interpretationCorrect?Confusion / revision
no message yet_________yes / no___
current real zero0______yes / no___
remembered value is stale_________yes / no___

When it gets dramatic

A tidy number can hide a messy history

The display begins at zero after every boot

Zero is being used as a default before evidence arrives. Use an explicit waiting state and a separate has-value flag.

The tally never becomes stale

You may be updating the arrival clock inside the display loop. Change it only when a valid Gate Keeper message arrives.

The count jumps backward

The source probably reset or rebased. Preserve the received value, mark recovery or reset, and document the event rather than inventing continuity.

The same message makes the display flicker

MQTT delivery or reconnect may repeat a value. Re-render only when state changes, while still accepting the new arrival time if your rule permits.

Pressing the button changes the public total

The reader has accidentally become a second authority. Restrict the control to local acknowledgement, brightness, or help text.

Choose your direction

What kind of distributed-systems team will you become?

The freshness designers

Make age, staleness, and recovery understandable without hiding the last useful value.

The restart historians

Explore cold boot, local persistence, source reset, and the honest limits of continuity.

The public interpreters

Focus on zero, waiting, stale, and overflow through careful first-viewer trials.

Each direction is real engineering. Pick the question that keeps your team curious.

A calm way through the build

Collect four small wins

  1. tt-01 says hello and shows dashes.

    No source message means no invented count.

  2. A fixed example can visit all four display states.

    Test the visual language before MQTT.

  3. One Gate Keeper message becomes a current value.

    Store the value and its arrival time together.

  4. Planned silence becomes stale and a new message recovers.

    Add the viewer test after the state logic is frozen.

When a new step fails, return to the last small win. The fault is now somewhere in the few wires or lines you just added.

The garden handshake

Share what you found

These names are the rigid part of the project. They let another team find your work without knowing what you called the variables in your code.

When state changes

Tally operating state

garden/entrance/tally/tt-01/status

Unit: enum

Listen beyond your own device.

garden/entrance/counter/gk-01/count

Display the newest valid cumulative count exactly as Gate Keeper publishes it. Persist it locally or wait for a new event after boot; the device must not query or replay the browser API.

Finish line

Ready to introduce to the garden

  • tt-01 stays online and publishes its own waiting, current, stale, recovered, or error status.

  • The reject feed stays clear after the final code starts.

  • The tally reads Gate Keeper and never creates, offsets, or resets its authoritative count.

  • Waiting, real zero, stale memory, recovery, source reset, and overflow have documented behaviour.

  • Five first-time viewers are tested and the build log reports interpretation errors plus one revision.

  • The display and LED are safely current-limited, controls are local only, and the device label can be scanned.

The Turnstile Tally earns trust by showing not only a number, but the boundary between what it knows, remembers, and is still waiting to learn.

Backbone now

Live status

Updates from the same public event stream

Checking tt-01…