Live crossing

Ion4 Smart Crossing

Adam Tas Corridor crossing, Stellenbosch · live from device crossing-01
Cloud broker: connecting Device: waiting City link: unknown

The crossing

LEFT
Waiting
Mode--
Train--
Railway gate--
Car at barrier--
Car barrier--
Trains / cars counted--
RIGHT

People crossing

Waiting now--nobody waiting
Average wait--sent to the city as wait_s
Last wait--press to red
Crossings served---- button presses

Environment

Road temperature----
Gas / smoke----
Soil moisture----
Daylight--lamp --

Live map

Where people are around the crossing, live. A person inside the crossing zone while the robots show blue (cars go), or on the railway while a train is coming, is logged as an infraction. Free map (OpenStreetMap), no API key. Locations are shared only when a person presses "Share my location".

Open this page on a phone and press "Share my location" to appear on every screen.

Zones

Crossing zone (30 m): on the road and the railway
Approach zone (120 m): about to cross
You  Others  Simulated

People now 0

Nobody is sharing a location yet.

Infractions 0

None so far.

Controls

Gates move from here only through the hardware tests below, which run in maintenance mode and are refused while a train is on the crossing. A remote command can never lift a barrier onto a train.

Event log

Ask the crossing

AI assistant (Gemini 3.8 Flash). It sees the live crossing data with every question.

Hi, I'm the Ion4 crossing assistant. Ask me about the trains, the wait times, the environment or how the system works.

Email alerts

Send an email when something needs attention
  • Fire or gas emergency at the crossing
  • Flooded path or ice risk on the road
  • Train on the crossing for more than 60 s
  • Device offline for more than 60 s

Each alert type sends at most once every 10 minutes. Alerts go out from this page, so keep it open on one laptop during the demo. Preview data never sends email.

Hardware test

tests locked Tests run only in maintenance mode, so the crossing is out of service while you test.

Robots (both lanes)

Lights

Buzzer

Railway gate

Car barrier

Whole crossing

Each test lasts 3 seconds (the up-and-down tests and the train drill 6 s). Gates moved by a test go back to automatic after 30 seconds. Device reply: --

Takes about 90 s. Stand by the device and watch and listen.

Boot self-test

no results yet Runs on its own after every reset: 5 s per part, the Serial Monitor says what to do.
PartResultDetail
Reset the ESP32, or press "Run self-test again" in maintenance mode.

Inputs: check each one on the real device

PartReading nowHow to check itResult
DS18B20 temperature--Hold the probe in your hand, it should rise--
MQ-5 gas--Unlit lighter gas near it, the value jumps--
Soil moisture--Dip the probe in water, it rises--
LDR light--Cover it with your hand, it drops--
Ultrasonic 1 (train)--Hand in front, distance changes; under 10 cm = train--
Button 1 pedestrian--Press it on the device--
Button 2 railway gate--Press it on the device--
Button 3 car barrier--Press it on the device--
Button 4 street lamp--Press it on the device--
WiFi signal--Better than -75 dBm is solid--
City mainframe link--Needs CITY_HOST in config.h--

Pin connections

ESP32 Dev Board 30-pin (CP2102), labels as printed on the board. Buttons use the internal pull-up: one leg to the pin, the opposite leg to GND. Every LED has its own resistor.

PinPartWiringExtra part
Traffic robots (left and right lane share pins)
D25RED, both robotsD25 → 220Ω → LED → GND, twice2 × 220Ω
D26ORANGE, both robotsD26 → 220Ω → LED → GND, twice2 × 220Ω
D33BLUE, both robotsD33 → 100Ω → LED → GND, twice2 × 100Ω
Push buttons
D13Button 1, pedestrianD13 ↔ button ↔ GNDnone
D18Button 2, railway gateD18 ↔ button ↔ GNDnone
D19Button 3, car barrier (hold 3 s = emergency)D19 ↔ button ↔ GNDnone
D21Button 4, street lamp (hold 3 s = maintenance)D21 ↔ button ↔ GNDnone
Train sensor and gates
D27Ultrasonic 1 TRIG (train)directnone
VNUltrasonic 1 ECHO (train)ECHO → 1kΩ → VN → 2.2kΩ → GND1kΩ + 2.2kΩ
RX2Servo, car barrierorange → RX2, red → breadboard 5V rail, brown → GNDnone
TX2Servo, railway gateorange → TX2, red → breadboard 5V rail, brown → GNDnone
Environment
D4DS18B20 temperatureyellow → D4, red → 3V3, black → GND, 4.7kΩ D4 to 3V34.7kΩ
D34MQ-5 gasAO → 10kΩ → D34 → 10kΩ → GND, VCC → breadboard 5V rail2 × 10kΩ
D35Soil moistureAO → D35, VCC → 3V3, GND → GNDnone
D32LDR light sensor3V3 → LDR → D32 → 10kΩ → GND10kΩ
D22Street lamp LEDD22 → 220Ω → LED → GND220Ω
D23Buzzer TMB12A03 (active, 3 V)D23 → 1kΩ → BC548 base; buzzer + → 3V3, buzzer − → collector; emitter → GNDBC548 (or BC547) + 1kΩ
D2Status LEDonboard, nothing to wirenone
Power
3V33.3V railDS18B20, soil moisture, LDR, buzzer
5V railBreadboard power supply, jumper on 5V9V battery clip → its barrel jack; 5V rail → both servos, MQ-5 VCC, ultrasonic VCCsupply module
USBESP32 powerlaptop USB powers the ESP32; do NOT also link VIN to the 5V rail
GNDCommon groundESP32 GND → breadboard GND rail: the only wire between the two supplies
VINRun without the laptopunplug USB first, then VIN → breadboard 5V rail
Reserved / free
D14, VPUltrasonic 2 (car), not fittedTRIG → D14, ECHO → 1kΩ → VP → 2.2kΩ → GND; set USE_CAR_SENSOR true1kΩ + 2.2kΩ
D5, D12, D15Boot pins, left freedo not use

Device console

Live log from the ESP32 (the same lines it prints on the Serial Monitor), plus what this website does. Everything is also written to the browser console (F12).

Waiting for the device. Lines appear here as soon as the ESP32 is on WiFi.

Serial Monitor commands (115200 baud, type a letter then Enter)

hlist the commands
pfull status line now
vraw sensor values
nmenormal, maintenance, emergency
1to4act as buttons 1 to 4
trun the boot self-test again
sskip the rest of a self-test

About Ion4 Smart Crossing

A safer, smarter level crossing for the Adam Tas Corridor in Stellenbosch, where the R44 and the railway line split communities. One small device runs the robots, the gates and the street light, watches the road conditions, and tells the city how long people wait to cross.

HenockNathanKipabiKilonga

Team Ion4 (team ID qsoju) · Hack the City by Octoco, October 2026 · Challenge: Getting Around, moving people across the divide

The problem

People walking between Kayamandi, the town and the university cross busy roads and the railway with long, unpredictable waits. Planners have little data on where people wait and where they bottleneck.

What the crossing does

  • Two robots (left and right lane) run red, red + orange, blue, orange in sync.
  • A pedestrian button cuts the cars' blue short, and the wait is measured.
  • An ultrasonic sensor sees the train: bell, red robots, railway gate and car barrier down.
  • Road temperature (ice, heat, fire), gas and smoke, and flooding are watched all the time.
  • The street light turns on by itself at night.

Three modes

  • Normal: the robot cycle with the walk chirp.
  • Maintenance: flashing orange; hardware tests allowed.
  • Emergency: flashing red and a siren, barrier down, railway gate open so people can leave, street light on.

Hardware

ESP32 (30-pin), 6 LEDs on 3 pins, 2 SG90 servos, HC-SR04 ultrasonic, DS18B20, MQ-5, soil moisture probe, LDR, buzzer, 4 push buttons, and a breadboard power supply for the 5 V parts. After every reset the device tests each part for 5 s.

Software and data

Firmware in Arduino C++ on two cores: control on one, WiFi and MQTT on the other. Every 30 s it sends uptime, average wait, road temperature and gas level to the Octoco city mainframe, with an HTTP fallback. Its status is retained, with a last will so the city knows when it goes offline. This website gets the full state over HiveMQ Cloud, with an AI assistant and email alerts.

Why it matters

Every press of the button becomes a data point: where people wait, for how long, and at what time of day. That is the evidence the corridor planners need to place crossings, change timings and make the case for funding.

Cloud broker

Brokereeb1e83a06da4b44b7a340bc19cd1e75.s1.eu.hivemq.cloud (HiveMQ Cloud)
Device port8883 MQTT over TLS
Website port8884 MQTT over secure WebSocket, path /mqtt
State topicion4/crossing/state, full JSON every 5 s
Command topicion4/crossing/cmd, for example {"cmd":"mode","val":"maintenance"}, {"cmd":"test","val":"train_drill"}, {"cmd":"self_test","val":"run"}
People topicion4/crossing/people, phone positions from the Live map: {"id","name","lat","lng","acc"}
Log topicion4/crossing/log, one line of text per device event (the Device console page)
City mainframehack/qsoju/crossing-01/telemetry every 30 s and hack/qsoju/crossing-01/status (retained), on the Octoco broker