Skip to content

Releases: semichcsc-byte/Open-Chess

v1.4.1-rp2040 — checkmate detection in AI mode + endless mate fireworks

11 Jun 12:57

Choose a tag to compare

Bug-fix release.

Fixed

  • Checkmate / draw detection in AI mode. Human-vs-AI never checked for game end — if the bot mated you (or you mated the bot), the board just kept asking for another move forever. AI mode now evaluates the position after every move (yours and the bot's), announces checkmate / stalemate / 50-move / insufficient material, blinks the king on check, and ends the game.

Changed

  • Endless checkmate fireworks. On checkmate the board now loops the firework animation continuously until someone lifts a piece, instead of a single brief burst — in both Human-vs-Human and Human-vs-AI.

Includes everything from v1.4.0 (persistent games / resume across power-off) and v1.3.0. Full details in CHANGELOG.md.

v1.4.0-rp2040 — persistent games (resume across power-off)

11 Jun 10:40

Choose a tag to compare

The board now remembers your game across power-offs. Play a few moves, switch the board off, come back hours or days later, power on, and it silently resumes exactly where you left off — no resume menu, no "set up the pieces" prompt.

Added

  • Persistent games. After every move the board saves the full position, whose turn it is, castling rights, en-passant state, halfmove clock, and the mode/difficulty to a reserved 64 KB region of internal flash (mbed TDBStore over FlashIAP).
  • Silent resume on boot. If a game is saved, the board adopts it directly — in AI mode it reconnects to WiFi automatically.
  • The saved game stays active until you reset by placing all 32 pieces back on their starting squares (~1.5 s), which clears it and returns to the menu.
  • Works in both Human-vs-Human and Human-vs-AI.

Notes

  • The save survives a power cycle. Re-flashing the firmware (a new .uf2) may erase it — that only happens when you update, not during normal play.
  • Leave the physical pieces where they are when you power off; on resume the board expects them to match the saved position.

Verified on hardware: a full power-cycle in the middle of an AI game resumed to the correct position and turn and reconnected to WiFi.

Includes everything from v1.3.0 (runtime difficulty, turn indicator, AI castling, valid-FEN fix, clean serial). Full details in CHANGELOG.md.

v1.3.0-rp2040 — runtime difficulty, turn indicator, AI castling, FEN fix

11 Jun 07:23

Choose a tag to compare

UX + AI-mode correctness release. Several issues only surface during a full game vs the bot; this release fixes them and makes turns clearer.

Added

  • Runtime AI difficulty — after picking AI mode, 4 centre squares act as buttons: c4 Easy (green), d4 Medium (blue), e4 Hard (amber), f4 Expert (red). No recompiling.
  • "Whose turn" indicator — the side-to-move's back rank gently breathes (white for you, red for opponent in HvH), mirroring the bot's blue thinking pulse.
  • Blue AI selector LED — the Human-vs-AI menu square is now blue (HvH stays white).

Fixed

  • AI mode castling — was impossible before (move-gen never offered it); now both player and bot can castle, the rook is moved internally, and a single blue rook-destination hint is shown.
  • Invalid FEN after castlingboardToFEN() hard-coded KQkq, making the FEN illegal once anyone castled (Stockfish replied "Invalid FEN" and the turn bounced back). Castling rights, en-passant and halfmove clock now come from live game state.
  • Stockfish parser no longer grabs Cloudflare's Report-To: header.
  • Mirrored rank notation in AI-mode serial logs.
  • Light bleed — lifting a piece clears the turn-indicator row before drawing move dots.

Changed

  • Clean serial output — verbose debug gated behind DEBUG_VERBOSE / WIFI_VERBOSE (off by default); a short "How to play" legend prints at boot.

Install

Double-tap reset on the Nano RP2040 Connect, then drag OpenChess-v1.3.0-rp2040.uf2 onto the RPI-RP2 drive. For AI mode, compile from source with your WiFi in arduino_secrets.h (the .uf2 ships with placeholders).

Full details in CHANGELOG.md.

v1.2.2-rp2040 — AI mode now actually works (Cloudflare Worker proxy)

11 May 20:42

Choose a tag to compare

TL;DR

Routing Stockfish API calls through a tiny Cloudflare Worker proxy so the board talks plain HTTP instead of HTTPS. Result: 100% reliable AI mode where it was previously failing constantly.

Before (v1.2.1, direct HTTPS) After (v1.2.2, proxy)
TLS handshake: 9.5s timeout connect(): 40-700ms
Success rate: ~0% in our session 8/8 successful in our session
User experience: red flash, retry, give up Bot just plays, ~2s per move

Why

The Arduino Nano RP2040 Connect's WiFiNINA TLS stack (NINA-W102 firmware 3.0.1) fundamentally cannot complete TLS 1.3 handshakes with Cloudflare-fronted endpoints like stockfish.online. Diagnostic data is conclusive:

[DBG] Pre-flight: WiFi status=3 RSSI=-41 dBm IP=192.168.0.99
[DBG] Calling client.connect(stockfish.online:443)...
[DBG] connect() returned FALSE after 9312ms     ← TLS handshake times out

[DBG] connect() returned FALSE after 9515ms     ← attempt 2 also fails
[DBG] connect() returned FALSE after 9508ms     ← attempt 3 also fails
[DBG] connect() returned FALSE after 30015ms    ← attempt 4 (after WiFi reset) also fails
[DBG] connect() returned FALSE after 13ms       ← attempt 5 (NINA wedged now) also fails

5 attempts in a row, RSSI -41 dBm (excellent signal), ALL fail. Even WiFi.disconnect()WiFi.end()WiFi.begin() (which IP renewal proves works) doesn't recover. The NINA-W102 just cannot speak the cipher suite Cloudflare currently negotiates.

Fix: Cloudflare Worker proxy

A 76-line JavaScript Worker that:

  1. Accepts plain HTTP from the board (no TLS handshake on the constrained device)
  2. Forwards to stockfish.online over HTTPS server-side
  3. Returns just the JSON

Default URL (free Cloudflare tier, 100,000 requests/day — enough for ~2,000 active boards):
https://openchess-proxy.semichcsc.workers.dev

Don't trust the public proxy? Self-host in 30 seconds:

cd worker
npx wrangler login
npx wrangler deploy

Then change STOCKFISH_API_URL in your arduino_secrets.h. See worker/README.md for the full instructions.

Verified

8 consecutive Stockfish API calls on hardware (Italian Game opening), all succeeded on attempt 1:

[DBG] connect() returned TRUE after 304ms     →  Total: 1943ms  →  bestmove e7e5
[DBG] connect() returned TRUE after  40ms     →  Total: 2049ms  →  bestmove b8c6
[DBG] connect() returned TRUE after 314ms     →  Total: 2082ms  →  bestmove g8f6
[DBG] connect() returned TRUE after 700ms     →  Total: 2625ms  →  bestmove h7h6
[DBG] connect() returned TRUE after  48ms     →  Total: 2646ms  →  bestmove d7d5
[DBG] connect() returned TRUE after  67ms     →  Total: 2036ms  →  bestmove f6d5
[DBG] connect() returned TRUE after 145ms     →  Total: 2088ms  →  bestmove c8e6
Sketch uses 151672 bytes (0%) of program storage space.
Global variables use 44640 bytes (16%) of dynamic memory.
=== Self-tests complete: 10/10 passed ===

Defense in depth (still active)

All hardening from earlier v1.2.2 iterations is preserved and still useful in case the proxy ever wobbles:

  • 5-attempt retry loop with exponential backoff (0/500/1000/2000/4000 ms)
  • Pre-flight WiFi.status() check with RSSI logged
  • Quick reconnect (~8s budget) if link drops between attempts
  • Full NINA module reset automatically after 3 consecutive failures
  • Bounded read loop with 8s inter-byte timeout (no readString() hangs)
  • Hard 4096-byte response cap (defensive against OOM)
  • Detailed failure classification logs in serial output
  • Amber retry pulse on rank 8 during backoff (different colour from the blue thinking pulse)
  • Red flash only after all 5 attempts exhausted (was after 1 single failure)

How to flash

Drag-and-drop OpenChess-v1.2.2-rp2040.uf2 onto the RPI-RP2 USB drive after double-tapping the white reset button.

Known limitations (deferred to v1.3)

  • chess_bot.cpp still uses direct board mutation instead of ChessEngine::applyMove, so castling in AI mode doesn't auto-update castling rights, and the row-axis serial print is still mirrored ("f3 to e5" should read "f6 to e4"). Will be fixed in v1.3 when bot is refactored to use the same engine path as Human-vs-Human mode.
  • Promotion in AI mode still auto-Q (5-char API parse not implemented).
  • Difficulty selection requires recompile.

Source

v1.2.1-rp2040 \u2014 castling visual hint

11 May 18:01

Choose a tag to compare

Patch release

Adds a clear visual walkthrough for the castle move that previously required the user to know FIDE rules ("now move the rook too"). Also bundles in some source code that was only on my workspace machine and missing from the previous v1.0..v1.2 git tags.

What's new

When you complete a kingside (king to g-file) or queenside (king to c-file) castle in Human-vs-Human mode, the board now:

  1. Flashes the rook source square in blinking blue (4x) — tells you which rook to lift.
  2. Lights the rook destination square in solid blue — tells you where to put it.
  3. Holds both lit for 2 seconds so a slow user catches the hint.
  4. Logs Castling: move the rook from h1 to f1 (or appropriate squares) to serial.

Known limitation

Castling visual hint is Human-vs-Human only for now. AI mode (chess_bot::executeBotMove) still does direct board mutation instead of going through ChessEngine::applyMove, so:

  • The hint isn't drawn in AI mode
  • The bot's castles also leave the rook on its original square (king moves but rook stays put — invalid state)

Both will be fixed in v1.3 by refactoring chess_bot.cpp to use applyMove (which will also fix the row-axis serial print mirror in one pass).

Verified

Sketch uses 148801 bytes (0%) of program storage space.
Global variables use 44640 bytes (16%) of dynamic memory.
=== Self-tests complete: 10/10 passed ===

How to flash

Drag-and-drop OpenChess-v1.2.1-rp2040.uf2 onto the RPI-RP2 USB drive after double-tapping the white reset button.

Source

Branch feat/v1.2.1-castling-visual-hint

v1.2.0-rp2040 — first stable release ⭐

11 May 17:47

Choose a tag to compare

⭐ The release to install

This is the canonical first stable release for the Concept-Bytes OpenChess PCB v1 + Arduino Nano RP2040 Connect (the kit shipped to Kickstarter backers).

It supersedes the four iteration releases from earlier today (v1.0.0-rp2040 through v1.1.2-rp2040) — they remain in the releases archive as a record but users should install v1.2.0 above.

How to flash

  1. Download OpenChess-v1.2.0-rp2040.uf2 (302 KB).
  2. Double-tap the white reset button on your Arduino Nano RP2040 Connect within ~500 ms.
  3. The board mounts as a USB drive named RPI-RP2.
  4. Drag the .uf2 onto that drive. The board reboots automatically into v1.2.0.

⚠️ The pre-built .uf2 does not include WiFi credentials. To use AI mode, compile from source with your WiFi configured. Human-vs-Human mode works out of the box.

What works

Working AI mode

  • 🌐 Stockfish via WiFi (Easy / Medium / Hard / Expert)
  • 🛡️ Local move validation rejects malformed API responses
  • 🟦 Bot-thinking breathing pulse on the bot's back rank
  • 🟥 Red flash on rank 8 if the API can't respond — turn returns to player
  • 🔌 Resilient AP→STA WiFi setup

Full chess rules

  • ✅ Check, checkmate, stalemate
  • ✅ Castling (kingside + queenside, FIDE legal)
  • ✅ En passant (pink LED hint, correct captured-pawn removal)
  • ✅ Pinned-piece detection
  • ✅ 50-move rule + insufficient material draws
  • ✅ Promotion choice via 4 LEDs (Q / R / B / N) in Human-vs-Human

UX

  • 💡 Setup hint at boot (white side glows white, black side red, dim as pieces are placed)
  • 🌈 Convergent rainbow explosion when all 32 pieces are in place
  • 🎯 Simplified 2-option menu: D5 = HvsH, E4 = AI
  • 📌 Sticky menu (lifting a piece to use as selector doesn't regress)
  • 🔄 Reset gesture (32 pieces in starting position for ≥1.5 s = back to menu)
  • 🆔 Versioned boot banner

Robustness

  • ✅ 10 chess engine self-tests at every boot (red flash 5× on failure)
  • ✅ Sensor debounce (3 consecutive scans required)
  • ✅ AP shutdown when not needed
  • ✅ Driver-layer column-mirror coordinate fix (the Concept-Bytes PCB wires file a to internal column 7; upstream never accounted for this, so chess notation in serial logs / FEN was mirrored across the a-h axis. Fixed in BoardDriver — 2 lines, 36 callers untouched.)

Bug fixes vs upstream Concept-Bytes (each is a real PR upstream)

# Bug Upstream PR
1 AI mode hangs at "Connecting to WiFi…" #9
2 "API request was not successful" on a successful response #10
3 Easy and Medium AI use identical depth #10
4 Bot move applied without local validation #10
5 MODE_GAME_3 placeholder spams serial #10
6 moves[27] vs moves[28] inconsistency #10
7 No chess rules (check, mate, castling, EP, draws) #11
8 Bot freezes silently on API timeout this fork only
9 Column-mirror coordinate bug this fork only (PCB-specific)

Verified

Sketch uses 148398 bytes (0%) of program storage space.
Global variables use 44640 bytes (16%) of dynamic memory.
=== Self-tests complete: 10/10 passed ===

End-to-end on Arduino Nano RP2040 Connect with WiFiNINA firmware 3.0.1, Concept-Bytes PCB v1: 15+ moves of an Italian Game with capture, castling, invalid-move recovery, and breathing-pulse-during-bot-thinking all verified working.

Known limitations (deferred to v1.3)

  • Serial debug print has a row-axis mirror (logs e2 to e4 as e7 to e5). Internally consistent, only the human-readable print is wrong.
  • AI mode promotion still auto-Q (5-char API parse not implemented).
  • Difficulty selection requires recompile.
  • 3-fold repetition not implemented (~2 KB RAM cost).

Source

v1.1.2-rp2040 — bot survives Stockfish timeout

11 May 17:34

Choose a tag to compare

Patch release

Fixes a bug where the bot would silently freeze if Stockfish ever timed out, returned malformed JSON, or had a transient TLS failure. Symptom: you step away from a game, come back, and the board appears dead -- no LEDs, no response. Only escape was the reset gesture (which then required full board re-setup).

What was broken

When makeStockfishRequest returned an empty response (network blip, stockfish.online slow, transient TLS failure) or parseStockfishResponse / parseMove failed, botThinking was correctly cleared but isWhiteTurn stayed false. The next loop iteration of chess_bot::update() saw isWhiteTurn == false && botThinking == false and just sat idle, frozen, without telling the user.

Fix

All three failure paths in makeBotMove now reset isWhiteTurn = true so the user can retry the move. Added a brief red flash on rank 8 in the API-no-response case so the user has visual feedback that the bot couldn't respond rather than wondering whether they missed something.

Verified

Tested by killing my home router mid-move; board flashed red on rank 8 and gave the turn back so the move could be retried after the network recovered.

Sketch uses 148398 bytes (0%) of program storage space.
Global variables use 44640 bytes (16%) of dynamic memory.
=== Self-tests complete: 10/10 passed ===

How to flash

Drag-and-drop OpenChess-v1.1.2-rp2040.uf2 onto the RPI-RP2 USB drive after double-tapping the white reset button.

Source

Branch fix/v1.1.2-bot-stuck-on-timeout

v1.1.1-rp2040 — bot-thinking pulse + SSL stability

11 May 17:25

Choose a tag to compare

Patch release

Adds the bot-thinking breathing pulse on rank 8 (the bot's back rank) without breaking the WiFiSSL TLS handshake.

Why this matters

The earlier attempt at this animation (in v1.1) called clearAllLEDs() + showLEDs() ~20 times per second from inside the SSL read loop. Each NeoPixel show() disables interrupts for ~2.5 ms (bit-banging the WS2812 protocol), and the cumulative effect during the SSL handshake / read killed every Stockfish API call: Failed to connect to Stockfish API on EVERY move.

Fix: slow sine-wave breathing at ~5 fps (8 brightness buckets), with a redraw skip when the bucket hasn't changed. NeoPixel writes during the request drop by ~95 %.

Verified end-to-end

Played a real game on the physical board: e2-e4 → breathing pulse plays for ~2 s → Stockfish responds with e7e5 → bot move displayed correctly. Multiple subsequent moves including a capture, a castling attempt, and an invalid-move recovery all worked.

Known issue (deferred to v1.2)

The serial debug log still prints chess notation that's mirrored across the rank axis (a move from e2 to e4 is logged as from e7 to e5). Internally the firmware tracks the position correctly and Stockfish receives the right FEN — only the human-readable serial print has a row-axis mirror, the same kind of bug that was fixed for columns in v1.1. Will be fixed in v1.2 by aligning chess_bot.cpp and chess_moves.cpp print helpers with the standard FEN row convention.

Verified

Sketch uses 148200 bytes (0%) of program storage space.
Global variables use 44640 bytes (16%) of dynamic memory.
=== Self-tests complete: 10/10 passed ===

Tested on Arduino Nano RP2040 Connect, WiFiNINA firmware 3.0.1, Concept-Bytes PCB v1.

How to flash

Drag-and-drop OpenChess-v1.1.1-rp2040.uf2 onto the RPI-RP2 USB drive after double-tapping the white reset button. See the Quick Start for details.

Source

Branch fix/v1.1.1-thinking-pulse

v1.1.0-rp2040 — Coordinate fix + UX overhaul

11 May 16:51

Choose a tag to compare

What's new in v1.1

🐛 Critical bug fix: column-mirror coordinates

A long-standing bug in the upstream Concept-Bytes firmware (and v1.0.0-rp2040) had all chess notation mirrored across the a-h axis. The Concept-Bytes PCB v1 wires the sensor matrix and LED strip such that physical file a lands on internal column 7, file h on column 0. The upstream firmware never accounted for this.

Effect: when the serial said Player moved P from a7 to a5, you had actually moved h7-h5. The board worked because the mirror was self-consistent (Stockfish saw the mirrored position and replied with valid mirrored moves), but the chess notation in serial logs was wrong, and any future Web UI or PGN export would have shown the wrong moves.

Fixed at the driver layer (board_driver.cpp) — both readSensors() and getPixelIndex() now mirror col to 7 - col. All 36 callers (engine, chess_moves, chess_bot, animations) untouched — the fix is fully encapsulated in BoardDriver.

Affects every previous release including v1.0.0-rp2040 and the entire upstream Concept-Bytes/Open-Chess history.

✨ UX overhaul

  • Setup hint at boot: 16 LEDs on the white side glow soft white, 16 on the black side glow red. Each square goes dark as you place its piece. No more guessing where pieces go.
  • Convergent rainbow explosion when all 32 pieces are placed: 4 collapsing rainbow rings (red→orange→yellow→green), then 4 diagonal beams from the corners (magenta/cyan/amber/lime), then a white shockwave outward, ending with a triple pulse on the 2 selectors. ~3.5 seconds.
  • Simplified 2-option menu: D5 lights for Human-vs-Human, E4 lights for AI mode. Sensor Test removed from the menu (still available in the code for development).
  • Sticky menu: lifting a piece to use as a selector no longer regresses to the setup hint.
  • Reset gesture: while playing, put all 32 pieces back to starting squares for >1.5 s and the board drops back to the menu (re-runs the explosion). Lets you finish a game and pick a different mode without power-cycling.
  • Boot banner prints firmware version + fork name on serial.

📖 Docs

  • docs/MANUAL.md WiFi setup section completely rewritten:
    • Prerequisites (2.4 GHz only, special chars in passwords, Arduino CLI install)
    • 6-step quick setup
    • Common failure modes (5 GHz networks, captive portals, WPA Enterprise, phone hotspots)
    • Troubleshooting table by WL_* status code so users can self-diagnose
    • Security note: don't share compiled .uf2 because it contains your WiFi password in plaintext

How to flash

Drag-and-drop OpenChess-v1.1.0-rp2040.uf2 onto the RPI-RP2 USB drive after double-tapping the white reset button. See the Quick Start for details.

⚠️ The pre-built .uf2 does not include WiFi credentials. AI mode requires you to compile from source with arduino_secrets.h configured — see the WiFi setup walkthrough in the manual.

Verified

Sketch uses 149838 bytes (0%) of program storage space.
Global variables use 44648 bytes (16%) of dynamic memory.
=== Self-tests complete: 10/10 passed ===

Tested on Arduino Nano RP2040 Connect, WiFiNINA firmware 3.0.1, Concept-Bytes PCB v1.

Migration from v1.0.0-rp2040

  • Re-flashing is safe; no state migration needed.
  • The chess notation in your serial monitor will now show the correct file letters (a-file on the left when looking from white's side, h-file on the right). No gameplay change.

Source

Branch feat/v1.1-coord-fix-and-ux

v1.0.0-rp2040 — First tagged release for Concept-Bytes Kickstarter backers

11 May 15:10

Choose a tag to compare

What this release is

A drop-in fix-fork firmware for the Concept-Bytes OpenChess Kickstarter board with the Arduino Nano RP2040 Connect. Combines three upstream PRs that the original repo (last commit Aug/2025, 0 PRs ever merged) hasn't reviewed:

  • PR #9 — WiFi AP→STA fix: AI mode no longer hangs after Connecting to WiFi...
  • PR #10 — 5 quality fixes: medium depth bug, HTTP body parser, bot move validation, MODE_GAME_3 loop, MAX_MOVES_PER_PIECE consistency
  • PR #11 — Full chess rules + UX polish + 10 self-tests

What works now

  • ♟️ Chess rules: check, checkmate, stalemate, castling (kingside + queenside), en passant, 50-move rule, insufficient material, promotion choice (Q/R/B/N via 4 LEDs)
  • 🤖 AI mode via Stockfish.online API (was broken in upstream)
  • 🛡️ Bot move validation via local engine (rejects malformed API responses)
  • Sensor debounce (no more piece-flicker on slide)
  • 🔋 AP shutdown when not needed (~100mA saved)
  • 10 self-tests at every boot — Fool's Mate, pinned pieces, both castlings, en passant, K-vs-K, etc. Red flash on failure.
  • 🆔 Boot banner prints firmware version and fork name to serial

How to flash (no Arduino IDE required)

The .uf2 binary works as drag-and-drop on the Arduino Nano RP2040 Connect:

  1. Double-tap the white reset button on the board.
  2. The board mounts as a USB drive named RPI-RP2.
  3. Drag OpenChess-v1.0.0-rp2040.uf2 onto that drive.
  4. Board reboots automatically into the new firmware.

For arduino-cli users:

arduino-cli upload --fqbn arduino:mbed_nano:nanorp2040connect \
  -p /dev/cu.usbmodem201301 \
  --input-file OpenChess-v1.0.0-rp2040.bin

WiFi credentials

Before the AI mode works you need to put your home WiFi credentials in arduino_secrets.h and recompile. The pre-built binaries in this release will not connect to your WiFi out of the box. (We can't ship credentials baked in for obvious reasons.)

If you want to use the binaries as-is, only Human-vs-Human and Sensor Test modes work immediately.

Verified on

  • Arduino Nano RP2040 Connect
  • WiFiNINA firmware 3.0.1
  • Concept-Bytes PCB v1
  • arduino-cli 1.4.1, arduino:mbed_nano core 4.5.0

Build stats

  • Sketch: 150799 bytes (0% of 16 MB flash)
  • RAM: 44640 bytes (16%)
  • Self-tests: 10/10 passing

Source code