Generate node firmware from a YAML file at build time #119
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/yaml-generator"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
YN-2.
NODE=nodes/x.yaml pio run -e gen_xiao_c3|gen_xiao_s3|gen_lolin32runsscripts/gen_node.pyas apre:script. It writessrc/gen_node/main.cpp(gitignored) from the YAML, using the YN-1 runtime (ctrl::Bind,node.addBind,SwitchInput). PyYAML is installed into PlatformIO's Python on first use. Any validation error stops the build with one line naming the file and field, and aboard:that doesn't match the environment is one of them.Decisions:
toggleon a YAML source withlatching: truebecomesToggleOnChange; numeric (hand-written) sources are trusted and getToggle.can::MsgClass::Eventas its filter interest; none otherwise. The "more than one message class" check is not written: every v1 source isCLASS_EVENT, so it cannot fail. The README sentence about it is left as is.SwitchEndpointgains an optionalinvertargument so a relay can be active-low. Existing callers are unchanged. It only touches the GPIO write, so it has no host test.D0(GPIO2) is out, and on the S3D2(GPIO3).D7toD10are taken by the CAN board on both XIAOs.frequency(Hz) andfade(ms).nodes/shed.yamlis the sample: a relay with a local toggle from a switch and a remote follow of a hand-written node.Tested:
scripts/test_yaml_node.py(stdlibunittest, 17 cases, mutating the latching rule and the strapping check each fails one); a CI step runs it, then builds everynodes/*.yamlwith its matching env. Built locally: the sample ongen_xiao_c3, plus throwaway nodes covering dimmer, occupancy and temperature ongen_lolin32and relay and latching switch ongen_xiao_s3. Native suite andpio runstill pass. Not run on hardware.Three findings, most serious first.
lib/node-runtime/src/switch_endpoint.cpp, begin(): pinMode(OUTPUT) runs before the off level is written. With invert on, the pin sits at the chip's default output level, which is the on level, until applyOutput() runs. For an active-low driver that is a boot-time pulse on. The "driver polarity" invariant says the off level goes out before the pin is taken. Fix it, or state in the PR why a relay is exempt.
CI only compiles nodes/shed.yaml, which is XIAO C3 with a relay and a switch. The dimmer, occupancy, temperature, XIAO S3 and LOLIN32 generation paths are never compiled. I built them by hand and they pass today, but nothing keeps them passing. Add a second sample covering those, or have build_yaml_nodes.sh also build a fixture on each env.
The CI pip step is redundant. scripts/gen_node.py already installs pyyaml when it is missing. Delete the CI line, or delete the install from the script and keep the CI line. Installing packages as a side effect of
pio runis the worse of the two.Smaller cleanups in scripts/yaml_node.py:
boardand never uses it.Findings 1, 2 and 4 fixed in the follow-up commit: the off level is written before
pinMode(not checked on hardware),scripts/fixtures/holds a LOLIN32 and an S3 node that CI builds with the sample, and the label, path and unused-argument cleanups are done. Finding 3 left: the CI install is for the runner's system Python, which looks up the environment name from the YAML. The one ingen_node.pyis for PlatformIO's own Python, which is a different interpreter.