wirestudio 0.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wirestudio-0.10.0/LICENSE +21 -0
- wirestudio-0.10.0/PKG-INFO +563 -0
- wirestudio-0.10.0/README.md +540 -0
- wirestudio-0.10.0/pyproject.toml +57 -0
- wirestudio-0.10.0/setup.cfg +4 -0
- wirestudio-0.10.0/tests/test_active_design.py +304 -0
- wirestudio-0.10.0/tests/test_agent.py +355 -0
- wirestudio-0.10.0/tests/test_api.py +356 -0
- wirestudio-0.10.0/tests/test_ascii_gen.py +141 -0
- wirestudio-0.10.0/tests/test_compatibility.py +307 -0
- wirestudio-0.10.0/tests/test_design_events.py +139 -0
- wirestudio-0.10.0/tests/test_designs.py +180 -0
- wirestudio-0.10.0/tests/test_designs_seed.py +185 -0
- wirestudio-0.10.0/tests/test_enclosure.py +126 -0
- wirestudio-0.10.0/tests/test_enclosure_search.py +211 -0
- wirestudio-0.10.0/tests/test_fleet.py +463 -0
- wirestudio-0.10.0/tests/test_kicad.py +232 -0
- wirestudio-0.10.0/tests/test_kicad_import.py +167 -0
- wirestudio-0.10.0/tests/test_library_rtttl.py +91 -0
- wirestudio-0.10.0/tests/test_mcp_auth.py +122 -0
- wirestudio-0.10.0/tests/test_mcp_resources.py +206 -0
- wirestudio-0.10.0/tests/test_mcp_server.py +249 -0
- wirestudio-0.10.0/tests/test_pin_solver.py +283 -0
- wirestudio-0.10.0/tests/test_recommend.py +265 -0
- wirestudio-0.10.0/tests/test_schema.py +34 -0
- wirestudio-0.10.0/tests/test_serve.py +82 -0
- wirestudio-0.10.0/tests/test_tools_add_bus.py +90 -0
- wirestudio-0.10.0/tests/test_yaml_gen.py +653 -0
- wirestudio-0.10.0/wirestudio/__init__.py +3 -0
- wirestudio-0.10.0/wirestudio/agent/__init__.py +8 -0
- wirestudio-0.10.0/wirestudio/agent/agent.py +313 -0
- wirestudio-0.10.0/wirestudio/agent/session.py +65 -0
- wirestudio-0.10.0/wirestudio/agent/tools.py +518 -0
- wirestudio-0.10.0/wirestudio/api/__init__.py +3 -0
- wirestudio-0.10.0/wirestudio/api/__main__.py +45 -0
- wirestudio-0.10.0/wirestudio/api/app.py +884 -0
- wirestudio-0.10.0/wirestudio/api/schemas.py +236 -0
- wirestudio-0.10.0/wirestudio/api/serve.py +73 -0
- wirestudio-0.10.0/wirestudio/csp/__init__.py +20 -0
- wirestudio-0.10.0/wirestudio/csp/compatibility.py +414 -0
- wirestudio-0.10.0/wirestudio/csp/pin_solver.py +521 -0
- wirestudio-0.10.0/wirestudio/designs/__init__.py +11 -0
- wirestudio-0.10.0/wirestudio/designs/active.py +36 -0
- wirestudio-0.10.0/wirestudio/designs/events.py +108 -0
- wirestudio-0.10.0/wirestudio/designs/seed.py +200 -0
- wirestudio-0.10.0/wirestudio/designs/store.py +129 -0
- wirestudio-0.10.0/wirestudio/enclosure/__init__.py +30 -0
- wirestudio-0.10.0/wirestudio/enclosure/openscad.py +195 -0
- wirestudio-0.10.0/wirestudio/enclosure/search.py +217 -0
- wirestudio-0.10.0/wirestudio/examples/__init__.py +1 -0
- wirestudio-0.10.0/wirestudio/examples/attic-logger.json +82 -0
- wirestudio-0.10.0/wirestudio/examples/awning-control.json +158 -0
- wirestudio-0.10.0/wirestudio/examples/bl0906-mainmeter.json +67 -0
- wirestudio-0.10.0/wirestudio/examples/bluemotion.json +97 -0
- wirestudio-0.10.0/wirestudio/examples/bluesonoff.json +77 -0
- wirestudio-0.10.0/wirestudio/examples/desk-climate.json +69 -0
- wirestudio-0.10.0/wirestudio/examples/desk-matrix.json +72 -0
- wirestudio-0.10.0/wirestudio/examples/distance-sensor.json +119 -0
- wirestudio-0.10.0/wirestudio/examples/esp32-audio.json +124 -0
- wirestudio-0.10.0/wirestudio/examples/garage-motion.json +90 -0
- wirestudio-0.10.0/wirestudio/examples/keypad.json +86 -0
- wirestudio-0.10.0/wirestudio/examples/multi-temp.json +98 -0
- wirestudio-0.10.0/wirestudio/examples/nextion-thermostat.json +86 -0
- wirestudio-0.10.0/wirestudio/examples/oled.json +87 -0
- wirestudio-0.10.0/wirestudio/examples/parking-distance.json +75 -0
- wirestudio-0.10.0/wirestudio/examples/rc522.json +132 -0
- wirestudio-0.10.0/wirestudio/examples/room-climate.json +81 -0
- wirestudio-0.10.0/wirestudio/examples/rs485-energy.json +72 -0
- wirestudio-0.10.0/wirestudio/examples/securitypanel.json +151 -0
- wirestudio-0.10.0/wirestudio/examples/smart-plug-v1.json +84 -0
- wirestudio-0.10.0/wirestudio/examples/smart-plug.json +87 -0
- wirestudio-0.10.0/wirestudio/examples/ttgo-lora32.json +136 -0
- wirestudio-0.10.0/wirestudio/examples/tuya-smart-plug.json +97 -0
- wirestudio-0.10.0/wirestudio/examples/wasserpir.json +79 -0
- wirestudio-0.10.0/wirestudio/examples/weather-station.json +95 -0
- wirestudio-0.10.0/wirestudio/examples/wemosgps.json +101 -0
- wirestudio-0.10.0/wirestudio/fleet/__init__.py +4 -0
- wirestudio-0.10.0/wirestudio/fleet/client.py +266 -0
- wirestudio-0.10.0/wirestudio/generate/__init__.py +4 -0
- wirestudio-0.10.0/wirestudio/generate/__main__.py +48 -0
- wirestudio-0.10.0/wirestudio/generate/ascii_gen.py +114 -0
- wirestudio-0.10.0/wirestudio/generate/yaml_gen.py +321 -0
- wirestudio-0.10.0/wirestudio/kicad/__init__.py +5 -0
- wirestudio-0.10.0/wirestudio/kicad/generator.py +331 -0
- wirestudio-0.10.0/wirestudio/kicad/import.py +11 -0
- wirestudio-0.10.0/wirestudio/kicad/importer.py +232 -0
- wirestudio-0.10.0/wirestudio/kicad/symbol_parser.py +152 -0
- wirestudio-0.10.0/wirestudio/library/__init__.py +198 -0
- wirestudio-0.10.0/wirestudio/library/boards/esp01_1m.yaml +30 -0
- wirestudio-0.10.0/wirestudio/library/boards/esp32-c3-devkitm-1.yaml +53 -0
- wirestudio-0.10.0/wirestudio/library/boards/esp32-devkitc-v4.yaml +83 -0
- wirestudio-0.10.0/wirestudio/library/boards/esp32-s3-devkitc-1.yaml +77 -0
- wirestudio-0.10.0/wirestudio/library/boards/esp32-wrover-cam.yaml +71 -0
- wirestudio-0.10.0/wirestudio/library/boards/esp32cam-ai-thinker.yaml +78 -0
- wirestudio-0.10.0/wirestudio/library/boards/esp8285-1m.yaml +45 -0
- wirestudio-0.10.0/wirestudio/library/boards/m5stack-atom.yaml +49 -0
- wirestudio-0.10.0/wirestudio/library/boards/m5stack-atoms3.yaml +67 -0
- wirestudio-0.10.0/wirestudio/library/boards/nodemcu-32s.yaml +72 -0
- wirestudio-0.10.0/wirestudio/library/boards/nodemcu-v2.yaml +60 -0
- wirestudio-0.10.0/wirestudio/library/boards/ttgo-lora32-v1.yaml +91 -0
- wirestudio-0.10.0/wirestudio/library/boards/ttgo-t-beam.yaml +75 -0
- wirestudio-0.10.0/wirestudio/library/boards/wemos-d1-mini.yaml +67 -0
- wirestudio-0.10.0/wirestudio/library/components/adc.yaml +71 -0
- wirestudio-0.10.0/wirestudio/library/components/ads1115.yaml +61 -0
- wirestudio-0.10.0/wirestudio/library/components/ads1115_channel.yaml +69 -0
- wirestudio-0.10.0/wirestudio/library/components/aht10.yaml +63 -0
- wirestudio-0.10.0/wirestudio/library/components/apa102.yaml +66 -0
- wirestudio-0.10.0/wirestudio/library/components/bh1750.yaml +54 -0
- wirestudio-0.10.0/wirestudio/library/components/bl0906.yaml +97 -0
- wirestudio-0.10.0/wirestudio/library/components/bme280.yaml +51 -0
- wirestudio-0.10.0/wirestudio/library/components/bmp180.yaml +53 -0
- wirestudio-0.10.0/wirestudio/library/components/bmp280.yaml +61 -0
- wirestudio-0.10.0/wirestudio/library/components/cc1101.yaml +77 -0
- wirestudio-0.10.0/wirestudio/library/components/cse7766.yaml +58 -0
- wirestudio-0.10.0/wirestudio/library/components/dht.yaml +54 -0
- wirestudio-0.10.0/wirestudio/library/components/ds18b20.yaml +63 -0
- wirestudio-0.10.0/wirestudio/library/components/esp32_camera.yaml +103 -0
- wirestudio-0.10.0/wirestudio/library/components/esp32_rmt_led_strip.yaml +59 -0
- wirestudio-0.10.0/wirestudio/library/components/gpio_input.yaml +61 -0
- wirestudio-0.10.0/wirestudio/library/components/gpio_output.yaml +51 -0
- wirestudio-0.10.0/wirestudio/library/components/hc-sr04.yaml +55 -0
- wirestudio-0.10.0/wirestudio/library/components/hc-sr501.yaml +52 -0
- wirestudio-0.10.0/wirestudio/library/components/hlw8012.yaml +79 -0
- wirestudio-0.10.0/wirestudio/library/components/htu21d.yaml +53 -0
- wirestudio-0.10.0/wirestudio/library/components/hx711.yaml +60 -0
- wirestudio-0.10.0/wirestudio/library/components/ili9xxx.yaml +78 -0
- wirestudio-0.10.0/wirestudio/library/components/lcd_pcf8574.yaml +59 -0
- wirestudio-0.10.0/wirestudio/library/components/ld2420.yaml +57 -0
- wirestudio-0.10.0/wirestudio/library/components/max31855.yaml +58 -0
- wirestudio-0.10.0/wirestudio/library/components/max7219.yaml +62 -0
- wirestudio-0.10.0/wirestudio/library/components/max98357a.yaml +46 -0
- wirestudio-0.10.0/wirestudio/library/components/mcp23008.yaml +50 -0
- wirestudio-0.10.0/wirestudio/library/components/mcp23017.yaml +50 -0
- wirestudio-0.10.0/wirestudio/library/components/modbus.yaml +62 -0
- wirestudio-0.10.0/wirestudio/library/components/mpu6050.yaml +72 -0
- wirestudio-0.10.0/wirestudio/library/components/nextion.yaml +73 -0
- wirestudio-0.10.0/wirestudio/library/components/pcf8574.yaml +60 -0
- wirestudio-0.10.0/wirestudio/library/components/pulse_counter.yaml +70 -0
- wirestudio-0.10.0/wirestudio/library/components/rc522.yaml +51 -0
- wirestudio-0.10.0/wirestudio/library/components/rcwl-0516.yaml +49 -0
- wirestudio-0.10.0/wirestudio/library/components/rdm6300.yaml +43 -0
- wirestudio-0.10.0/wirestudio/library/components/rf_bridge.yaml +41 -0
- wirestudio-0.10.0/wirestudio/library/components/rotary_encoder.yaml +76 -0
- wirestudio-0.10.0/wirestudio/library/components/rtttl.yaml +52 -0
- wirestudio-0.10.0/wirestudio/library/components/sdm_meter.yaml +82 -0
- wirestudio-0.10.0/wirestudio/library/components/sht3xd.yaml +58 -0
- wirestudio-0.10.0/wirestudio/library/components/ssd1306.yaml +55 -0
- wirestudio-0.10.0/wirestudio/library/components/st7789.yaml +72 -0
- wirestudio-0.10.0/wirestudio/library/components/sx127x.yaml +90 -0
- wirestudio-0.10.0/wirestudio/library/components/tm1638.yaml +56 -0
- wirestudio-0.10.0/wirestudio/library/components/tsl2561.yaml +66 -0
- wirestudio-0.10.0/wirestudio/library/components/tuya.yaml +66 -0
- wirestudio-0.10.0/wirestudio/library/components/tuya_sensor.yaml +60 -0
- wirestudio-0.10.0/wirestudio/library/components/tuya_switch.yaml +53 -0
- wirestudio-0.10.0/wirestudio/library/components/uart_gps.yaml +41 -0
- wirestudio-0.10.0/wirestudio/library/components/vl53l0x.yaml +72 -0
- wirestudio-0.10.0/wirestudio/library/components/ws2812b.yaml +53 -0
- wirestudio-0.10.0/wirestudio/library/components/xpt2046.yaml +65 -0
- wirestudio-0.10.0/wirestudio/mcp/__init__.py +20 -0
- wirestudio-0.10.0/wirestudio/mcp/auth.py +114 -0
- wirestudio-0.10.0/wirestudio/mcp/server.py +528 -0
- wirestudio-0.10.0/wirestudio/model.py +153 -0
- wirestudio-0.10.0/wirestudio/recommend/__init__.py +8 -0
- wirestudio-0.10.0/wirestudio/recommend/recommender.py +223 -0
- wirestudio-0.10.0/wirestudio/schema/__init__.py +1 -0
- wirestudio-0.10.0/wirestudio/schema/design.schema.json +213 -0
- wirestudio-0.10.0/wirestudio/validate.py +26 -0
- wirestudio-0.10.0/wirestudio.egg-info/PKG-INFO +563 -0
- wirestudio-0.10.0/wirestudio.egg-info/SOURCES.txt +171 -0
- wirestudio-0.10.0/wirestudio.egg-info/dependency_links.txt +1 -0
- wirestudio-0.10.0/wirestudio.egg-info/entry_points.txt +3 -0
- wirestudio-0.10.0/wirestudio.egg-info/requires.txt +14 -0
- wirestudio-0.10.0/wirestudio.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 esphome-studio contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: wirestudio
|
|
3
|
+
Version: 0.10.0
|
|
4
|
+
Summary: Agent-driven IoT device design tool that produces ESPHome YAML.
|
|
5
|
+
Author: wirestudio contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: pydantic>=2.6
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
12
|
+
Requires-Dist: jsonschema>=4.21
|
|
13
|
+
Requires-Dist: jinja2>=3.1
|
|
14
|
+
Requires-Dist: fastapi>=0.110
|
|
15
|
+
Requires-Dist: uvicorn[standard]>=0.27
|
|
16
|
+
Requires-Dist: anthropic>=0.40
|
|
17
|
+
Requires-Dist: httpx>=0.27
|
|
18
|
+
Requires-Dist: slowapi>=0.1.9
|
|
19
|
+
Requires-Dist: mcp>=1.27
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
22
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
23
|
+
|
|
24
|
+
# wirestudio
|
|
25
|
+
|
|
26
|
+
Agent-driven IoT device design tool. Describe a goal (or pick parts);
|
|
27
|
+
get ESPHome YAML, an ASCII wiring diagram, and a BOM that compile
|
|
28
|
+
under upstream ESPHome.
|
|
29
|
+
|
|
30
|
+
Produces ESPHome configs but is not affiliated with the ESPHome
|
|
31
|
+
project — see [`weirded/fleet-for-esphome`](https://github.com/weirded/fleet-for-esphome)
|
|
32
|
+
for the OTA-deploy companion this studio's **Push to fleet** flow
|
|
33
|
+
talks to.
|
|
34
|
+
|
|
35
|
+
## Status
|
|
36
|
+
|
|
37
|
+
`v0.9.0` — first tagged release. The studio has wide surface area
|
|
38
|
+
(YAML, schematic, enclosure, agent, fleet handoff, web UI) and a
|
|
39
|
+
narrow set of things actually verified against upstream tools. This
|
|
40
|
+
section is honest about which is which, ordered by how much it
|
|
41
|
+
matters that it works.
|
|
42
|
+
|
|
43
|
+
Tiers, in priority order:
|
|
44
|
+
|
|
45
|
+
| Tier | Area | What it does | Verified by |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| **Verified** | ESPHome YAML production | render `design.json` → ESPHome YAML | `esphome config` passes on every bundled example, every PR ([gate](.github/workflows/esphome-config.yml)); nightly `esphome compile` smoke against a representative example ([compile](.github/workflows/esphome-compile.yml)) |
|
|
48
|
+
| **Verified** | CSP pin solver + compat checker | assign legal pins, surface boot-strap / ADC2-WiFi / voltage / locked-pin issues | unit tests + property checks in `tests/test_pin_solver.py` + `tests/test_compatibility.py` |
|
|
49
|
+
| **Verified** | Fleet handoff | push YAML to `fleet-for-esphome` ha-addon, optional compile + log relay | round-trip tests in `tests/test_fleet.py` |
|
|
50
|
+
| **Works (lighter checks)** | KiCad schematic | emit a SKiDL Python script the user runs locally | unit tests assert the script is well-formed Python with expected nets; **not** verified by opening in KiCad |
|
|
51
|
+
| **Works (lighter checks)** | Parametric enclosure | OpenSCAD `.scad` from board mount-hole metadata | unit tests + manual-print iteration; not verified by an OpenSCAD parser in CI |
|
|
52
|
+
| **Experimental** | Thingiverse search relay | rank community models for a board | smoke-tested; depends on a third-party search API that ranks unevenly |
|
|
53
|
+
| **Experimental** | Agent (Claude tool-using) | natural-language design driving | works in practice; tool surface is small; no auto-eval against task list yet |
|
|
54
|
+
| **Deferred** | KiCad PCB layout | Freerouting + Gerber + JLCPCB CPL/BOM | 1.0+, not started |
|
|
55
|
+
|
|
56
|
+
The **Verified** tier is the bar the project is asking to be judged
|
|
57
|
+
on. Everything else is offered with the caveat that's spelled out in
|
|
58
|
+
the table.
|
|
59
|
+
|
|
60
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the bar a change has to
|
|
61
|
+
clear before merging, [`CHANGELOG.md`](CHANGELOG.md) for per-release
|
|
62
|
+
deltas, and [`START.md`](START.md) for the longer-form design notes.
|
|
63
|
+
|
|
64
|
+
Tested against ESPHome **`==2025.12.7`** (pinned in
|
|
65
|
+
`.github/workflows/esphome-config.yml` + bumped deliberately). When
|
|
66
|
+
that pin moves, this line moves with it.
|
|
67
|
+
|
|
68
|
+
## What it does
|
|
69
|
+
|
|
70
|
+
- **Design.** Web UI inspector (board, fleet metadata, components,
|
|
71
|
+
buses, connections, requirements, warnings). Add components by
|
|
72
|
+
picking a capability (**Add by function**) — the recommender ranks
|
|
73
|
+
library matches against use cases. Drag-and-drop pinout for
|
|
74
|
+
component-to-board pin assignment. Pin locks per role. Bus editor
|
|
75
|
+
with rename propagation + inline compatibility warnings. USB
|
|
76
|
+
bootstrap from a plugged-in ESP via WebSerial + esptool-js. Saved
|
|
77
|
+
designs at `designs/<id>.json` with a **Saved** tab + **New design**
|
|
78
|
+
dialog.
|
|
79
|
+
- **Validate.** CSP pin solver assigns every unbound connection with
|
|
80
|
+
capability-aware fallback (boot strap pins de-prioritised; ADC1
|
|
81
|
+
preferred over ADC2 on classic ESP32). Port-compatibility checker
|
|
82
|
+
flags input-only-as-output errors, boot-strap risks, serial console
|
|
83
|
+
reuse, voltage limits, ADC2/WiFi conflicts, locked-pin mismatches.
|
|
84
|
+
Strict mode (header toggle) promotes warn/error compat to render
|
|
85
|
+
errors as a pre-deploy gate.
|
|
86
|
+
- **Generate.** Pure functions over `design.json` + the static
|
|
87
|
+
library produce ESPHome YAML, ASCII wiring diagrams + BOM, a
|
|
88
|
+
parametric OpenSCAD enclosure (`.scad`), and a SKiDL Python script
|
|
89
|
+
the user runs locally to produce a `.kicad_sch`. Bundled examples
|
|
90
|
+
pinned as goldens.
|
|
91
|
+
- **Deploy.** **Push to fleet** ships the YAML to a running
|
|
92
|
+
[`weirded/fleet-for-esphome`](https://github.com/weirded/fleet-for-esphome)
|
|
93
|
+
ha-addon over Bearer-token HTTP; optional `compile: true` enqueues
|
|
94
|
+
an OTA build with live log streaming (Server-Sent Events). **Strict
|
|
95
|
+
mode** refuses the push when warn/error compat issues remain.
|
|
96
|
+
- **Discover enclosures.** Generate a parametric `.scad` shell from
|
|
97
|
+
the board's mount-hole + USB-port metadata, or search community
|
|
98
|
+
models on Thingiverse (`THINGIVERSE_API_KEY`).
|
|
99
|
+
- **Self-host.** Single multi-arch Docker image
|
|
100
|
+
(`linux/amd64` + `linux/arm64`). FastAPI serves API + SPA from one
|
|
101
|
+
process. Kubernetes manifest, docker-compose recipe, and an nginx
|
|
102
|
+
production layout in [`deploy/`](deploy/).
|
|
103
|
+
|
|
104
|
+
## Quickstart
|
|
105
|
+
|
|
106
|
+
### Docker (single-image deployment)
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
docker run --rm -p 8765:8765 \
|
|
110
|
+
-e ANTHROPIC_API_KEY=sk-ant-... \
|
|
111
|
+
-v wirestudio-data:/data \
|
|
112
|
+
ghcr.io/moellere/wirestudio:v0.9.0
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Open <http://localhost:8765>. The image bundles the FastAPI server +
|
|
116
|
+
the built web UI in one process; `/api/*` is the JSON API,
|
|
117
|
+
`/` is the SPA. `/data` holds the agent's session log + saved
|
|
118
|
+
designs across upgrades.
|
|
119
|
+
|
|
120
|
+
Available tags:
|
|
121
|
+
|
|
122
|
+
| Tag | What it tracks |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `:v0.9.0` / `:0.9.0` / `:0.9` / `:latest` | the v0.9.0 release |
|
|
125
|
+
| `:main` | latest commit on `main` (rolling) |
|
|
126
|
+
| `:sha-<short>` | a specific commit |
|
|
127
|
+
|
|
128
|
+
All four feature-gating env vars are optional — the studio runs
|
|
129
|
+
without any of them, just with the corresponding feature turned off:
|
|
130
|
+
|
|
131
|
+
| Env var | What it gates |
|
|
132
|
+
|---|---|
|
|
133
|
+
| `ANTHROPIC_API_KEY` | the agent (`/agent/*` endpoints + the chat sidebar) |
|
|
134
|
+
| `FLEET_URL` + `FLEET_TOKEN` | fleet-for-esphome push (`/fleet/*`) |
|
|
135
|
+
| `THINGIVERSE_API_KEY` | enclosure search (`/enclosure/search`) |
|
|
136
|
+
|
|
137
|
+
For Kubernetes, see [`deploy/k8s.yaml`](deploy/k8s.yaml). For an
|
|
138
|
+
nginx-front compose recipe, see [`deploy/README.md`](deploy/README.md).
|
|
139
|
+
|
|
140
|
+
### CLI
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
pip install -e .[dev]
|
|
144
|
+
python -m wirestudio.generate examples/garage-motion.json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Prints rendered YAML and the ASCII wiring block to stdout. To write to files:
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
python -m wirestudio.generate examples/garage-motion.json \
|
|
151
|
+
--out-yaml build/garage-motion.yaml \
|
|
152
|
+
--out-ascii build/garage-motion.txt
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### HTTP API
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
python -m wirestudio.api # localhost:8765
|
|
159
|
+
python -m wirestudio.api --reload # dev mode (auto-reload on edits)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Browse the auto-generated OpenAPI docs at <http://127.0.0.1:8765/docs>.
|
|
163
|
+
|
|
164
|
+
To enable the **agent** endpoints (`/agent/turn`, `/agent/sessions/{id}`),
|
|
165
|
+
export an Anthropic API key before starting the server:
|
|
166
|
+
|
|
167
|
+
```sh
|
|
168
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
169
|
+
python -m wirestudio.api
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Without a key, `/agent/status` reports `available: false` and the agent
|
|
173
|
+
sidebar in the UI shows a friendly notice instead of trying to talk.
|
|
174
|
+
|
|
175
|
+
To enable the **fleet handoff** (`/fleet/push` and the **Push to fleet**
|
|
176
|
+
header button), point the API at a running fleet-for-esphome ha-addon:
|
|
177
|
+
|
|
178
|
+
```sh
|
|
179
|
+
export FLEET_URL=http://homeassistant.local:8765
|
|
180
|
+
export FLEET_TOKEN=$(grep -oP '(?<=token: )\S+' .../addon/secrets.yaml)
|
|
181
|
+
python -m wirestudio.api
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`GET /fleet/status` reports `available: true` when both env vars are set
|
|
185
|
+
and the addon answers a probe; otherwise the UI surfaces the specific
|
|
186
|
+
reason (URL missing, unauthorized, unreachable).
|
|
187
|
+
|
|
188
|
+
### MCP server
|
|
189
|
+
|
|
190
|
+
The studio's design-editing tools are also exposed over the
|
|
191
|
+
[Model Context Protocol](https://modelcontextprotocol.io) at `/mcp`.
|
|
192
|
+
Point Claude Code or Claude Desktop at the daemon and the model drives
|
|
193
|
+
the studio on your Claude subscription — no Anthropic key, no studio-side
|
|
194
|
+
token spend. See [`docs/MCP.md`](docs/MCP.md) for the end-to-end setup.
|
|
195
|
+
|
|
196
|
+
### Web UI (dev)
|
|
197
|
+
|
|
198
|
+
```sh
|
|
199
|
+
# In one terminal:
|
|
200
|
+
python -m wirestudio.api
|
|
201
|
+
|
|
202
|
+
# In another:
|
|
203
|
+
cd web && npm install && npm run dev
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Open <http://localhost:5173>. Vite proxies `/api/*` to the studio API,
|
|
207
|
+
so no CORS plumbing in dev. The same web UI is served at `/` from the
|
|
208
|
+
production Docker image; the dev server is only useful when you're
|
|
209
|
+
editing UI code yourself.
|
|
210
|
+
|
|
211
|
+
Inspector surfaces:
|
|
212
|
+
|
|
213
|
+
- **Design pane** — board picker, fleet metadata (device_name, tags,
|
|
214
|
+
secrets refs), requirements, warnings, components list (add /
|
|
215
|
+
remove with auto-wiring), buses (add / rename / edit pin slots /
|
|
216
|
+
remove), per-bus + design-level compatibility warnings.
|
|
217
|
+
- **Component-instance pane** — params (form generated from each
|
|
218
|
+
library entry's `params_schema`), connections (per-row editor with
|
|
219
|
+
rail / gpio / bus / expander_pin / component target kinds),
|
|
220
|
+
Form ⇄ Pinout view toggle for drag-and-drop pin assignment, 🔓/🔒
|
|
221
|
+
per-row pin lock.
|
|
222
|
+
|
|
223
|
+
Header buttons: **New design**, **Reset**, **Save**, **Download JSON**,
|
|
224
|
+
**Solve pins**, **strict** (toggle), **Connect device** (USB
|
|
225
|
+
bootstrap), **Add by function** (capability picker), **Schematic**
|
|
226
|
+
(KiCad export), **Enclosure** (parametric `.scad` + Thingiverse
|
|
227
|
+
search), **Push to fleet**.
|
|
228
|
+
|
|
229
|
+
Useful endpoints:
|
|
230
|
+
|
|
231
|
+
| Method | Path | What it does |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| `GET` | `/library/boards` | summaries of every board in the library |
|
|
234
|
+
| `GET` | `/library/boards/{id}` | full board, including pinout |
|
|
235
|
+
| `GET` | `/library/components?category=&use_case=&bus=` | filtered component summaries |
|
|
236
|
+
| `GET` | `/library/components/{id}` | full component, including ESPHome template |
|
|
237
|
+
| `GET` | `/library/use_cases` | distinct capabilities across the library, with counts; powers the **Add by function** picker |
|
|
238
|
+
| `POST` | `/library/recommend` | rank library components against a free-text or capability query |
|
|
239
|
+
| `POST` | `/design/validate` | parse a `design.json`, return summary or 422 |
|
|
240
|
+
| `POST` | `/design/render` | parse + render a `design.json` to `{yaml, ascii}` |
|
|
241
|
+
| `POST` | `/design/enclosure/openscad` | generate a parametric `.scad` shell for the design's board |
|
|
242
|
+
| `POST` | `/design/kicad/schematic` | generate a SKiDL Python script the user runs locally to produce a `.kicad_sch` |
|
|
243
|
+
| `GET` | `/enclosure/search?library_id=...&query=...` | search community-uploaded enclosure models (Thingiverse) |
|
|
244
|
+
| `GET` | `/enclosure/search/status` | per-source availability + configure hints |
|
|
245
|
+
| `GET` | `/examples` | list bundled examples |
|
|
246
|
+
| `GET` | `/examples/{id}` | fetch an example as raw `design.json` |
|
|
247
|
+
| `GET` | `/fleet/status` | check whether `FLEET_URL` + `FLEET_TOKEN` reach a fleet-for-esphome ha-addon |
|
|
248
|
+
| `POST` | `/fleet/push` | render `design.json` and push it as `<device_name>.yaml` (optionally `compile: true`) |
|
|
249
|
+
| `GET` | `/fleet/jobs/{run_id}/log?offset=N` | poll the addon's build log for a compile run; returns `{log, offset, finished}` |
|
|
250
|
+
| `GET` | `/fleet/jobs/{run_id}/log/stream` | Server-Sent Events relay over the same log endpoint; ~300ms cadence, exits with `event: done` when the build finishes |
|
|
251
|
+
|
|
252
|
+
The HTTP API is a thin layer over the studio's pure-function modules
|
|
253
|
+
(`wirestudio.generate`, `wirestudio.csp`, `wirestudio.recommend`, `wirestudio.fleet`,
|
|
254
|
+
`wirestudio.enclosure`, `wirestudio.kicad`). Server state is limited to the
|
|
255
|
+
agent session log + the saved-design store — both file-backed under
|
|
256
|
+
`/data` (via `SESSIONS_DIR` / `DESIGNS_DIR`). Permissive CORS for
|
|
257
|
+
`localhost:5173` / `localhost:3000` so the dev Vite server can hit
|
|
258
|
+
it without a proxy.
|
|
259
|
+
|
|
260
|
+
## Examples
|
|
261
|
+
|
|
262
|
+
| Example | Board | What it is |
|
|
263
|
+
|---|---|---|
|
|
264
|
+
| [`garage-motion.json`](examples/garage-motion.json) | ESP32-DevKitC-V4 | PIR + BME280 (temp/humidity/pressure) over I2C |
|
|
265
|
+
| [`awning-control.json`](examples/awning-control.json) | WeMos D1 Mini | Cover controller — 4 limit switches + buttons via MCP23008 expander, 2 GPIO relays, dual-PWM motor drive |
|
|
266
|
+
| [`wasserpir.json`](examples/wasserpir.json) | WeMos D1 Mini | Single PIR with a scheduled nightly reboot |
|
|
267
|
+
| [`oled.json`](examples/oled.json) | WeMos D1 Mini | SSD1306 status display rendering time, date, IP |
|
|
268
|
+
| [`bluemotion.json`](examples/bluemotion.json) | WeMos D1 Mini | PIR + WS2812B NeoPixel; motion lights the LED |
|
|
269
|
+
| [`distance-sensor.json`](examples/distance-sensor.json) | NodeMCU v2 | HC-SR04 ultrasonic + WS2812B NeoPixel; LED color tracks distance |
|
|
270
|
+
| [`securitypanel.json`](examples/securitypanel.json) | WeMos D1 Mini | 12 door/window/motion sensors via MCP23017 expander, RTTTL piezo, GPIO siren |
|
|
271
|
+
| [`rc522.json`](examples/rc522.json) | WeMos D1 Mini | MFRC522 RFID reader (SPI), NeoPixel status LED, RTTTL piezo, manual button |
|
|
272
|
+
| [`esp32-audio.json`](examples/esp32-audio.json) | NodeMCU-32S | I2S audio (MAX98357A DAC) + ST7789V SPI dashboard display, Arduino framework |
|
|
273
|
+
| [`bluesonoff.json`](examples/bluesonoff.json) | ESP-01S 1MB | Sonoff Basic relay; front button (boot strap pin) toggles a single GPIO relay |
|
|
274
|
+
| [`wemosgps.json`](examples/wemosgps.json) | WeMos D1 Mini | UART GPS module — lat/lon/altitude/speed/satellites + runtime baud-rate selector |
|
|
275
|
+
| [`ttgo-lora32.json`](examples/ttgo-lora32.json) | TTGO LoRa32 V1 | ESP32 + onboard SX1276 LoRa radio + onboard SSD1306 OLED + battery ADC, ESP-IDF |
|
|
276
|
+
| [`multi-temp.json`](examples/multi-temp.json) | WeMos D1 Mini | Two DS18B20 temp sensors sharing a single 1-wire bus + an RCWL-0516 microwave motion sensor |
|
|
277
|
+
| [`room-climate.json`](examples/room-climate.json) | WeMos D1 Mini | BH1750 ambient-light + AHT20 temp/humidity on one I2C bus |
|
|
278
|
+
| [`desk-climate.json`](examples/desk-climate.json) | ESP32-C3-DevKitM-1 | Sensirion SHT3x precision temp/humidity over I2C |
|
|
279
|
+
| [`parking-distance.json`](examples/parking-distance.json) | NodeMCU v2 | VL53L0X laser ToF distance (indoor parking-spot indicator) |
|
|
280
|
+
| [`keypad.json`](examples/keypad.json) | WeMos D1 Mini | 8 buttons read through a PCF8574 GPIO expander over I2C |
|
|
281
|
+
| [`smart-plug.json`](wirestudio/examples/smart-plug.json) | ESP8285 1MB | Athom-style smart plug — relay + button + CSE7766 AC power metering over UART 4800 8E1 |
|
|
282
|
+
| [`smart-plug-v1.json`](wirestudio/examples/smart-plug-v1.json) | ESP8285 1MB | Older Athom v1 / Sonoff POW R1 plug — same topology with the HLW8012 / BL0937 3-pin pulse meter |
|
|
283
|
+
| [`desk-matrix.json`](wirestudio/examples/desk-matrix.json) | ESP32-DevKitC | 8x8 WS2812 matrix driven by the ESP32 RMT peripheral (no bit-banging) |
|
|
284
|
+
| [`rs485-energy.json`](wirestudio/examples/rs485-energy.json) | ESP32-DevKitC-V4 | Eastron SDM230 single-phase energy meter via Modbus RTU (UART2 + MAX485 transceiver, GPIO5 drives DE+RE) |
|
|
285
|
+
| [`bl0906-mainmeter.json`](wirestudio/examples/bl0906-mainmeter.json) | ESP32-DevKitC-V4 | BL0906 6-channel CT-clamp energy monitor over UART2 (Athom EM6-style whole-home sub-metering) |
|
|
286
|
+
| [`nextion-thermostat.json`](wirestudio/examples/nextion-thermostat.json) | ESP32-DevKitC-V4 | Nextion HMI thermostat panel — display on UART2 + SHT3xD temp/humidity on default I2C |
|
|
287
|
+
| [`tuya-smart-plug.json`](wirestudio/examples/tuya-smart-plug.json) | ESP8285 1MB | Tuya-MCU smart plug — relay (DP 1) + power (DP 17) + energy (DP 18) over UART 9600; logger off UART0 |
|
|
288
|
+
| [`weather-station.json`](wirestudio/examples/weather-station.json) | ESP32-DevKitC-V4 | BMP280 barometer + HTU21D temp/humidity + TSL2561 lux on one shared I2C bus |
|
|
289
|
+
| [`attic-logger.json`](wirestudio/examples/attic-logger.json) | WeMos D1 Mini | DHT22 single-wire temp/humidity + legacy BMP180 I2C barometer |
|
|
290
|
+
|
|
291
|
+
Generated artifacts for each are pinned as goldens in
|
|
292
|
+
[`tests/golden/`](tests/golden/). For a per-component / per-board view of
|
|
293
|
+
which library entries are exercised by these examples, see
|
|
294
|
+
[`docs/library-coverage.md`](docs/library-coverage.md) (regenerate with
|
|
295
|
+
`python scripts/coverage_matrix.py`).
|
|
296
|
+
|
|
297
|
+
## Architecture
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
design.json ── single source of truth (JSON-Schema-validated)
|
|
301
|
+
│
|
|
302
|
+
▼
|
|
303
|
+
┌─ wirestudio.model pydantic models mirroring the schema
|
|
304
|
+
├─ wirestudio.library loads boards/ + components/ YAML
|
|
305
|
+
├─ wirestudio.generate design + library → ESPHome YAML + ASCII
|
|
306
|
+
├─ wirestudio.csp pin solver + port-compatibility checker
|
|
307
|
+
├─ wirestudio.recommend deterministic capability ranking
|
|
308
|
+
├─ wirestudio.agent Claude tool-using agent + session store
|
|
309
|
+
├─ wirestudio.designs file-backed designs/<id>.json store
|
|
310
|
+
├─ wirestudio.fleet fleet-for-esphome HTTP client
|
|
311
|
+
├─ wirestudio.enclosure parametric OpenSCAD + Thingiverse search
|
|
312
|
+
├─ wirestudio.kicad SKiDL Python script emitter
|
|
313
|
+
└─ wirestudio.api FastAPI HTTP layer (mounts everything above)
|
|
314
|
+
serve.py adds the production wrapper:
|
|
315
|
+
API at /api/*, web bundle at /
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Generators are pure functions of `design.json` + the static library — no
|
|
319
|
+
artifact-to-document round-trips. Library files in `library/components/`
|
|
320
|
+
carry the electrical metadata ESPHome doesn't (pin roles, voltage ranges,
|
|
321
|
+
current draw, decoupling caps, pull-up requirements) plus a Jinja2 template
|
|
322
|
+
that renders the ESPHome YAML for that component, an `enclosure:` block
|
|
323
|
+
the OpenSCAD generator reads, and a `kicad:` block the schematic exporter
|
|
324
|
+
reads.
|
|
325
|
+
|
|
326
|
+
## Library
|
|
327
|
+
|
|
328
|
+
Currently shipped:
|
|
329
|
+
|
|
330
|
+
**Boards** (`library/boards/`)
|
|
331
|
+
- `esp32-devkitc-v4` — ESP32 DevKitC V4 (ESP32-WROOM-32, 4MB flash)
|
|
332
|
+
- `nodemcu-32s` — NodeMCU-32S (ESP32-WROOM-32, marks I2S-capable pins)
|
|
333
|
+
- `ttgo-lora32-v1` — LilyGO TTGO LoRa32 V1 (ESP32 + onboard SX1276 + onboard SSD1306)
|
|
334
|
+
- `ttgo-t-beam` — LilyGO TTGO T-Beam v1.x (ESP32 + onboard SX1276 + NEO-6M GPS + AXP192 PMIC + 18650)
|
|
335
|
+
- `esp32-c3-devkitm-1` — ESP32-C3-DevKitM-1 (single-core RISC-V, USB-Serial-JTAG, onboard WS2812)
|
|
336
|
+
- `esp32-s3-devkitc-1` — ESP32-S3-DevKitC-1 (dual-core Xtensa, native USB, onboard WS2812)
|
|
337
|
+
- `esp32cam-ai-thinker` — AI-Thinker ESP32-CAM (ESP32-WROVER-B + OV2640 + microSD)
|
|
338
|
+
- `esp32-wrover-cam` — ESP32-WROVER-CAM (Freenove-style, OV2640 with the WROVER pinout)
|
|
339
|
+
- `m5stack-atom` — M5Stack Atom Lite / Echo (ESP32-PICO-D4, 24mm cube, onboard SK6812)
|
|
340
|
+
- `m5stack-atoms3` — M5Stack AtomS3 (ESP32-S3 + onboard 0.85" 128×128 ST7789 + IMU)
|
|
341
|
+
- `wemos-d1-mini` — WeMos D1 Mini (ESP-12F module, ESP8266)
|
|
342
|
+
- `nodemcu-v2` — NodeMCU v2 (ESP-12E/F module, ESP8266, breaks out RX/TX/MISO/MOSI as D9-D12)
|
|
343
|
+
- `esp01_1m` — ESP-01S 1MB module / Sonoff Basic-class devices
|
|
344
|
+
- `esp8285-1m` — Generic ESP8285 1MB SoC (Athom / Sonoff Basic R3+ / Tuya smart plugs)
|
|
345
|
+
|
|
346
|
+
**Components** (`library/components/`)
|
|
347
|
+
|
|
348
|
+
_Environmental sensors:_
|
|
349
|
+
- `bme280` — Bosch temperature/humidity/pressure sensor (I2C)
|
|
350
|
+
- `bmp180` — Bosch BMP180/BMP085 barometric pressure + temperature (I2C)
|
|
351
|
+
- `bmp280` — Bosch temperature/pressure sensor (I2C, no humidity)
|
|
352
|
+
- `dht` — DHT11 / DHT22 / AM2302 temperature + humidity (single-wire)
|
|
353
|
+
- `htu21d` — TE Connectivity HTU21D temperature + humidity (I2C; covers Si7021 / SHT2x)
|
|
354
|
+
- `sht3xd` — Sensirion SHT3x / SHT4x precision temp + humidity (I2C; modern default)
|
|
355
|
+
- `aht10` — Aosong AHT10 / AHT20 cheap temp + humidity (I2C; AliExpress weather modules)
|
|
356
|
+
- `ds18b20` — Dallas DS18B20 1-Wire temperature sensor (single-pin bus + 4.7kΩ pull-up)
|
|
357
|
+
- `bh1750` — BH1750FVI ambient light sensor in lux (I2C; GY-30 / GY-302 modules)
|
|
358
|
+
|
|
359
|
+
_Specialty sensors:_
|
|
360
|
+
- `max31855` — Maxim K-type thermocouple amplifier (SPI; -270..+1372°C)
|
|
361
|
+
- `hx711` — AVIA 24-bit load-cell ADC (custom 2-wire serial)
|
|
362
|
+
- `tsl2561` — AMS ambient light sensor (lux, I2C)
|
|
363
|
+
- `mpu6050` — InvenSense 6-axis IMU (3-axis accel + 3-axis gyro + die temp, I2C)
|
|
364
|
+
|
|
365
|
+
_Presence / distance:_
|
|
366
|
+
- `hc-sr04` — ultrasonic distance sensor (4-pin: VCC, GND, TRIGGER, ECHO)
|
|
367
|
+
- `hc-sr501` — PIR motion sensor (used as a generic PIR)
|
|
368
|
+
- `rcwl-0516` — microwave doppler motion sensor (low-power PIR alternative)
|
|
369
|
+
- `ld2420` — Hi-Link LD2420 24GHz mmWave presence sensor (UART)
|
|
370
|
+
- `vl53l0x` — STMicro VL53L0X laser time-of-flight distance (I2C; indoor up to ~1.2m)
|
|
371
|
+
|
|
372
|
+
_RFID / radios:_
|
|
373
|
+
- `rc522` — MFRC522 RFID reader (SPI, singleton)
|
|
374
|
+
- `rdm6300` — RDM6300 125kHz EM4100 RFID reader (UART, singleton)
|
|
375
|
+
- `sx127x` — Semtech SX1276/SX1278 LoRa radio (SPI, singleton)
|
|
376
|
+
- `cc1101` — TI CC1101 sub-GHz transceiver (SPI, singleton)
|
|
377
|
+
- `rf_bridge` — Sonoff RF Bridge 433MHz EFM8 module (UART, singleton)
|
|
378
|
+
|
|
379
|
+
_Displays:_
|
|
380
|
+
- `ssd1306` — 128×64 OLED (I2C)
|
|
381
|
+
- `st7789` — Sitronix ST7789V color TFT (SPI write-only)
|
|
382
|
+
- `ili9xxx` — ILI9341 / ILI9486 / ILI9488 SPI TFT
|
|
383
|
+
- `lcd_pcf8574` — HD44780 16x2 / 20x4 LCD via PCF8574 I2C backpack
|
|
384
|
+
- `tm1638` — TM1638 8-digit 7-segment + 8 LEDs + 8 buttons combo
|
|
385
|
+
- `max7219` — MAX7219 7-segment / 8x8 LED matrix driver (SPI)
|
|
386
|
+
|
|
387
|
+
_Touch / input:_
|
|
388
|
+
- `xpt2046` — XPT2046 resistive touchscreen controller (SPI)
|
|
389
|
+
- `rotary_encoder` — Quadrature rotary encoder (KY-040 style)
|
|
390
|
+
|
|
391
|
+
_IO expanders + ADC hubs:_
|
|
392
|
+
- `mcp23008` — 8-bit I2C GPIO expander (Microchip)
|
|
393
|
+
- `mcp23017` — 16-bit I2C GPIO expander (Microchip)
|
|
394
|
+
- `pcf8574` — NXP PCF8574 / PCF8575 8-/16-bit I2C GPIO expander (cheap, weak open-drain)
|
|
395
|
+
- `ads1115` — TI 4-channel 16-bit ADC (I2C) hub; rescues ESP32 designs from the ADC2/WiFi conflict
|
|
396
|
+
- `ads1115_channel` — one logical reading on an ADS1115 hub (multiplexer + gain + update_interval per channel)
|
|
397
|
+
|
|
398
|
+
_Generic IO:_
|
|
399
|
+
- `gpio_input` — generic binary_sensor on a GPIO or expander pin (buttons, limit switches, door/window/motion sensors)
|
|
400
|
+
- `gpio_output` — generic switch on a GPIO or expander pin (relays, indicators)
|
|
401
|
+
- `adc` — generic analog input (battery monitoring, potentiometers, LDRs)
|
|
402
|
+
- `pulse_counter` — pulse counter / tachometer (RPM, flow, energy meters)
|
|
403
|
+
|
|
404
|
+
_Light / audio / camera:_
|
|
405
|
+
- `ws2812b` — WS2812B / SK6812 addressable RGB LED (1-wire NeoPixel; bit-banged or ESP8266-DMA)
|
|
406
|
+
- `esp32_rmt_led_strip` — same WS2812 / SK6812 silicon, ESP32 RMT-driven (preferred on ESP32 / S2 / S3 / C3)
|
|
407
|
+
- `apa102` — APA102 / SK9822 addressable RGB strip (DotStar, SPI-style)
|
|
408
|
+
- `max98357a` — Maxim Class-D mono I2S amp + DAC
|
|
409
|
+
- `rtttl` — piezo buzzer + RTTTL melody player (PWM output)
|
|
410
|
+
- `esp32_camera` — ESP32 OV2640 / OV7670 / OV5640 camera
|
|
411
|
+
|
|
412
|
+
_Power metering:_
|
|
413
|
+
- `cse7766` — Chipsea AC voltage / current / power / energy over UART 4800 8E1 (Athom v2/c3 + Sonoff plugs)
|
|
414
|
+
- `hlw8012` — HLW8012 / BL0937 / CSE7759 AC power meter via 3-pin pulse interface (older Athom v1 + Sonoff POW R1)
|
|
415
|
+
- `bl0906` — Belling 6-channel AC energy meter over UART 19200 (Athom EM6 / whole-home sub-metering)
|
|
416
|
+
- `modbus` + `sdm_meter` — Modbus RTU bus (RS485 via MAX485 transceiver) + Eastron SDM120/220/230/630 single/three-phase DIN-rail meter
|
|
417
|
+
|
|
418
|
+
_Vendor bridges:_
|
|
419
|
+
- `tuya` + `tuya_switch` + `tuya_sensor` — Tuya MCU UART bridge plus per-datapoint switch and sensor platforms (smart plugs / switches / climate gadgets that ship with an ESP8266-class radio talking to a separate Tuya MCU)
|
|
420
|
+
|
|
421
|
+
_Displays (HMI):_
|
|
422
|
+
- `nextion` — Nextion HMI smart display over UART 9600 (T/K/P series; .tft uploaded separately via Nextion Editor)
|
|
423
|
+
|
|
424
|
+
_Location:_
|
|
425
|
+
- `uart_gps` — generic UART GPS module (NEO-6M / NEO-8M)
|
|
426
|
+
|
|
427
|
+
The `gpio_input` / `gpio_output` components and the `kind: expander_pin`
|
|
428
|
+
connection target together let downstream platforms hang off any expander
|
|
429
|
+
without bloating `esphome_extras`. See `examples/securitypanel.json` for a
|
|
430
|
+
12-sensor MCP23017 wiring or `examples/awning-control.json` for a mix of
|
|
431
|
+
expander inputs and outputs.
|
|
432
|
+
|
|
433
|
+
The library now spans the device classes used across the
|
|
434
|
+
[`moellere/esphome`](https://github.com/moellere/esphome) device
|
|
435
|
+
configurations (camera boards, mmWave presence, sub-GHz radios,
|
|
436
|
+
character LCDs, touchscreens, generic ADC and pulse counters,
|
|
437
|
+
addressable LEDs, RTTTL piezo, RFID variants, and the M5Stack /
|
|
438
|
+
ESP32-C3 / ESP32-S3 board family). It will keep growing as new device
|
|
439
|
+
configs land. See
|
|
440
|
+
[`START.md` § Library sourcing strategy](START.md#library-sourcing-strategy)
|
|
441
|
+
for the hybrid plan.
|
|
442
|
+
|
|
443
|
+
## Layout
|
|
444
|
+
|
|
445
|
+
```
|
|
446
|
+
schema/ JSON Schema for design.json (source of truth)
|
|
447
|
+
library/boards/ board manifests (pinout, rails, framework, enclosure, kicad)
|
|
448
|
+
library/components/ component manifests (electrical + ESPHome + enclosure + kicad)
|
|
449
|
+
wirestudio/ python package — see Architecture above for the module map
|
|
450
|
+
web/ React 19 + Vite + Tailwind v4 SPA
|
|
451
|
+
examples/ bundled design.json files (every one pinned by goldens)
|
|
452
|
+
tests/ pytest + golden artifacts; vitest tests under web/src
|
|
453
|
+
deploy/ k8s.yaml, docker-compose.yml, nginx.conf for self-hosting
|
|
454
|
+
Dockerfile multi-stage build for the published GHCR image
|
|
455
|
+
.github/workflows/ GHA workflow that publishes ghcr.io/.../wirestudio
|
|
456
|
+
scripts/ dev helpers (currently: examples → `esphome config` gate)
|
|
457
|
+
CHANGELOG.md per-release feature deltas
|
|
458
|
+
START.md vision, decisions, phase plan
|
|
459
|
+
CLAUDE.md working conventions for both Claude and humans
|
|
460
|
+
CONTRIBUTING.md substantive bar a change has to clear (the YAML gate, etc.)
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Tests
|
|
464
|
+
|
|
465
|
+
```sh
|
|
466
|
+
python -m pytest # ~297 cases, ~10s
|
|
467
|
+
python -m ruff check . # lint
|
|
468
|
+
cd web && npx vitest run # ~125 cases, ~5s (vitest + jsdom)
|
|
469
|
+
pip install 'esphome==2025.12.7'
|
|
470
|
+
python scripts/check_examples.py # the YAML gate -- every example through `esphome config`
|
|
471
|
+
python scripts/check_examples.py --compile garage-motion # the compile-smoke; slow (~10min cold)
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
The `esphome config` gate is the headline test: it renders every
|
|
475
|
+
bundled example through the studio and runs upstream ESPHome's own
|
|
476
|
+
validator against the output. Anything the studio emits has to
|
|
477
|
+
round-trip through that gate, and the GitHub Actions workflow
|
|
478
|
+
([`.github/workflows/esphome-config.yml`](.github/workflows/esphome-config.yml))
|
|
479
|
+
runs it on every PR. A nightly compile-smoke
|
|
480
|
+
([`.github/workflows/esphome-compile.yml`](.github/workflows/esphome-compile.yml))
|
|
481
|
+
goes one level deeper -- it runs `esphome compile` against a
|
|
482
|
+
representative example so we catch upstream toolchain / codegen
|
|
483
|
+
regressions even when no code has changed.
|
|
484
|
+
|
|
485
|
+
To run the same gate before every push, install the pre-commit
|
|
486
|
+
hooks once:
|
|
487
|
+
|
|
488
|
+
```sh
|
|
489
|
+
pip install pre-commit
|
|
490
|
+
pre-commit install --hook-type pre-push
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
After that, `git push` runs the gate locally and aborts on failure.
|
|
494
|
+
|
|
495
|
+
Golden tests pin the generator output for every bundled example.
|
|
496
|
+
Regenerate goldens with the CLI when output legitimately changes;
|
|
497
|
+
commit the new files in the same diff as the code change. The web
|
|
498
|
+
suite covers `lib/design.ts` plus React components (BusList,
|
|
499
|
+
ConnectionForm, EnclosureDialog, Inspector, CapabilityPickerDialog,
|
|
500
|
+
PinoutView, PushToFleetDialog, SchematicDialog) via React Testing
|
|
501
|
+
Library + jsdom; network surfaces are mocked at the api/client
|
|
502
|
+
boundary so the suite stays offline.
|
|
503
|
+
|
|
504
|
+
The GitHub Actions workflow runs the YAML gate + the full suite +
|
|
505
|
+
multi-arch image build on every PR + merge to main.
|
|
506
|
+
|
|
507
|
+
## Roadmap
|
|
508
|
+
|
|
509
|
+
Reorganised by priority — what's worth working on next, ordered by
|
|
510
|
+
how much it raises the floor on whether the studio is actually
|
|
511
|
+
useful. The previous "ship more surface area" roadmap is preserved
|
|
512
|
+
in [`CHANGELOG.md`](CHANGELOG.md) (per-release deltas) and
|
|
513
|
+
[`START.md`](START.md) (decisions + phase scope).
|
|
514
|
+
|
|
515
|
+
**Priority 1 — YAML production correctness.** *Active.* The single
|
|
516
|
+
non-negotiable bar: every artifact the studio emits round-trips
|
|
517
|
+
through upstream `esphome config`. Done so far: `esphome config` CI
|
|
518
|
+
gate over every bundled example; pinned ESPHome version called out
|
|
519
|
+
in this README + workflow; CONTRIBUTING.md establishes the gate as
|
|
520
|
+
the merge bar. Next: real `esphome compile` smoke for one example;
|
|
521
|
+
component-coverage matrix (which components have an example that
|
|
522
|
+
validates) so additions are forced through the gate.
|
|
523
|
+
|
|
524
|
+
**Priority 2 — Wiring schema correctness.** *Verified-light.* SKiDL
|
|
525
|
+
emitter + 100% library `kicad:` coverage shipped. Honest gap: the
|
|
526
|
+
output is unit-tested as Python text, not opened in KiCad. Next:
|
|
527
|
+
container-side KiCad CLI in CI to actually open + render the
|
|
528
|
+
generated schematic; pin-solver property tests on randomized
|
|
529
|
+
designs; compatibility-checker fuzzing.
|
|
530
|
+
|
|
531
|
+
**Priority 3 — Enclosures.** *Lower priority.* Parametric OpenSCAD
|
|
532
|
+
generator + Thingiverse search relay shipped. Open question: keep
|
|
533
|
+
investing here, or outsource to e.g.
|
|
534
|
+
[YAPP_Box](https://github.com/mrWheel/YAPP_Box) and integrate
|
|
535
|
+
instead of reimplementing? Decision deferred until P1 + P2 are
|
|
536
|
+
tighter.
|
|
537
|
+
|
|
538
|
+
**Priority 4 — PCB layout.** *Deferred to 1.0+.* No work in flight;
|
|
539
|
+
not adding surface here until P1 is rock solid.
|
|
540
|
+
|
|
541
|
+
**Plumbing — already shipped.** API (`0.2`), web UI (`0.3` +
|
|
542
|
+
`0.6+`), USB bootstrap (`0.4`), agent (`0.5` + streaming), CSP
|
|
543
|
+
solver (`0.6`), fleet handoff (`0.7`), enclosure (`0.8`), KiCad
|
|
544
|
+
schematic (`0.9`), Docker single-image deploy + K8s manifest. See
|
|
545
|
+
[`CHANGELOG.md`](CHANGELOG.md) for the per-release feature deltas.
|
|
546
|
+
|
|
547
|
+
**Future** — multi-writer state backend so the studio can run as a
|
|
548
|
+
HA replica; agent eval harness against a task list; ESPHome version
|
|
549
|
+
matrix in CI (last 2 stables) so we can call out which components
|
|
550
|
+
work where.
|
|
551
|
+
|
|
552
|
+
## Contributing
|
|
553
|
+
|
|
554
|
+
[`CONTRIBUTING.md`](CONTRIBUTING.md) is the substantive bar — what
|
|
555
|
+
"working" means for the artifacts the studio produces, including
|
|
556
|
+
the `esphome config` gate every PR has to clear. [`CLAUDE.md`](CLAUDE.md)
|
|
557
|
+
covers the prose / commit / comment conventions (concise, no emojis,
|
|
558
|
+
default-to-no-comments, boundary-only validation, no premature
|
|
559
|
+
abstraction).
|
|
560
|
+
|
|
561
|
+
## License
|
|
562
|
+
|
|
563
|
+
MIT. See [`LICENSE`](LICENSE).
|