Skip to content

Commit c9ea445

Browse files
committed
Build professional substrate calculator and calibration wizard
1 parent 7668f6a commit c9ea445

23 files changed

Lines changed: 1228 additions & 993 deletions

.github/workflows/pages.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@ on:
88
- 'tools/site/**'
99
- 'tools/build_site.py'
1010
- 'docs/**'
11+
- 'tests/wizard.test.js'
12+
- 'tests/export_fixtures.js'
13+
- 'tests/test_generated_configs.py'
1114
- '.github/workflows/pages.yml'
1215
pull_request:
1316
paths:
1417
- 'tools/setup/**'
1518
- 'tools/site/**'
1619
- 'tools/build_site.py'
1720
- 'docs/**'
21+
- 'tests/wizard.test.js'
22+
- 'tests/export_fixtures.js'
23+
- 'tests/test_generated_configs.py'
1824
- '.github/workflows/pages.yml'
1925
workflow_dispatch:
2026

@@ -37,16 +43,35 @@ jobs:
3743
with:
3844
node-version: '22'
3945
- run: python -m pip install -r tools/site/requirements.txt
40-
- run: node --test tests/calculator.test.js
46+
- run: node --test tests/calculator.test.js tests/wizard.test.js
4147
- name: Build site and check links
4248
run: python tools/build_site.py
4349
- uses: actions/upload-pages-artifact@v4
4450
with:
4551
path: _site
4652

53+
validate-yaml:
54+
runs-on: ubuntu-latest
55+
timeout-minutes: 20
56+
steps:
57+
- uses: actions/checkout@v6
58+
- uses: actions/setup-python@v5
59+
with:
60+
python-version: '3.12'
61+
- uses: actions/setup-node@v4
62+
with:
63+
node-version: '22'
64+
- uses: actions/cache@v4
65+
with:
66+
path: ~/.platformio
67+
key: tdr-wizard-esphome-2026.8.2
68+
- run: python -m pip install esphome==2026.8.2
69+
- name: Validate all exports and compile the weighed import
70+
run: python tests/test_generated_configs.py --compile
71+
4772
deploy:
4873
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
49-
needs: build
74+
needs: [build, validate-yaml]
5075
runs-on: ubuntu-latest
5176
permissions:
5277
pages: write

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
with:
1919
python-version: '3.12'
2020
- run: pip install PyYAML==6.0.2
21-
- run: node --test tests/calculator.test.js
21+
- run: node --test tests/calculator.test.js tests/wizard.test.js
2222
- run: python tests/test_firmware.py
2323
- run: python tests/test_repository.py
2424
- run: python tests/test_logger.py

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ output/playwright/
1818
/esphome/factory/.gitignore
1919

2020
# Generated GitHub Pages site
21-
/_site/
21+
/_site*/

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
An ESPHome reader for the **INFWIN MT22A SDI-12** substrate probe, with checked water-content calibration, bulk EC, temperature and observed dryback trends. Runs locally on ESP32/M5Stack hardware with a web page, Home Assistant, optional MQTT and CSV logging.
44

5-
**Open the [live substrate and calibration setup desk](https://jaketherabbit.github.io/TDR-Sensor/).** It covers cubes, cubes on shared slabs, coco containers, metric/custom sizes, weighed calibration records and an actual-size printable placement sheet. The [field guides](https://jaketherabbit.github.io/TDR-Sensor/guides/) are readable on the site too.
5+
**Open the [live substrate calculator and calibration wizard](https://jaketherabbit.github.io/TDR-Sensor/).** Configure cubes, shared slabs or coco containers; switch all calculator measurements between metric and imperial; follow diagrams for each system; and export sensor settings or board-specific ESPHome YAML. The calibration wizard supports a wet reference or weighed A/B/C checks, with downloadable records and actual-size A4/Letter placement templates. The [field guides](https://jaketherabbit.github.io/TDR-Sensor/guides/) are readable on the site too.
66

7-
For offline use, download this repository ZIP, extract it and open [tools/setup/index.html](tools/setup/index.html) in a browser. Calculator entries stay in your browser; the site does not connect to or control a sensor.
7+
For offline use, download this repository ZIP, extract it and open [tools/setup/index.html](tools/setup/index.html) in a browser. Setup and calibration records are saved in this browser and can be exported/imported as a JSON project. The site does not connect to or control a sensor. Generated YAML provides explicit setup/import buttons; references are never written automatically at boot.
88

99
![MT22 placement on a three-plant slab](docs/img/mt22-placement.svg)
1010

docs/CALIBRATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Calibrate without pretending saturation is 100% VWC
1+
# Calibrate the MT22
22

33
There are two different tasks: saving a repeatable wet reference, and estimating actual volumetric water content from independent weights. Version 3 keeps them separate. All captures are available on the node's web page and in Home Assistant; calibration does not require reflashing.
44

docs/CONFIG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,31 @@ For MQTT, uncomment the `tdr_mqtt.yaml` package and fill in `mqtt_broker`, `mqtt
7474

7575

7676
CSV logging: wide format now records each field's observation age, blanks readings after `--max-age` (default 120 seconds) or a disconnected stream, and refuses to append a mismatched header. Start a new CSV after upgrading. Use long format for entities that appear after the initial snapshot; wide mode warns rather than silently dropping new columns. Adjust maximum age to the actual reporting cadence, not the desired irrigation interval.
77+
78+
## Generate a configuration in the calculator
79+
80+
The [setup wizard](../tools/setup/index.html#volume) exports the selected board,
81+
data pin, SDI-12 address, sampling cadence and substrate profile. It offers a
82+
sensor-settings report, a complete device YAML and a `secrets.yaml.example` file.
83+
Fill the secrets locally; the website never asks for them.
84+
85+
The YAML pins the v3 packages. It adds **Apply wizard setup**, which explicitly
86+
sets the profile and capture/check limits and starts a new capture window. Saved
87+
ESPHome preferences take precedence over initial defaults, so press this button
88+
after installing the configuration when you want to apply those settings.
89+
90+
If the wizard contains a valid recorded wet reference or checked A/B/C set, the
91+
export also adds **Import wizard references**. Use it only for the same physical
92+
probe, medium and placement. It requires Calibration mode, the expected profile,
93+
ten fresh readings and a stable RAW window. It replaces references only when
94+
pressed; rebooting never reimports them. Verify all saved values afterward,
95+
turn Calibration mode off, and wait ten seconds before disconnecting power.
96+
97+
If references were already captured on the device at their original moisture
98+
levels, simply verify them against the wizard's report. Do not recapture old A/B/C
99+
values at a different current moisture level. Substrate litres belong in the
100+
volume record and steering app; they are not substituted for measured calibration.
101+
102+
The wizard accepts the probe's actual address character. The pinned driver uses
103+
indices 0–9 for digits, 10–35 for a–z, and 36–61 for A–Z. The exporter performs that
104+
conversion; its YAML comment preserves the address character for comparison.

docs/PLACEMENT.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@ The factory does not publish an MT22/Prestige-specific minimum distance from eve
2323

2424
## Cubes alone
2525

26+
![MT22 horizontal placement in a standalone cube](img/mt22-cube-placement.svg)
27+
2628
Use a repeatable side insertion into a sufficiently large block, with the rod row level. A midpoint height is an initial mapping position, subject to the same boundary and representativeness checks. A 150 mm-wide Hugo can accommodate the 88 mm contact face geometrically; that is not proof of whole-block accuracy.
2729

2830
**Small propagation blocks need a different sensor or validation arrangement.** A 75 mm-wide cube cannot accommodate the MT22's 88 mm-wide face in this orientation. Do not cut a larger hole or leave an outer pin in air. Some 100 mm blocks also leave very little lateral clearance; check the sensing footprint rather than relying solely on rod length. A physically smaller substrate-specific probe may be a better fit.
2931

3032
## Coco / peat containers
3133

34+
![MT22 placement within a coco container](img/mt22-coco-placement.svg)
35+
3236
Measure at a recorded depth in the actual packed, rooted medium, away from the emitter stream, stem, drainage layer and container boundary. Map more than one depth or compare representative pots before choosing a standard position. The middle of the filled height is a possible initial comparison point, not a universal coco rule.
3337

3438
Where practical, place the sensor during filling and pack hydrated medium around all rods consistently without creating cavities or compacting a special dense pocket. On an established container, make a minimal side opening if the container design allows it and avoid repeated insertion through roots. A curved pot wall does not provide a flat 88 mm contact surface; verify full substrate contact along every rod instead of forcing the housing against the wall. Keep the chosen position fixed as moisture changes; coco shrinkage can create air gaps.
@@ -37,9 +41,9 @@ Different pot heights and media mixes need their own calibration and placement r
3741

3842
## Print and use the template
3943

40-
- Print A4, **Actual size / 100%**, with Fit, Shrink and browser headers/footers disabled.
41-
- Measure both perpendicular 100 mm scale bars. Aim for no more than 0.5 mm discrepancy; reject a scaled print.
42-
- Select the correct slab-height page. Align the base datum with the bottom face of the rockwool.
44+
- The fixed slab PDF uses A4. The calculator generates A4 or US Letter sheets for your selected dimensions and units. Print **Actual size / 100%**, with Fit, Shrink and browser headers/footers disabled.
45+
- Measure both perpendicular check bars: 100 mm in metric or 4 in in imperial. Aim for no more than 0.5 mm (0.02 in) discrepancy; reject a scaled print.
46+
- Select the correct slab-height page. Align the base datum with the bottom of the medium. For a custom sheet marked Tall container, first mark the chosen height with a ruler and align its centreline; that sheet has no base datum.
4347
- Transfer your actual sensor's three pin positions onto the printed centreline using scrap backing. Remove the paper before final insertion; do not drill oversized holes in the substrate.
4448
- The printed 88 × 26 mm outline locates the housing. It does not calibrate VWC or prove the chosen location is representative.
4549

docs/VALIDATION.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ Use **ESPHome 2026.8.2**. Source checks, compiled host tests and firmware builds
66

77
```sh
88
pip install esphome==2026.8.2 PyYAML==6.0.2
9-
node --test tests/calculator.test.js
9+
node --test tests/calculator.test.js tests/wizard.test.js
10+
python tests/test_generated_configs.py --compile
1011
python tests/test_firmware.py
1112
python tests/test_repository.py
1213
python tests/check_configs.py
@@ -25,7 +26,7 @@ The setup tests run the same JavaScript used in the page. They cover real Hugo d
2526

2627
Open `tools/setup/index.html` from an extracted download and verify it without a network connection. Check cube-only, cube-on-slab, slab-only and coco calculations; invalid input must clear the previous answer. Add a weighed record and download the CSV. Check the layout at desktop and phone widths.
2728

28-
The supplied two-page PDF has A4 pages and a dimensioned 88 × 26 mm face. The custom print sheet uses an A4 SVG in physical millimetres, including perpendicular 100 mm scale bars. PDF geometry checks cannot compensate for a printer driver scaling the page: always measure both bars on the physical print.
29+
The supplied two-page PDF has A4 pages and a dimensioned 88 × 26 mm face. The custom template supports A4 and US Letter, with physical SVG geometry in millimetres regardless of display units. Its perpendicular check bars are 100 mm in metric mode or 4 inches in imperial mode. Tall containers use a ruler-marked centreline instead of pretending the entire height fits on one page. PDF geometry checks cannot compensate for a printer driver scaling the page: always measure both bars on the physical print.
2930

3031
## What remains a field check
3132

@@ -45,3 +46,24 @@ There is no automatic deployment or flashing step in these checks. A successful
4546
- Browser interaction checks passed for all four systems, preset/custom edits, gallons, tapered pots, invalid inputs, weighed calculations, CSV download, desktop/phone layout and a custom A4 print sheet.
4647
- The custom printed PDF had one A4 page; its contact-face rectangle measured 87.999 × 26.000 mm in PDF coordinates. Physical printer scaling still requires the two ruler checks.
4748
- No firmware was installed on a physical node and no Home Assistant or irrigation settings were changed. Consult the PR checks for the final five-board CI build result.
49+
50+
## Calculator and calibration wizard
51+
52+
The wizard checks substrate geometry, unit conversion, manual wet-reference records,
53+
and weighed A/B/C records before generating a configuration. It uses the same
54+
soilless response fit as the firmware, including 0.1% sensor-input rounding and
55+
independent C bounds. Changing sample geometry, placement or tare invalidates
56+
recorded references; changing display units preserves their canonical values.
57+
58+
`test_generated_configs.py` exercises 15 real exports: five boards, each with no
59+
calibration, a wet reference, or a checked A/B/C import. It validates them against
60+
ESPHome and their pinned remote packages using temporary dummy secrets. `--compile`
61+
also builds the Atom Lite weighed-reference export, including the generated C++
62+
import action. The Pages deployment waits for this check and the site build.
63+
64+
Browser verification covers unit round trips, US and UK container presets, sample
65+
volume updates, undersized cubes, wet and weighed workflows, rejected C points,
66+
YAML/report/CSV downloads, reload and project import, reference invalidation,
67+
responsive layouts and a one-page Letter template (612 × 792 PDF points).
68+
The browser checks entered data. It cannot verify the physical sensor's capture
69+
window, identity, contact or live readiness.

docs/img/mt22-coco-placement.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)