Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
206fc4a
Use different RGB patterns for Active Clearing vs Awaiting Release EStop
nullstalgia Jan 9, 2026
9e4cf09
Use Yellow for Active Clearing.
nullstalgia Jan 9, 2026
a9b66ef
Bruteforcing Arduino 3.0 support
nullstalgia Jan 23, 2026
08897d4
fix captiveportal include path and config struct construction
hhvrc Jan 23, 2026
4096bfc
Rename OpenShock::Serial -> OpenShock::SerialCmds
nullstalgia Jan 24, 2026
67c4e31
Use Arduino 3.0 WiFi AP class
nullstalgia Jan 24, 2026
55000a5
Captive portal: fix use-after-free and DNS Server not being invoked
nullstalgia Jan 24, 2026
50c8320
Captive portal: Pause scan on user websocket connect to reduce d/c risk
nullstalgia Jan 24, 2026
71c3128
Fix template deduction errs
nullstalgia Jan 24, 2026
5b2bdf6
Temporarily comment out IPv6 logic (as type now has combined v4 and v6)
nullstalgia Jan 24, 2026
4f83d81
Temporarily comment out error pragma
nullstalgia Jan 24, 2026
d87d300
Captive portal: Samsung devices beginning to respond correctly
nullstalgia Jan 24, 2026
cb06a40
Captive portal: non-empty redirect
nullstalgia Jan 24, 2026
5490510
Add xtensa-esp-elf-gdb and openocd-esp32 to platform_packages
nullstalgia Jan 24, 2026
b731c74
Improve GPIO LED EStop interaction blink patterns
nullstalgia Jan 25, 2026
8edc45e
Merge branch 'feat/estop-activeclearing-awaitingrelease-patterns' int…
nullstalgia Jan 25, 2026
b82600f
Merge branch 'develop' into feat/arduino-3.0
hhvrc Feb 16, 2026
51596b2
Fix more stuff
hhvrc Feb 16, 2026
b84dccc
Merge branch 'develop' into feat/arduino-3.0
hhvrc Feb 16, 2026
72b491a
More fixes
hhvrc Feb 16, 2026
3d3460d
Merge branch 'develop' into feat/arduino-3.0
hhvrc Feb 16, 2026
babac53
Merge branch 'develop' into feat/arduino-3.0
hhvrc Mar 27, 2026
c2c4a87
wip: merge develop and fix span migration for Arduino 3.0
hhvrc Mar 27, 2026
bac7630
Merge branch 'develop' into feat/arduino-3.0
hhvrc Apr 20, 2026
350bd74
Bump platform version
hhvrc Apr 20, 2026
1fe26ec
Merge remote-tracking branch 'origin/develop' into feat/arduino-3.0
hhvrc Apr 22, 2026
83e7a8c
Start modularizing firmware
hhvrc Apr 23, 2026
8cdbed1
Move more stuff
hhvrc Apr 23, 2026
ade5c4d
Merge branch 'develop' into feat/arduino-3.0
hhvrc Jun 1, 2026
863b006
Merge branch 'develop' into feat/arduino-3.0
hhvrc Jun 2, 2026
df131af
Merge remote-tracking branch 'origin/develop' into feat/arduino-3.0
hhvrc Jun 29, 2026
6460c25
build: make arduino-3.0 component layout compile
hhvrc Jun 29, 2026
c25a337
build: sdkconfig defaults+per-chip layering; fix S3-Mini USB serial
hhvrc Jun 29, 2026
009d007
fix(ci): add GitPython dep and cache restore-keys
hhvrc Jun 29, 2026
d0ee048
fix(ci): cache full pioarduino tree and stop hard-depending on GitPython
hhvrc Jun 29, 2026
9f602e8
fix: address Copilot review comments for Arduino 3.0 migration
hhvrc Jun 29, 2026
99618ef
Merge branch 'develop' into feat/arduino-3.0
hhvrc Jul 9, 2026
356893f
build: drop unused arduino-esp32 managed components to slim the build
hhvrc Jul 9, 2026
a3d07e9
feat(json): migrate config + serialization from cJSON to osjson
hhvrc Jul 9, 2026
95338c9
refactor(components): split hwutil/panic out of util/logging; rename …
hhvrc Jul 9, 2026
9f1da2f
fix(util): SemVer dotted prereleases + ordering, TryStringSplit remai…
hhvrc Jul 9, 2026
2eaabad
test: host-test suites for common and util (linux target)
hhvrc Jul 9, 2026
aa95fd6
style: clang-format 21 across the project; drop moved util sources
hhvrc Jul 9, 2026
842558b
refactor(serial,logging): route console I/O through IDF, drop Arduino…
hhvrc Jul 9, 2026
e0b096e
refactor(rmt): migrate RF + LED drivers to IDF driver/rmt_tx
hhvrc Jul 9, 2026
bb7482f
refactor(http): migrate HTTP client to esp_http_client, drop Arduino …
hhvrc Jul 9, 2026
f075170
refactor(ip): drop Arduino IPAddress, remove dead IP config helpers
hhvrc Jul 9, 2026
c523a7b
refactor(events): extract event bus into its own components/events
hhvrc Jul 9, 2026
e4e4e89
refactor(wifi): migrate WiFi/scan/SoftAP from Arduino WiFi to esp_wifi
hhvrc Jul 9, 2026
2deae47
Update sdkconfig.defaults
hhvrc Jul 9, 2026
07f3da7
refactor(crypto): migrate Hashing to mbedTLS generic md API
hhvrc Jul 9, 2026
b042a24
build(idf): enable esp_http_server WebSocket support
hhvrc Jul 9, 2026
4d114ea
feat(captive-portal): add isolated ESP-IDF components for portal prim…
hhvrc Jul 9, 2026
b39e74e
refactor(fs): rename static_fs -> fs, add ConfigFs, hide lfs.h behind…
hhvrc Jul 9, 2026
d22d1a8
build: migrate to espressif32 7.0.1 / ESP-IDF 6, drop Arduino framework
hhvrc Jul 9, 2026
8a08524
feat(fs): add TestFilesystem() partition-probe helpers
hhvrc Jul 9, 2026
c731293
refactor: drop remaining Arduino references from ESP-IDF components
hhvrc Jul 9, 2026
7f3de47
build: fix ESP-IDF 6 build blockers and remove Arduino WS/RFC8908 files
hhvrc Jul 9, 2026
608177a
build: initialize new IDF 6 LED-driver config struct fields
hhvrc Jul 9, 2026
35aa264
refactor: migrate gateway client and captive portal to native ESP-IDF
hhvrc Jul 9, 2026
ac1f899
build(certs): track binaries in Git LFS and refresh CA bundle
hhvrc Jul 9, 2026
29a0c7a
fix(osjson): remove embedded NUL byte from host test comment
hhvrc Jul 9, 2026
2a523a7
feat(tls): verify server certificates against a compiled-in CA bundle
hhvrc Jul 9, 2026
b03e81e
style: apply clang-format 21 across the source tree
hhvrc Jul 9, 2026
e179200
ci(cpp-linter): ignore vendored littlefs and managed_components
hhvrc Jul 9, 2026
c2c9751
fix(common): don't fail component builds when OPENSHOCK_RF_TX_GPIO is…
hhvrc Jul 9, 2026
c4c3a24
ci(cpp-linter): ignore native host_test sources
hhvrc Jul 9, 2026
4f10112
ci fixes
hhvrc Jul 9, 2026
588e799
docs(changes): add change file for the ESP-IDF migration
hhvrc Jul 9, 2026
de70a35
ci: pre-build bootloader serially to avoid bootloader.ld link race
hhvrc Jul 9, 2026
363adad
ci: retry pio run to survive the intermittent bootloader.ld link race
hhvrc Jul 9, 2026
1229e33
feat(certs): pin GlobalSign Root CA R1 and add merged trust store wit…
hhvrc Jul 9, 2026
6cdd93c
ci: remove bootloader.ld retry logic, restore plain pio run
hhvrc Jul 9, 2026
8ef2688
refactor(enums): migrate remaining converters to the string_view API
hhvrc Jul 9, 2026
92ac83c
build: migrate from PlatformIO to native ESP-IDF
hhvrc Jul 9, 2026
dd63e87
refactor(firmware): read board and build config from Kconfig
hhvrc Jul 9, 2026
c6bce75
ci: migrate CI/CD to native ESP-IDF
hhvrc Jul 9, 2026
8d6ee33
chore: drop committed local tooling config
hhvrc Jul 9, 2026
32b8813
ci: build C++ and staticfs in parallel, then merge
hhvrc Jul 9, 2026
c9eba1e
fix(ci): activate the ESP-IDF venv so idf.py runs
hhvrc Jul 9, 2026
64e7413
fix(ci): run idf.py via install-esp-idf-action's wrapper
hhvrc Jul 9, 2026
c0cab92
fix(ci): unblock cpp-linter on the native ESP-IDF migration
hhvrc Jul 10, 2026
90146c2
refactor: restructure into idiomatic ESP-IDF components
hhvrc Jul 10, 2026
a3c7789
chore(common): drop LanguageVersionCheck compile-time C++ standard guard
hhvrc Jul 10, 2026
6074a88
chore: drop dead includes and tighten component visibility
hhvrc Jul 10, 2026
5875dab
refactor(serial): dedicated low-level transport; logging writes to it
hhvrc Jul 10, 2026
d521342
test(protocols): host-test the RF bit-encoders
hhvrc Jul 10, 2026
6d42c44
refactor(core): privatize leaky headers and demote their deps
hhvrc Jul 10, 2026
ff06541
ci(get-vars): tighten sanitize and ref parsing
hhvrc Jul 10, 2026
c55acb4
test(util): host-test Checksum, TinyVec and FnProxy
hhvrc Jul 10, 2026
f95b13c
refactor(common): extract InferFirmwareBootType as a pure function
hhvrc Jul 10, 2026
e916560
refactor(serialization): extract generated flatbuffer schemas into a …
hhvrc Jul 10, 2026
a3c87d2
refactor(config): extract config into its own low-layer component
hhvrc Jul 10, 2026
6062099
refactor(device_control): extract estop/radio/visual/CommandHandler f…
hhvrc Jul 10, 2026
0d11fc0
refactor(util): modernize FnProxy and DigitCounter
hhvrc Jul 10, 2026
6634ffd
refactor(util): propagate noexcept through FnProxy; cast to const C
hhvrc Jul 10, 2026
f093a58
Assign explicit values to SetGPIOResultCode enum
hhvrc Jul 13, 2026
7dad3fa
Fix formatting of InternalError in SetGPIOResultCode
hhvrc Jul 13, 2026
cb2396e
refactor(config): make each config own its JSON object
hhvrc Jul 13, 2026
1907462
refactor LittleFS component
hhvrc Jul 13, 2026
7e5748a
refactor(components): consolidate foundation layer and split out crypto
hhvrc Jul 13, 2026
79baacb
refactor(serial): scan console chunks in place instead of byte-by-byte
hhvrc Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 14 additions & 0 deletions .changes/esp-idf-6-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
kind: changed
breaking: true
---
Rebuild the firmware on the native ESP-IDF platform

## Release Note
This is one of the biggest updates the firmware has ever had: the whole thing has been rebuilt from the ground up on Espressif's native platform, leaving the old Arduino foundation behind.

You won't see a pile of new buttons from this release — most of the work is under the hood. What you get is a firmware that's faster to start up, lighter on memory, and far more stable, with a much cleaner codebase that makes future features quicker and safer to add. It also brings a real security upgrade: your hub now checks that it's genuinely talking to OpenShock's servers before it trusts them, so the connection between your device and the network is properly protected.

Just about every part of the firmware was touched along the way — WiFi and networking, the way settings are stored, the radio that talks to your shockers, the status LEDs, and the serial console. Everything has been retested and put back together on the new foundation.

Because this rework runs so deep, we're treating it as a major release. It flashes and runs like any other update, and your existing setup carries over.
8 changes: 0 additions & 8 deletions .claude/hooks/clang-format.sh

This file was deleted.

15 changes: 0 additions & 15 deletions .claude/settings.json

This file was deleted.

5 changes: 0 additions & 5 deletions .env

This file was deleted.

3 changes: 0 additions & 3 deletions .env.development

This file was deleted.

3 changes: 0 additions & 3 deletions .env.production

This file was deleted.

2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
* text=auto eol=lf
*.txt text eol=lf
*.exe filter=lfs diff=lfs merge=lfs -text
scripts/flatc filter=lfs diff=lfs merge=lfs -text
30 changes: 14 additions & 16 deletions .github/actions/build-compilationdb/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: build-compilationdb
description: Builds the compilation database for the firmware for code analysis
description: >-
Build a representative board with native ESP-IDF to emit
build/compile_commands.json (for cpp-linter) and a real compile pass (for
CodeQL C/C++). Uses OpenShock-Core-V2 / esp32s3 as the canonical config.
inputs:
version:
required: true
Expand All @@ -8,25 +11,20 @@ inputs:
runs:
using: composite
steps:
- uses: ./.github/actions/pio-cache
with:
env: ci-build
- uses: ./.github/actions/setup-esp-idf

- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
cache: 'pip'

- name: Install python dependencies
shell: bash
run: pip install -r requirements.txt

- name: Build firmware
working-directory: .
# Build only the `app` target: this configures the project (writing
# build/OpenShock-Core-V2/compile_commands.json for cpp-linter) and compiles
# the application (so CodeQL traces the C/C++). It skips the static0 image, so
# no frontend / littlefs is needed. ccache is left off so CodeQL sees every
# compiler invocation.
- name: Build firmware (OpenShock-Core-V2 / esp32s3)
shell: bash
run: |
set -euo pipefail
export OPENSHOCK_FW_BUILD_DATE="$(git show -s --format=%cI HEAD 2>/dev/null || date -u +%Y-%m-%dT%H:%M:%SZ)"
pio run -e ci-build -t compiledb
python3 scripts/build.py OpenShock-Core-V2 app
env:
OPENSHOCK_FW_VERSION: ${{ inputs.version }}
OPENSHOCK_FW_GIT_REF: ${{ github.ref }}
OPENSHOCK_FW_GIT_COMMIT: ${{ github.sha }}
OPENSHOCK_FW_GIT_COMMIT: ${{ github.sha }}
57 changes: 38 additions & 19 deletions .github/actions/build-firmware/action.yml
Original file line number Diff line number Diff line change
@@ -1,46 +1,65 @@
name: build-firmware
description: Builds the firmware partitions and uploads them as an artifact
description: >-
Compile one board's C++ firmware with native ESP-IDF and upload its discrete
partition images (app, bootloader, partition-table). Builds only the code
targets - not the static0 web-assets image - so it runs in parallel with
build-staticfs; the merge-partitions job links them together.
inputs:
board:
required: true
description: 'Board name to build'
description: 'Board name to build (matches boards/<board>.defaults)'
version:
required: true
description: 'Current firmware version'

runs:
using: composite
steps:
- uses: ./.github/actions/pio-cache
with:
env: ${{ inputs.board }}
- uses: ./.github/actions/setup-esp-idf

- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
# ccache keyed per board's chip (compiler/framework artifacts track the chip).
- name: Cache ccache
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
cache: 'pip'

- name: Install python dependencies
shell: bash
run: pip install -r requirements.txt
path: ~/.cache/ccache
key: ccache-${{ runner.os }}-${{ inputs.board }}-${{ github.sha }}
restore-keys: |
ccache-${{ runner.os }}-${{ inputs.board }}-

# Build only the code targets (app + bootloader + partition-table). This
# skips the static0 image (built separately by build-staticfs), so no
# frontend is needed here. scripts/build.py resolves the target from
# boards/<board>.defaults, sets OPENSHOCK_BOARD, and layers the sdkconfig.
- name: Build firmware
working-directory: .
shell: bash
# head_commit.timestamp only exists on push events, so derive the build
# date from the checked-out commit (falling back to now) - otherwise
# schedule/dispatch builds bake in an empty date.
run: |
set -euo pipefail
export OPENSHOCK_FW_BUILD_DATE="$(git show -s --format=%cI HEAD 2>/dev/null || date -u +%Y-%m-%dT%H:%M:%SZ)"
pio run -e ${{ inputs.board }}
export IDF_CCACHE_ENABLE=1
python3 scripts/build.py "${{ inputs.board }}" app bootloader partition-table
env:
OPENSHOCK_FW_VERSION: ${{ inputs.version }}
OPENSHOCK_FW_GIT_REF: ${{ github.ref }}
OPENSHOCK_FW_GIT_COMMIT: ${{ github.sha }}

- name: Upload build artifacts
# Flat, canonically-named images. app.bin/staticfs.bin are the names the
# device OTA pulls (OtaUpdateManager.cpp); merge_image.py and the CDN upload
# consume these too. `project(firmware)` names the app image firmware.bin.
- name: Stage partition images
shell: bash
env:
B: build/${{ inputs.board }}
run: |
set -euo pipefail
mkdir -p dist
cp "$B/firmware.bin" dist/app.bin
cp "$B/bootloader/bootloader.bin" dist/bootloader.bin
cp "$B/partition_table/partition-table.bin" dist/partition-table.bin

- name: Upload partition images
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: firmware_build_${{ inputs.board }}
path: .pio/build/${{ inputs.board }}/*.bin
retention-days: 1
path: dist/*.bin
retention-days: 7
if-no-files-found: error
51 changes: 26 additions & 25 deletions .github/actions/build-staticfs/action.yml
Original file line number Diff line number Diff line change
@@ -1,51 +1,52 @@
name: build-staticfs
description: Builds the static filesystem partition and uploads it as an artifact
description: >-
Pack the captive-portal web assets into the static0 littlefs image once
(board-independent) via scripts/gen_staticfs.py. Runs in parallel with the
per-board C++ build; the merge job combines the two.
inputs:
version:
required: true
description: 'Current firmware version'
description: 'Current firmware version (unused in the image, kept for parity)'
required: false
default: ''

runs:
using: composite
steps:
- uses: ./.github/actions/pio-cache
with:
env: fs

- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
cache: 'pip'

- name: Install dependencies
- name: Install Python dependencies
shell: bash
run: pip install -r requirements.txt

- name: Download built frontend
# The frontend is built once in build-frontend and downloaded here so
# gen_staticfs.py packs the prebuilt assets rather than rebuilding them.
- name: Download frontend
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: frontend
path: frontend/build/
path: frontend/build

- name: Build filesystem partition
# static0 is 0x09D000 bytes in the 4MB OTA table (partitions/ota_4mb.csv);
# the image is board-independent, so one build serves every board. Geometry
# (4 KiB blocks, 128-byte read/prog) matches the runtime mount in
# components/fs/src/LfsPartition.cpp and the CMake build.
- name: Build static filesystem image
shell: bash
# head_commit.timestamp only exists on push events; derive from the commit
# (falling back to now) so schedule/dispatch builds don't get an empty date.
run: |
export OPENSHOCK_FW_BUILD_DATE="$(git show -s --format=%cI HEAD 2>/dev/null || date -u +%Y-%m-%dT%H:%M:%SZ)"
pio run --target buildfs -e fs
env:
OPENSHOCK_FW_VERSION: ${{ inputs.version }}
OPENSHOCK_FW_GIT_REF: ${{ github.ref }}
OPENSHOCK_FW_GIT_COMMIT: ${{ github.sha }}

- name: Rename partition binary
shell: bash
run: mv .pio/build/fs/littlefs.bin staticfs.bin
python scripts/gen_staticfs.py \
--frontend-dir frontend \
--staging-dir staticfs \
--output staticfs.bin \
--partition-size 0x09D000 \
--block-size 4096 --read-size 128 --prog-size 128 \
--skip-frontend-build

- name: Upload internal filesystem artifact
- name: Upload static filesystem artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: firmware_staticfs
path: staticfs.bin
retention-days: 1
retention-days: 7
if-no-files-found: error
9 changes: 5 additions & 4 deletions .github/actions/cdn-upload-firmware/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ runs:
pattern: firmware_*

# Assemble the full /<version>/ tree locally, one directory per board, so it
# can be pushed in a single mirror. Each board directory keeps the previous
# per-board layout: static + build partitions, the merged firmware.bin, and
# md5/sha256 checksums over every .bin.
# can be pushed in a single mirror. Each board directory keeps the per-board
# layout the device OTA expects: the shared staticfs.bin, the board's app.bin
# (+ bootloader / partition-table) from firmware_build_<board>, the merged
# firmware.bin, and md5/sha256 checksums over every .bin.
- name: Assemble upload tree
shell: bash
env:
Expand All @@ -44,7 +45,7 @@ runs:
[ -z "$board" ] && continue
dest="upload/$board"
mkdir -p "$dest"
cp artifacts/firmware_staticfs/*.bin "$dest"/
cp artifacts/firmware_staticfs/staticfs.bin "$dest"/
cp "artifacts/firmware_build_$board"/*.bin "$dest"/
cp "artifacts/firmware_merged_$board"/OpenShock_*.bin "$dest"/firmware.bin
(
Expand Down
27 changes: 18 additions & 9 deletions .github/actions/merge-partitions/action.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
name: merge-partitions
description: Merges multiple partitions into a single flashable binary
description: >-
Link a board's C++ partition images (from build-firmware) with the shared
static0 image (from build-staticfs) into a single flashable binary via
scripts/merge_image.py. Needs esptool only - no full ESP-IDF install.
inputs:
version:
description: 'Version of the firmware'
description: 'Firmware version'
required: true
board:
description: 'Board name to merge partitions for'
Expand All @@ -15,25 +18,31 @@ runs:
with:
cache: 'pip'

- name: Install dependencies
- name: Install Python dependencies
shell: bash
run: pip install -r requirements.txt

- name: Download static filesystem partition
- name: Download C++ partition images
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: firmware_staticfs
name: firmware_build_${{ inputs.board }}
path: merge

- name: Download firmware partitions
- name: Download static filesystem image
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: firmware_build_${{ inputs.board }}
name: firmware_staticfs
path: merge

- name: Merge partitions
shell: bash
run: |
python scripts/merge_image.py ${{ inputs.board }}
mv merged.bin OpenShock_${{ inputs.board }}_${{ inputs.version }}.bin
set -euo pipefail
python scripts/merge_image.py \
--board "${{ inputs.board }}" \
--bindir merge \
--staticfs merge/staticfs.bin \
--output "OpenShock_${{ inputs.board }}_${{ inputs.version }}.bin"

- name: Upload merged firmware binary
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
Loading
Loading