This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
name: Compile All
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
|
||||
- name: Setup secrets
|
||||
run: |
|
||||
cp secrets.yaml.sample secrets.yaml
|
||||
cp templates/secrets.yaml.sample templates/secrets.yaml
|
||||
|
||||
- name: Compile All
|
||||
run: |
|
||||
nix develop --command make compile-all
|
||||
+10
@@ -15,3 +15,13 @@ secrets.yaml
|
||||
|
||||
# direnv cache
|
||||
/.direnv
|
||||
|
||||
# Make dependencies
|
||||
.Makefile.deps
|
||||
|
||||
# Nix build outputs
|
||||
result
|
||||
result-*
|
||||
|
||||
# Pre-commit
|
||||
.pre-commit-config.yaml
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# Automatically find all YAML files and exclude special/secrets files
|
||||
ALL_YAML := $(wildcard *.yaml)
|
||||
EXCLUDE_YAML := secrets.yaml btproxy.yaml
|
||||
DEVICE_YAML := $(filter-out $(EXCLUDE_YAML), $(ALL_YAML))
|
||||
DEVICES := $(DEVICE_YAML:.yaml=)
|
||||
|
||||
BTPROXY_REPLICAS := c25bac c2577c c25b74
|
||||
|
||||
STAMP_DIR := .esphome/stamps
|
||||
MAKEFLAGS += --keep-going
|
||||
FLASH_TARGETS := $(addprefix $(STAMP_DIR)/.stamp-flash-, $(DEVICES)) $(addprefix $(STAMP_DIR)/.stamp-flash-btproxy-, $(BTPROXY_REPLICAS))
|
||||
COMPILE_TARGETS := $(addprefix $(STAMP_DIR)/.stamp-compile-, $(DEVICES)) $(addprefix $(STAMP_DIR)/.stamp-compile-btproxy-, $(BTPROXY_REPLICAS))
|
||||
|
||||
ESPHOME_BIN := $(shell command -v esphome)
|
||||
$(shell mkdir -p $(STAMP_DIR) && echo "$(ESPHOME_BIN)" > $(STAMP_DIR)/.esphome-bin.tmp && cmp -s $(STAMP_DIR)/.esphome-bin.tmp $(STAMP_DIR)/.esphome-bin || mv $(STAMP_DIR)/.esphome-bin.tmp $(STAMP_DIR)/.esphome-bin; rm -f $(STAMP_DIR)/.esphome-bin.tmp)
|
||||
all: compile-all
|
||||
|
||||
flash-all: $(FLASH_TARGETS)
|
||||
compile-all: $(COMPILE_TARGETS)
|
||||
|
||||
clean:
|
||||
rm -rf $(STAMP_DIR) .Makefile.deps
|
||||
|
||||
# Convenience targets
|
||||
flash-%: $(STAMP_DIR)/.stamp-flash-%
|
||||
@:
|
||||
compile-%: $(STAMP_DIR)/.stamp-compile-%
|
||||
@:
|
||||
|
||||
# Normal devices: compile
|
||||
$(STAMP_DIR)/.stamp-compile-%: %.yaml $(STAMP_DIR)/.esphome-bin
|
||||
@mkdir -p $(STAMP_DIR)
|
||||
esphome compile $<
|
||||
@touch $@
|
||||
|
||||
# Normal devices: flash
|
||||
$(STAMP_DIR)/.stamp-flash-%: %.yaml $(STAMP_DIR)/.esphome-bin
|
||||
@mkdir -p $(STAMP_DIR)
|
||||
esphome run --no-logs --device OTA $<
|
||||
@touch $@
|
||||
|
||||
# Special btproxy devices: compile
|
||||
$(STAMP_DIR)/.stamp-compile-btproxy-%: btproxy.yaml $(STAMP_DIR)/.esphome-bin
|
||||
@mkdir -p $(STAMP_DIR)
|
||||
esphome -s name btproxy-$* compile $<
|
||||
@touch $@
|
||||
|
||||
# Special btproxy devices: flash
|
||||
$(STAMP_DIR)/.stamp-flash-btproxy-%: btproxy.yaml $(STAMP_DIR)/.esphome-bin
|
||||
@mkdir -p $(STAMP_DIR)
|
||||
esphome -s name btproxy-$* run --no-logs --device OTA $<
|
||||
@touch $@
|
||||
|
||||
# Include generated dependencies
|
||||
-include .Makefile.deps
|
||||
|
||||
# Rule to update dependencies
|
||||
.Makefile.deps: $(wildcard *.yaml) $(wildcard templates/*.yaml) generate_deps.py
|
||||
@echo "Updating dependencies..."
|
||||
@python3 generate_deps.py "$(DEVICES)" "$(BTPROXY_REPLICAS)" > $@
|
||||
|
||||
.PHONY: all flash-all compile-all clean
|
||||
@@ -10,28 +10,41 @@ timezone when syncing the clock (NTP).
|
||||
|
||||
## Compiling
|
||||
|
||||
```
|
||||
```bash
|
||||
$ cp -i secrets.yaml{.sample,}
|
||||
$ cp -i templates/secrets.yaml{.sample,}
|
||||
|
||||
# Edit both secrets.yaml files.
|
||||
|
||||
$ ./reflash.sh compile ''
|
||||
# Compile all devices in parallel (up to 4 jobs)
|
||||
$ nix develop --command make compile-all -j4
|
||||
|
||||
# Or compile a single device
|
||||
$ nix develop --command make compile-bathroomheater
|
||||
```
|
||||
|
||||
## Running
|
||||
## Flashing
|
||||
|
||||
```
|
||||
$ ./reflash.sh
|
||||
To flash all devices (automatically prioritizes OTA and skips prompts):
|
||||
|
||||
```bash
|
||||
$ nix develop --command make flash-all -j4
|
||||
```
|
||||
|
||||
or
|
||||
To flash a single device:
|
||||
|
||||
```
|
||||
$ esphome run file.yaml
|
||||
```bash
|
||||
$ nix develop --command make flash-bathroomheater
|
||||
```
|
||||
|
||||
Look up list of runnable configurations inside `reflash.sh` script.
|
||||
Alternatively, you can drop into the development shell and run `esphome` directly:
|
||||
|
||||
```bash
|
||||
$ nix develop
|
||||
$ esphome run bathroomheater.yaml
|
||||
```
|
||||
|
||||
**Note:** The Makefile automatically tracks dependencies (including `!include` files and local `external_components` directories). It will natively evaluate changes and only recompile what has actually changed since the last run.
|
||||
|
||||
## Running remotely
|
||||
|
||||
|
||||
Generated
+79
-3
@@ -1,12 +1,72 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1767039857,
|
||||
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||
"owner": "NixOS",
|
||||
"repo": "flake-compat",
|
||||
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fw_nix": {
|
||||
"inputs": {
|
||||
"git-hooks": "git-hooks",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1783867522,
|
||||
"narHash": "sha256-rJUjsQbVFWWFQ7Xwt69Ad76v7OIpDXbqzW25d+I2BBs=",
|
||||
"owner": "futureware-tech",
|
||||
"repo": "nix",
|
||||
"rev": "e132e29c641ee55aba9ad08507ace53e19cf2b3e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "futureware-tech",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"git-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": [
|
||||
"fw_nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1783008725,
|
||||
"narHash": "sha256-jGiy6+sxjNWXSjp25uoJuNfyH9zBK1PEDY0lVoL4ibQ=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "bca82caa46d5ec0f5d422c61fb1e30bc51313cbe",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1783224372,
|
||||
"narHash": "sha256-8i/87eeoqiGE4yOTjwSA3Eh/ziJRQEmd/unYU+K27sk=",
|
||||
"lastModified": 1783776592,
|
||||
"narHash": "sha256-UgCQzxeWI75XM8G+hPrPh+MKzEPjG3SpAj7dtqSbksA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d407951447dcd00442e97087bf374aad70c04cea",
|
||||
"rev": "e7a3ca8092b61ff85b6a45bf863ea2b2d6a661b3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -18,8 +78,24 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fw_nix": "fw_nix",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
@@ -3,29 +3,72 @@
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
fw_nix = {
|
||||
url = "github:futureware-tech/nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs }:
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
fw_nix,
|
||||
}:
|
||||
let
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (system: f {
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
});
|
||||
forAllSystems =
|
||||
f:
|
||||
nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (
|
||||
system:
|
||||
f {
|
||||
inherit system;
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
devShells = forAllSystems ({ pkgs }: {
|
||||
default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
esphome
|
||||
esptool
|
||||
cc2538-bsl
|
||||
bash # for ./reflash.sh
|
||||
];
|
||||
checks = forAllSystems (
|
||||
{ system, ... }: {
|
||||
pre-commit-check = fw_nix.inputs.git-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = fw_nix.lib.pre-commit.hooks // {
|
||||
# Disable check-yaml because it fails on ESPHome's custom YAML tags (like !include, !secret)
|
||||
check-yaml.enable = false;
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
shellHook = ''
|
||||
echo -n "ESPHome "
|
||||
esphome --version
|
||||
'';
|
||||
};
|
||||
});
|
||||
devShells = forAllSystems (
|
||||
{ system, pkgs, ... }:
|
||||
let
|
||||
esphome-fhs = pkgs.buildFHSEnv {
|
||||
name = "esphome";
|
||||
targetPkgs =
|
||||
pkgs: with pkgs; [
|
||||
esphome
|
||||
zlib
|
||||
];
|
||||
multiPkgs = pkgs: with pkgs; [ zlib ];
|
||||
runScript = "esphome";
|
||||
};
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
esphome-fhs
|
||||
esptool
|
||||
cc2538-bsl
|
||||
gnumake
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
${self.checks.${system}.pre-commit-check.shellHook}
|
||||
echo -n "ESPHome "
|
||||
esphome --version
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_deps(file_path, visited=None):
|
||||
if visited is None:
|
||||
visited = set()
|
||||
if str(file_path) in visited:
|
||||
return set()
|
||||
visited.add(str(file_path))
|
||||
|
||||
deps = set()
|
||||
p = Path(file_path)
|
||||
if not p.is_file():
|
||||
return deps
|
||||
|
||||
with open(p, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
matches = re.findall(r"!include\s+([a-zA-Z0-9_/-]+\.yaml)", content)
|
||||
for match in matches:
|
||||
# Resolve path relative to the file being processed
|
||||
if match.startswith("/"):
|
||||
dep_path = Path(match)
|
||||
else:
|
||||
dep_path = (p.parent / match).resolve().relative_to(Path.cwd())
|
||||
|
||||
deps.add(str(dep_path))
|
||||
deps.update(get_deps(dep_path, visited))
|
||||
|
||||
# Also track local external_components directories
|
||||
source_matches = re.findall(r"source:\s+([a-zA-Z0-9_/-]+)", content)
|
||||
for match in source_matches:
|
||||
if match.startswith("/"):
|
||||
source_dir = Path(match)
|
||||
else:
|
||||
source_dir = (p.parent / match).resolve().relative_to(Path.cwd())
|
||||
|
||||
if source_dir.is_dir():
|
||||
for f in source_dir.rglob("*"):
|
||||
if f.is_file():
|
||||
deps.add(str(f))
|
||||
|
||||
return deps
|
||||
|
||||
|
||||
def main():
|
||||
devices = sys.argv[1].split()
|
||||
btproxy_replicas = sys.argv[2].split()
|
||||
|
||||
for device in devices:
|
||||
yaml_file = f"{device}.yaml"
|
||||
if not Path(yaml_file).is_file():
|
||||
continue
|
||||
|
||||
deps = get_deps(yaml_file)
|
||||
if deps:
|
||||
deps_str = " ".join(sorted(deps))
|
||||
print(f"$(STAMP_DIR)/.stamp-compile-{device}: {deps_str}")
|
||||
print(f"$(STAMP_DIR)/.stamp-flash-{device}: {deps_str}")
|
||||
|
||||
if Path("btproxy.yaml").is_file():
|
||||
deps = get_deps("btproxy.yaml")
|
||||
if deps:
|
||||
deps_str = " ".join(sorted(deps))
|
||||
for replica in btproxy_replicas:
|
||||
print(f"$(STAMP_DIR)/.stamp-compile-btproxy-{replica}: {deps_str}")
|
||||
print(f"$(STAMP_DIR)/.stamp-flash-btproxy-{replica}: {deps_str}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a full list of known esphome devices and
|
||||
# - reflash them
|
||||
# - reflash those that match $1
|
||||
# - do $1 to those that match $2
|
||||
#
|
||||
# Ex.: ./reflash.sh logs car
|
||||
|
||||
set -e
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
command=$1
|
||||
shift
|
||||
else
|
||||
command="run --no-logs"
|
||||
fi
|
||||
|
||||
declare -a flash
|
||||
|
||||
for config in \
|
||||
bathroomheater.yaml \
|
||||
blinds.yaml \
|
||||
heating.yaml \
|
||||
loud-siren.yaml \
|
||||
watermeter.yaml \
|
||||
heating-eg.yaml \
|
||||
heating-og.yaml \
|
||||
car-charger.yaml \
|
||||
freezer.yaml \
|
||||
living-room-entertainment.yaml \
|
||||
living-room-infra.yaml \
|
||||
outdoor-equipment.yaml \
|
||||
storage-heater.yaml \
|
||||
basement-dehum.yaml \
|
||||
zigbee-coordinator-ch24.yaml \
|
||||
zigbee-coordinator-ch25.yaml \
|
||||
child-west-ac.yaml \
|
||||
child-east-ac.yaml \
|
||||
spare-power-meter.yaml \
|
||||
office-desk-north.yaml \
|
||||
shadow-udmp.yaml \
|
||||
attic-central.yaml \
|
||||
office-rack.yaml \
|
||||
radiation.yaml \
|
||||
cat-feeder-cam.yaml \
|
||||
btproxy-laundry.yaml \
|
||||
garage-gate.yaml \
|
||||
irrigation.yaml \
|
||||
tools-power.yaml; do
|
||||
flash+=("${command?} ${config?}")
|
||||
done
|
||||
|
||||
if [[ "$command" == run* ]] || [[ "$command" == upload* ]] || [[ "$command" == logs* ]] || [[ "$command" == log* ]]; then
|
||||
for btproxy_replica in \
|
||||
c25bac \
|
||||
c2577c \
|
||||
c25b74
|
||||
do
|
||||
flash+=("${command?} btproxy.yaml --device btproxy-${btproxy_replica?}")
|
||||
done
|
||||
else
|
||||
flash+=("${command?} btproxy.yaml")
|
||||
fi
|
||||
|
||||
declare -A flash_result
|
||||
|
||||
print_results_table() {
|
||||
printf -- "-%.0s" {1..80}
|
||||
printf "\n%-70sSTATUS\n\n" "COMMAND"
|
||||
for result_cmdline in "${flash[@]}"; do
|
||||
printf "%-70s" "$result_cmdline "
|
||||
if [[ -v flash_result["$result_cmdline"] ]]; then
|
||||
echo "${flash_result["$result_cmdline"]}"
|
||||
else
|
||||
echo "N/A"
|
||||
fi
|
||||
done
|
||||
printf "\n%-70s%d\n" "TOTAL" "${#flash[@]}"
|
||||
printf -- "-%.0s" {1..80}
|
||||
echo
|
||||
echo
|
||||
}
|
||||
|
||||
for cmdline in "${flash[@]}"; do
|
||||
if [ $# -gt 0 ]; then
|
||||
if [[ "$cmdline" =~ $1 ]]; then
|
||||
:;
|
||||
else
|
||||
flash_result["$cmdline"]=SKIPPED
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
flash_result["$cmdline"]=CURRENT
|
||||
|
||||
print_results_table
|
||||
echo "Launching esphome: $cmdline"
|
||||
if echo 1 | esphome $cmdline; then
|
||||
flash_result["$cmdline"]=OK
|
||||
else
|
||||
flash_result["$cmdline"]=FAIL
|
||||
fi
|
||||
done
|
||||
|
||||
print_results_table
|
||||
Reference in New Issue
Block a user