Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e95623d
core: rewrite for esp32 on esphome
mik3y Aug 2, 2026
c87c965
components: add kegboard hub and flow meter
mik3y Aug 2, 2026
10a7d16
components: add kegbot server reporter
mik3y Aug 2, 2026
34dbc61
build: add board configs, examples, and ci
mik3y Aug 2, 2026
5b3b958
packages: add relays, buzzer, and led pins
mik3y Aug 3, 2026
86b7ab4
core: add auth grant state machine
mik3y Aug 3, 2026
1440a39
components: add token auth and ibutton presence
mik3y Aug 3, 2026
93d7a19
build: add native host smoke compile
mik3y Aug 3, 2026
fa39520
docs: add event protocol and authenticated pouring specs
mik3y Aug 3, 2026
6efa7fa
core: implement event protocol serialization
mik3y Aug 3, 2026
6281e78
components: speak the event protocol
mik3y Aug 3, 2026
390a68b
misc: run pre-commit
mik3y Aug 3, 2026
d458723
protocol: remove needless optionality
mik3y Aug 3, 2026
3847b0c
protocol: authentication is optional and server-driven
mik3y Aug 3, 2026
3187693
docs: pour timing anchors to pour end
mik3y Aug 3, 2026
de0de87
components: declare actions synchronous
mik3y Aug 3, 2026
1ce6ea3
reporter: log sends at debug, bodies at very-verbose
mik3y Aug 3, 2026
fdec2e9
docs: readme section on protocol traffic logging
mik3y Aug 3, 2026
fa466db
tools: add kegboard-sim, a tui kegboard for receiver development
mik3y Aug 3, 2026
722f9cc
misc: rebrand as kegboard v4
mik3y Aug 3, 2026
0fe55bb
docs: restore the manual as a sphinx project (WIP)
mik3y Aug 3, 2026
76c2372
protocol: status self-describes meters and relays
mik3y Aug 4, 2026
9bb4011
protocol: command catalog moves into the protocol doc
mik3y Aug 4, 2026
4e4f368
protocol: server-issued grants own scope, limits, and lifecycle
mik3y Aug 5, 2026
a5a972c
firmware: implement the grant model
mik3y Aug 5, 2026
1dd0119
tools: kegboard-sim speaks the grant protocol
mik3y Aug 5, 2026
8e32417
auth: remove local mode; the server always decides
mik3y Aug 5, 2026
1ff3d2e
relays: the watchdog cannot guard grant-held valves; say so and confi…
mik3y Aug 5, 2026
5b0babf
reporter: temperature events no longer reset delivery backoff
mik3y Aug 5, 2026
93cb7cc
docs: README minimal config uses meter_number, not index
mik3y Aug 5, 2026
2abc866
docs, comments: sweep references to removed local mode and legacy pykeg
mik3y Aug 5, 2026
d93b0b4
sim: pours split and continue across grant boundaries
mik3y Aug 5, 2026
a137da5
sim: prompt delivery when healthy, error acks for malformed grants
mik3y Aug 5, 2026
c9d40e6
core: host-testable delivery and auth engines
mik3y Aug 5, 2026
c11d4ff
misc: cleanup docs
mik3y Aug 5, 2026
98b9e7a
tests: grant updates can move to a disjoint meter set
mik3y Aug 5, 2026
3b4ed20
misc: run lint
mik3y Aug 5, 2026
312a1c6
docs: misc editorial cleanups
mik3y Aug 6, 2026
70140a6
misc: add bump script
mik3y Aug 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
Language: Cpp
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: DontAlign
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 2000
PointerAlignment: Right
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 2
UseTab: Never
136 changes: 136 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
# Pinned deliberately. ESPHome makes breaking changes to its external
# component API on a regular cadence, so contributors should not have a
# release land on them mid-PR. The nightly job in dev.yaml tracks upstream.
ESPHOME_VERSION: "2026.6.5"

jobs:
core-tests:
name: Core unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Check core purity
run: python3 script/check-core-purity.py

- name: Run tests
run: make -C tests/core STRICT=1

- name: Install jsonschema
run: pip install jsonschema

# The firmware's serialized output must validate against the normative
# protocol schemas, and the schema files must match the doc appendices.
- name: Check protocol schema conformance
run: python3 script/check-events-schema.py

lint:
name: Lint and format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v6
with:
python-version: "3.12"

- uses: pre-commit/action@v3.0.1

host-compile:
name: Host smoke compile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install ESPHome
run: pip install "esphome==${ESPHOME_VERSION}"

# Compiles the components natively with the system compiler: a full
# type-check of the C++ in seconds, no ESP toolchain download. The ESP32
# matrix below still proves the real targets.
- name: Compile host smoke test
run: esphome compile tests/host/smoke.yaml

config:
name: Validate configs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install ESPHome
run: pip install "esphome==${ESPHOME_VERSION}"

- name: Provide dummy secrets
run: cp examples/secrets.yaml.example examples/secrets.yaml

- name: Validate
run: |
for config in examples/*.yaml; do
case "$config" in *secrets*) continue;; esac
echo "::group::$config"
esphome config "$config"
echo "::endgroup::"
done

compile:
name: Compile ${{ matrix.board }}
runs-on: ubuntu-latest
needs: [core-tests, config, host-compile]
strategy:
fail-fast: false
matrix:
include:
- board: esp32-s3-devkitc-1
config: examples/kegbot-2tap.yaml
- board: esp32-devkit
config: examples/home-assistant-2tap.yaml
# Widest surface: relays, buzzer, LEDs, rfid, ibutton, and auth.
- board: esp32-s3-full
config: examples/kegbot-full.yaml
steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Cache PlatformIO and ESP-IDF toolchains
uses: actions/cache@v4
with:
path: |
~/.platformio
~/.espressif
key: pio-${{ matrix.board }}-${{ env.ESPHOME_VERSION }}-${{ hashFiles('boards/*.yaml') }}
restore-keys: |
pio-${{ matrix.board }}-${{ env.ESPHOME_VERSION }}-

- name: Install ESPHome
run: pip install "esphome==${ESPHOME_VERSION}"

- name: Provide dummy secrets
run: cp examples/secrets.yaml.example examples/secrets.yaml

- name: Compile
run: esphome compile ${{ matrix.config }}
35 changes: 35 additions & 0 deletions .github/workflows/esphome-dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
# Tracks ESPHome's dev branch so their breaking changes surface here as a
# failing scheduled build rather than as a user bug report weeks later.
#
# This job is expected to break occasionally. It does not gate PRs.
name: ESPHome dev

on:
schedule:
# Weekly, Monday early UTC.
- cron: "0 5 * * 1"
workflow_dispatch:

jobs:
compile-against-dev:
name: Compile against ESPHome dev
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install ESPHome from dev
run: pip install git+https://github.com/esphome/esphome.git@dev

- name: Report version under test
run: esphome version

- name: Provide dummy secrets
run: cp examples/secrets.yaml.example examples/secrets.yaml

- name: Compile
run: esphome compile examples/kegbot-full.yaml
26 changes: 16 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
### global stuff
*.DS_Store
# Python / tooling
.venv/
__pycache__/
*.pyc
*.egg
*.o
*.hex

python/dist/*
python/distribute-*
python/*egg-info
# ESPHome build output
.esphome/
secrets.yaml

arduino/kegboard/.dep
arduino/kegboard/.lib
# Host test build output
tests/core/build/

# Sphinx build output
docs/_build/

# Editors / OS
.DS_Store
compile_commands.json
uv.lock
32 changes: 32 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
# Formatting and lint hooks. Install with: pre-commit install
#
# The C++ and Python conventions here deliberately mirror ESPHome's own, since
# our components are compiled into their tree and most contributors will be
# coming from that codebase. clang-format is pinned to the same v13 they pin.
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v13.0.1
hooks:
- id: clang-format
types_or: [c, c++]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.16.1
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

- repo: https://github.com/adrienverge/yamllint.git
rev: v1.37.1
hooks:
- id: yamllint
exclude: ^\.clang-format$

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-merge-conflict
18 changes: 18 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

version: 2

# Install the docs toolchain with uv from docs/uv.lock and build with
# sphinx. docs/ is a self-contained uv project; the firmware repo itself
# contains nothing to install.
build:
os: ubuntu-24.04
tools:
python: '3.13'
commands:
- asdf plugin add uv
- asdf install uv latest
- asdf global uv latest
- uv sync --project docs --frozen
- uv run --project docs --no-sync sphinx-build -T -b html docs $READTHEDOCS_OUTPUT/html
Loading
Loading