diff --git a/backend/Dockerfile b/backend/Dockerfile index 72918976..0725ed5a 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -22,15 +22,19 @@ ENV WASI_SDK=/opt/wasi-sdk # Initialize arduino-cli and install cores. # - arduino:avr → Uno / Nano / Mega / etc. (built-in core, always needed) -# - ATTinyCore:avr → ATtiny85 (Spence Konde's third-party core, drazzy.com index) -# Without this the FQBN ATTinyCore:avr:attinyx5:chip=85,clock=internal16mhz -# fails with "Platform 'ATTinyCore:avr' not found: platform not installed". +# - ATTinyCore:avr@1.4.1 → ATtiny85 (Spence Konde's third-party core, +# drazzy.com index). Pinned to 1.4.1 because >=1.5.0 depends on +# micronucleus hosted at azduino.com (frequently unreachable). 1.4.1's +# micronucleus tool comes from github.com/digistump and still supports +# the FQBN clock options we ship (clock=16pll, etc.). We never invoke +# micronucleus — it is only required for USB upload, not compilation — +# but arduino-cli will not install a core whose tool deps cannot fetch. RUN arduino-cli config init \ && arduino-cli config add board_manager.additional_urls \ http://drazzy.com/package_drazzy.com_index.json \ && arduino-cli core update-index \ && arduino-cli core install arduino:avr \ - && arduino-cli core install ATTinyCore:avr + && arduino-cli core install ATTinyCore:avr@1.4.1 WORKDIR /app diff --git a/backend/app/services/arduino_cli.py b/backend/app/services/arduino_cli.py index 9446cda5..b2de06a5 100644 --- a/backend/app/services/arduino_cli.py +++ b/backend/app/services/arduino_cli.py @@ -30,6 +30,17 @@ class ArduinoCLIService: "esp32": "esp32:esp32", } + # Version pins for `arduino-cli core install`. Keyed by core ID; if a core + # is in this map we pass `@` instead of just ``. + # ATTinyCore: >=1.5.0 depends on micronucleus hosted at azduino.com, which + # has been unreachable for extended periods. 1.4.1 is the last release + # whose micronucleus tool is on github.com (digistump release) AND still + # supports the FQBN options we use (clock=16pll, etc.). Compile-only — + # micronucleus itself is never invoked here. + CORE_INSTALL_VERSIONS: dict[str, str] = { + "ATTinyCore:avr": "1.4.1", + } + def __init__(self, cli_path: str = "arduino-cli"): self.cli_path = cli_path self._ensure_board_urls() @@ -147,12 +158,14 @@ class ArduinoCLIService: if self._is_core_installed(core_id): return {"needed": False, "installed": True, "core_id": core_id, "log": ""} - # Install the core - print(f"[arduino-cli] Auto-installing core {core_id} for board {fqbn}...") + # Install the core (optionally pinned to a specific version) + version = self.CORE_INSTALL_VERSIONS.get(core_id) + install_spec = f"{core_id}@{version}" if version else core_id + print(f"[arduino-cli] Auto-installing core {install_spec} for board {fqbn}...") def _install(): return subprocess.run( - [self.cli_path, "core", "install", core_id], + [self.cli_path, "core", "install", install_spec], capture_output=True, text=True ) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index cecac073..bc9b2690 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -35,7 +35,7 @@ fi arduino-cli core update-index 2>/dev/null || true arduino-cli core install arduino:avr 2>/dev/null || true arduino-cli core install rp2040:rp2040 2>/dev/null || true -arduino-cli core install ATTinyCore:avr 2>/dev/null || true +arduino-cli core install ATTinyCore:avr@1.4.1 2>/dev/null || true # ESP32 compilation now uses ESP-IDF instead of arduino-cli. # arduino-cli ESP32 core is no longer needed for QEMU-compatible builds.