Minimal HA content to reproduce the Butterfly Rack GUI: a YAML-mode dashboard (power graphs in mW, temperature graph, dual dBm/mW output readout, staged seed/booster controls, emergency-off), MQTT template sensors deriving mW from the dBm telemetry, and an emergency-shutdown script. Snippets merge into configuration.yaml / scripts.yaml; the dashboard file is copied whole. See homeassistant/README.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
koheron-esp32-bridge
ESP32 firmware that bridges the Butterfly EDFA Rack — a 1550 nm MOPA: a Koheron CTL200 driving a DFB seed into an Agiltron M511 EYDFA power amplifier (output up to ~1 W / 30 dBm) — to WiFi/MQTT for monitoring and control from Home Assistant (broker 192.168.0.102:1883, anonymous).
The whole rack is presented as a single HA device (butterfly_edfa_rack). Topics, mirroring the lab's EDFA→MQTT convention:
lab/laser/butterfly_edfa_rack/availability online | offline (LWT)
lab/laser/butterfly_edfa_rack/diag/<key> ESP/network diagnostics
lab/laser/butterfly_edfa_rack/seed/<key> Koheron CTL200 (increment 3)
lab/laser/butterfly_edfa_rack/amp/<key> Agiltron M511 (increment 4)
lab/laser/butterfly_edfa_rack/set/<...> commands (increment 5)
HA discovery configs are published under homeassistant/..., all sharing one device block so entities group under the single rack device.
Optical architecture
The rack is a MOPA (master-oscillator power-amplifier) at 1550 nm:
Koheron CTL200 Agiltron M511 EYDFA (two-stage)
┌──────────────┐ ┌─────────────────────────────────────┐
│ DFB1550LP │ fibre │ pre-amp stage ──► booster stage │ fibre
│ seed diode ├─────────►│ (pump diode A) (pump diode B, ├────────► output
│ + TEC │ │ ~170 mA, ~16 dBm "pump-1") │ (up to ~1 W
└──────────────┘ └─────────────────────────────────────┘ / 30 dBm)
ilaser, lason input PD preamp PD output-1 PD
The M511 has two internal pump diodes, and the firmware reads both:
- Pre-amp pump — runs semi-independently at ~170 mA, lifts the seed to ~16 dBm (
amp/preamp_current_ma,amp/preamp_power_dbm). - Booster pump = "pump-1" — the controllable output stage (
amp/pump1_current_ma, set viaset/amp/pump1_current_ma). - "Pump-2" is a second booster channel that this unit leaves at 0 mA regardless of settings (per
Lab/Equipment/Lasers/Agiltron EDFA); we don't drive it. It is read but not exposed as a control.
Run the booster in ACC (constant-current) mode — APC stepping quantises the output. Below transparency the booster erbium fibre absorbs the pre-amp output, so output stays at the PD floor (−60 dBm) until the pump is high enough.
Pump-1 vs output characterisation (2026-06-17)
Two sweeps. The transparency sweep used ~6 mW (7.8 dBm) seed into the EDFA; the high-power sweep added a 3 dB pad (input 3.2 dBm, within the ≤5 dBm benchtop spec) and a direct output-to-power-meter connection.
| Pump-1 | Output-1 (internal PD) | note |
|---|---|---|
| 500–900 mA | −60 dBm | below transparency, signal absorbed |
| 1200 mA | 21.0 dBm | booster turns on |
| 1500 mA | 23.1 dBm | |
| 2000 mA | 25.9 dBm | |
| 2500 mA | 27.1 dBm / 514 mW | documented 0.5 W operating point |
| 3000 mA | 28.3 dBm / 679 mW | |
| 3500 mA | 29.3 dBm / 857 mW | |
| 4000 mA | 30.1 dBm / 1026 mW | 1 W rated ceiling |
| 4500 mA | 30.85 dBm / 1216 mW | over-rating; curve still ~linear (not saturated) |
The unit (factory APC setpoint 30 dBm) comfortably exceeds 1 W: 1.22 W at 4500 mA with the output still climbing ~0.74 dB/500 mA and module temp only ~30 °C — so its true saturated maximum is higher, but driving a 1 W-rated pump diode past rating trades lifetime for diminishing return. Pump current overshoots ~2× briefly on each step up and settles in 2–4 s, so ramp gradually rather than jumping to the setpoint.
Internal PD vs external power meter: at 4500 mA the internal PD reported 1.22 W while a Thorlabs meter measured 1.05 W at the output (~0.6 dB high / residual loss). Treat the
amp/output*_power_dbmtelemetry as indicative, ~0.5–0.6 dB optimistic, not a calibrated power reading. (The earlier lab notes saw the opposite sign through a different connection, so the offset is path-dependent.)
Safety: Class 4, >1 W, invisible 1550 nm. The firmware clamps pump-1 to
PUMP_CURRENT_MAX_MA(4000 mA ≈ the 1 W rating) and seed current toSEED_CURRENT_MAX_MA— guardrails against accidental over-drive, not interlocks. Above 1 W the Agiltron manual requires matched high-power connectors or a splice on the output, else the output fibre/amplifier can be damaged. Always drop the pump to 0 before unmating any fibre. Treat the output as hazardous unless it terminates in a power meter / beam dump.
Hardware
-
ESP32-D0WD-V3 dev board (WROOM-32 class), CP2102N USB bridge →
/dev/ttyUSB0, MACb0:cb:d8:8f:ba:10. -
The ESP32 USB port is used only for flashing/console (UART0).
-
Two instrument links on separate hardware UARTs:
ESP32 Instrument Protocol GPIO17 (TX2) → Koheron CTL200 RX (terminal block) ASCII, 115200 8N1, \r\n,>>promptGPIO16 (RX2) ← Koheron CTL200 TX GPIO26 (TX1) → Agiltron M511 RX (P2 pin 3) binary 0x55AA packets, 115200 8N1 GPIO25 (RX1) ← Agiltron M511 TX (P2 pin 7) GND both grounds All links are 3V3 logic (CTL200 is 5V-tolerant). UART1 is remapped off its default flash-clashing pins.
Network: the firmware pins a static IP
192.168.0.150(gateway.1, /24) — seeUSE_STATIC_IPininclude/config.h. This avoids the clash with the BKtel EDFA Pi on.101that a DHCP lease originally caused..150is outside any device documented in the HA notes; move it if your DHCP pool overlaps.
Toolchain
PlatformIO (Arduino framework), pinned in a project-local .venv so nothing is installed globally.
make # show targets
make build # compile
make upload # compile + flash (PORT=/dev/ttyUSB0 by default)
make monitor # serial console at 115200
make detect # identify the chip on the port
A fresh checkout self-bootstraps the venv on first make.
Configuration
Copy include/secrets.example.h → include/secrets.h (git-ignored) and fill in WiFi + MQTT details. Needed from increment 2 onward.
Increment roadmap
- 1 — toolchain check. Blink + serial heartbeat; confirms build/upload/monitor.
- 2 — WiFi + MQTT + HA discovery. Joins WiFi, connects to broker with an LWT availability topic, publishes diagnostic entities (uptime, RSSI, IP).
- 3 — Seed telemetry (read-only). UART2 → Koheron
lason/ilaser/vlaser/rtset/rtact/itec/vtec/tboard/iphd/err; published underseed/...as HA sensors. Verified live against CTL200 fw v0.21 (echo + value +>>framing, parsed correctly). - 4 — Amp telemetry (read-only). UART1 → Agiltron
get_status(binary 0x55AA, ported fromedfa.py); publishes module/pre-amp temp, pre-amp & pump-1 currents, input/pre-amp/output dBm, warnings underamp/.... Verified against the live unit (SN Y4022708, PN EDFA-1C51113331111, device ID 0x0000006F).amp/pump_enabledreads the authoritativeget_settingsfield. - 5 — control.
set/...for seed (lason,ilaser) and amp (pump on/off, pump-1 ACC current) as HA switch/number entities, with firmware current clamps. Verified end-to-end: MQTT command → seed lasing → booster ramp to 27 dBm. Seed TEC setpoint (rtset, in ohms) is also settable, with a read-only °C readout derived from the thermistor. (Future: seedtecon, amp APC power, Koheronsave.)
MQTT interface
State topics retained under lab/laser/butterfly_edfa_rack/:
| Topic suffix | Meaning |
|---|---|
availability |
online / offline (LWT) |
diag/{uptime,rssi,ip} |
ESP / network diagnostics |
seed/link |
Koheron reachable? |
seed/laser_enabled |
seed laser on (1/0) |
seed/current_ma, seed/voltage_v |
seed drive |
seed/rt_setpoint_ohm, seed/rt_actual_ohm |
thermistor setpoint / actual |
seed/temp_c |
seed diode temperature (from rt_actual via NTC β-model, indicative) |
seed/tec_current_a, seed/tec_voltage_v, seed/board_temp_c |
seed TEC / board |
seed/photodiode_ma, seed/error |
seed monitor PD, CTL200 error code |
amp/link |
Agiltron reachable? |
amp/module_temp_c, amp/preamp_temp_c |
EDFA temperatures |
amp/preamp_current_ma, amp/preamp_power_dbm |
pre-amp stage |
amp/pump1_current_ma, amp/pump1_set_ma |
booster pump actual / setpoint |
amp/input_power_dbm, amp/output1_power_dbm, amp/output2_power_dbm |
optical powers |
amp/pump_enabled, amp/warnings |
booster state, decoded warnings |
Command topics (publish to lab/laser/butterfly_edfa_rack/set/):
| Topic suffix | Payload | Action |
|---|---|---|
seed/laser |
1 / 0 |
Koheron lason |
seed/current_ma |
mA | Koheron ilaser (clamped ≤ SEED_CURRENT_MAX_MA) |
seed/rt_setpoint_ohm |
Ω | Koheron rtset, seed TEC setpoint (clamped SEED_RT_SETPOINT_MIN/MAX_OHM) |
amp/pump |
1 / 0 |
Agiltron pump on / off |
amp/pump1_current_ma |
mA | set ACC mode + pump-1 current (clamped ≤ PUMP_CURRENT_MAX_MA) |