Current section

Files

Jump to
zigbee examples pair_and_read.exs
Raw

examples/pair_and_read.exs

# pair_and_read.exs, end-to-end Zigbee demo
#
# Opens an EmberZNet dongle, forms a coordinator network, pairs ONE device, then
# prints its temperature / humidity reports live.
#
# Run it from the library root:
#
# mix run examples/pair_and_read.exs
#
# Configure with env vars (defaults shown):
#
# ZBT_DEVICE=/dev/ttyACM0 # serial port (macOS ZBT-2: /dev/cu.usbmodem…)
# ZBT_SPEED=460800 # baud (460800 for the ZBT-2; often 115200 elsewhere)
# ZBT_CHANNEL=15 # Zigbee channel, 11..26
# ZBT_WATCH=120 # seconds to watch for reports after pairing
device = System.get_env("ZBT_DEVICE", "/dev/ttyACM0")
speed = String.to_integer(System.get_env("ZBT_SPEED", "460800"))
channel = String.to_integer(System.get_env("ZBT_CHANNEL", "15"))
watch_ms = String.to_integer(System.get_env("ZBT_WATCH", "120")) * 1000
hex = fn bin ->
bin |> :binary.bin_to_list() |> Enum.map_join(":", &String.pad_leading(Integer.to_string(&1, 16), 2, "0"))
end
# 1. Open the radio (Silicon Labs EmberZNet backend) and subscribe for events.
IO.puts("Opening #{device} @ #{speed} baud…")
{:ok, zb} = Zigbee.start_link(Zigbee.EZSP.Adapter, device: device, speed: speed)
:ok = Zigbee.subscribe(zb, self())
IO.inspect(Zigbee.info(zb), label: "radio")
# 2. Form a coordinator network (also registers the default HA endpoint).
IO.puts("\nForming network on channel #{channel}…")
{:ok, params} = Zigbee.form_network(zb, channel: channel)
IO.puts(" network up: pan_id=0x#{Integer.to_string(params.pan_id, 16)} channel=#{params.channel}")
# 3. Open joining and wait for a device to join.
IO.puts("\n>>> Put your device into pairing mode now (join window open)…")
case Zigbee.Interview.open_and_wait(zb) do
{:ok, dev} ->
IO.puts(" joined: node=0x#{Integer.to_string(dev.node_id, 16)} eui64=#{hex.(dev.eui64)}")
# 4. Interview it: enumerate endpoints, bind + configure temp/humidity reporting.
IO.puts("\nInterviewing device…")
case Zigbee.Interview.run(zb, dev.node_id, dev.eui64) do
{:ok, summary} ->
IO.puts(" endpoints=#{inspect(summary.endpoints)} bindings=#{length(summary.bindings)}")
# 5. Print reports as they arrive (collect/2 returns a batch each window).
IO.puts("\nWatching reports for #{div(watch_ms, 1000)}s (Ctrl-C to stop)…")
deadline = System.monotonic_time(:millisecond) + watch_ms
stream = fn stream ->
if System.monotonic_time(:millisecond) < deadline do
for r <- Zigbee.Interview.collect(zb, 5_000) do
IO.puts(" #{Integer.to_string(r.cluster, 16)} ep#{r.endpoint}: #{r.value}#{r.unit}")
end
stream.(stream)
end
end
stream.(stream)
IO.puts("\nDone.")
err ->
IO.inspect(err, label: "interview failed")
end
{:error, :timeout} ->
IO.puts(" no device joined within the window, try again and press pair sooner.")
end