// flowchart
flowchart TD
A([START]) --> B[Serial.begin 115200]
B --> C[initWiFi\nWiFi.begin SSID + password]
C --> C1{WiFi\nconnected?}
C1 -- No --> C2[Wait 500 ms] --> C1
C1 -- Yes --> D[initMQTTbroker\nsetServer + setCallback]
D --> E[Wire.begin SDA SCL]
E --> F[Reset OLED via GPIO16]
F --> G{display.begin\nSSD1306 OK?}
G -- No --> G1[Print error\nhalt forever]
G -- Yes --> H[Show Escape Room!\non OLED — 1.5 s]
H --> I[irrecv.enableIRIn]
I --> J[pinMode BUZZER OUTPUT\nanalogWriteRange 255]
J --> LOOP
subgraph LOOP [" loop() "]
L1{MQTT\nconnected?} -- No --> L2[mqttConnect]
L2 --> L2a{Connect OK?}
L2a -- Yes --> L2b[Publish hello\nSubscribe EscapeGame/Correct]
L2a -- No --> L2c[Wait 5 s] --> L2
L2b --> L3
L1 -- Yes --> L3[mqttClient.loop]
L3 --> L4[updateBuzzer\nadvance melody non-blocking]
L4 --> L5{waitingForServer?}
L5 -- Yes --> L_disp[updateDisplay\nyield] --> L1
L5 -- No --> L6{IR signal\nreceived?}
L6 -- No --> L_disp
L6 -- Yes --> L7[Read code\nirrecv.resume]
L7 --> L8{code valid?\nnot 0 / 0xFFFFFFFF}
L8 -- No --> L_disp
L8 -- Yes --> L9[irCodeToDigit\nlook up in IR_CODES array]
L9 --> L10{Digit\nrecognised?}
L10 -- No --> L11[Print unknown code] --> L_disp
L10 -- Yes --> L12{enteredCount\n< 4?}
L12 -- No --> L_disp
L12 -- Yes --> L13[Store digit\nenteredCount++\nupdateDisplay]
L13 --> L14{enteredCount\n== 4?}
L14 -- No --> L_disp
L14 -- Yes --> L15[waitingForServer = true\nDelay 300 ms]
L15 --> L16[Build payload\n d0 d1 d2 d3]
L16 --> L17[Publish payload\nto EscapeGame/Code]
L17 --> L_disp
end
subgraph CALLBACK [" callback() — triggered by incoming MQTT "]
CB1[Receive topic + message] --> CB2{Topic ==\nEscapeGame/Correct?}
CB2 -- No --> CB_END([Return])
CB2 -- Yes --> CB3[waitingForServer = false]
CB3 --> CB4{Message\nvalue?}
CB4 -- 1 correct --> CB5[startMelody correctNotes\nDelay 3 s\nenteredCount = 0]
CB4 -- 0 wrong --> CB6[startMelody wrongNotes\nenteredCount = 0]
CB5 & CB6 --> CB_END
end
subgraph BUZZER [" updateBuzzer() — non-blocking melody "]
UB1{currentMelody\n== nullptr?} -- Yes --> UB_END([Return])
UB1 -- No --> UB2{Note duration\nelapsed?}
UB2 -- No --> UB_END
UB2 -- Yes --> UB3[melodyIndex++]
UB3 --> UB4{End of\nmelody?}
UB4 -- Yes --> UB5[stopTone\ncurrentMelody = nullptr] --> UB_END
UB4 -- No --> UB6[noteStartTime = millis\nplayTone next note] --> UB_END
end