sondwave
LINK UP · UDP/47808

Make the wire visible

plug into the BAS networkthe site draws itselfwalk out with a tagged point list

read-only by default — safe to point at a live site
01 DISCOVERY

No dead
loaders

plug in, watch every controller answer — or say why it didn't. querying · responding · enumerating · timed-out · segmentation-reject, by name.

AHU-140/40responding · 12 ms
VAV-204enumerating12/40
MTR-Main18/18responding · 31 ms
CTRL-7via MS/TPquerying · 3.2 s
RTU-3large RPMsegmentation-reject
FCU-119no I-Amtimed-out · 5 s
02 TOPOLOGY

The trunk others miss

most tools flatten the site to a list of IPs. you get the real shape — MS/TP devices behind the router, on the right wire, weighted by latency.

◉ site:HQ — 3 nets · 214 points ├─ net:1 BACnet/IP backbone // 8–40 ms │ ├─ ▸ AHU-1 ahu · 0.94 │ │ ├─ discharge-air-temp 54.6 °F │ │ ├─ supply-fan-cmd on │ │ └─ mixed-air-damper 38 % │ ├─ ▸ CH-1 chiller · 0.91 │ └─ ▸ MTR-Main elecMeter · 0.88 ├─ net:12 MS/TP trunk // 9600 baud · 240–900 ms ⚠ │ ├─ ▸ VAV-201..214 vav · ×14 │ └─ ▸ FCU-1..8 fcu · ×8 └─ net:20 Modbus RTU gw // unit 1–12 └─ ▸ PWR-Panel meter · pm5560
AHU VAV Chiller FCU Meter Net / trunk Live value
03 TAGS

Named for you

every point tagged and typed on discovery — the naming you'd do by hand, done for you. Haystack-native, offline, corrections stick.

1Protocol-nativenames · units · present-value
2Rules & dictionariesdeterministic · on-box
3Embeddingsoffline-capable
4Cloud LLMClaude · when connected
point · zinc
@p:1a4f dis:"Discharge Air Temp"
  point sensor temp air discharge
  equipRef:@e:AHU-1  siteRef:@s:HQ
  unit:"°F"  kind:"Number"
  curVal:54.6  curStatus:"ok"
  bacnetCur:"AI:3.presentValue"
source rules 0.00 ▸ correct inline → flywheel
04 EXPORT

Walk out
with it

the point schedule you hand the office — select on the canvas, export in place. no re-typing, no per-point fee.

CSV Zinc Haystack-JSON
HQ-survey.csv · 214 points
id,dis,equip,net,unit,curVal,tags
@p:1a4f,Discharge Air Temp,AHU-1,1,°F,54.6,point sensor temp air discharge
@p:2b7c,Supply Fan Cmd,AHU-1,1,,on,point cmd fan
@p:3d19,Mixed Air Damper,AHU-1,1,%,38,point cmd damper
@p:5f22,Zone Temp,VAV-204,12,°F,71.2,point sensor temp air zone
@p:7a04,kW Demand,MTR-Main,1,kW,48.6,point sensor power elec
… 209 more · 3 formats · one click
05 DRIVERS

Every wire on the floor

BACnet, Modbus, MQTT — one process each. a wedged protocol stack can't take the rest down.

BACnet

flagship
IP · MS/TP · BBMD · foreign-device · wraps bacnet-stack
discoverread · RPMCOVwrite

Modbus

TCP · RTU · templated register maps
readblock-coalescewritetemplates

MQTT

south ingest · north publish
subscribepublishtopic-map

OPC-UA

planned
browsereadsubscribe
06 HARDWARE

Runs on a Pi

fanless · offline · one static binary · fits in your bag

<0 MB
RAM at idle
0k pts
polled @ 15 s
on a Pi 4
<0 s
cold start
0 MB
static binary
SPEC

No asterisks

Safetyread-only by default · writes off, audited, priority-scoped
Licensingno per-point fees — connect as many as the box can carry
Deploymentoffline / air-gapped, first class · no telemetry
ModelHaystack-native — not an export step
Isolationone process per protocol · crash alone, restart alone
Formcarry it · plug in · go
for integrators & OEMs

Build on top of it

everything the field tool does, the same daemon serves over an API — REST + WebSocket, described by OpenAPI, token-authed. the UI is just a client. embed the whole engine in your product.

GET /v1 — sondwave northbound
$ curl -H "Authorization: Bearer $TOKEN" edge.local/v1/devices
{ "id":"@d:AHU-1", "proto":"bacnet", "net":1, "points":40, "status":"ok", "latencyMs":12 }

$ websocat wss://edge.local/v1/ws
 { "ev":"i-am",   "dev":"@d:VAV-204", "ms":47 }
 { "ev":"cur",    "pt":"@p:1a4f",  "val":54.6 }
 { "ev":"tagged", "pt":"@p:1a4f",  "conf":0.93 }
$ sondwaved --iface eth0

Every controller.
Before you leave the room.

Watch a scan See the export