Record the firmware version the 7777-flex devices report

46b785f · Gabriel Morell · 2026-09-16 21:00

11 files +123 -19
Message
{commit_body(@commit)}

Files changed

modified lib/lambent_ex/scan/8266-7777.ex
+35 −19
@@ -213,16 +213,16 @@ defmodule LambentEx.Scan.ESP8266x7777 do
213 213 end
214 214 end
215 215
216 − def handle_cast({:scan_results, iface, ip, count, ind}, state) do
217 − IO.inspect({"SR", iface, ip, count, ind})
216 + def handle_cast({:scan_results, iface, ip, count, ind, ver}, state) do
217 + IO.inspect({"SR", iface, ip, count, ind, ver})
218 218 if_fmt = Kernel.to_string(iface)
219 219 ip_fmt = ip |> String.split(".") |> Enum.map(&String.to_integer/1) |> List.to_tuple()
220 − instances = %{if_fmt => [{ip, count, ind}]}
220 + instances = %{if_fmt => [{ip, count, ind, ver}]}
221 221 arp = state[:arps] |> Map.get(if_fmt, %{}) |> Map.get(ip_fmt)
222 222
223 223 state =
224 224 case arp do
225 − nil -> %{state | to_arp: List.insert_at(state.to_arp, 0, {iface, ip, count, ind})}
225 + nil -> %{state | to_arp: List.insert_at(state.to_arp, 0, {iface, ip, count, ind, ver})}
226 226 _val -> join_new_instances_old(instances, state)
227 227 end
228 228
@@ -355,8 +355,8 @@ defmodule LambentEx.Scan.ESP8266x7777 do
355 355 case resp.status_code do
356 356 404 ->
357 357 case resp.body do
358 − "File not found." -> {:lambent, ip, 0, nil}
359 − _other -> {:not_lambent, ip, -1, nil}
358 + "File not found." -> {:lambent, ip, 0, nil, nil}
359 + _other -> {:not_lambent, ip, -1, nil, nil}
360 360 end
361 361
362 362 # esp32rs
@@ -364,17 +364,20 @@ defmodule LambentEx.Scan.ESP8266x7777 do
364 364 IO.inspect({"218@", ip})
365 365
366 366 case resp.body |> Poison.decode(keys: :atoms) do
367 − {:ok, json} -> {:lambent, ip, json.udp_sox |> length, indicator_port(json)}
368 − {:error, _error} -> {:not_lambent, ip, -1, nil}
367 + {:ok, json} ->
368 + {:lambent, ip, json.udp_sox |> length, indicator_port(json), version(json)}
369 +
370 + {:error, _error} ->
371 + {:not_lambent, ip, -1, nil, nil}
369 372 end
370 373
371 374 _other ->
372 − {:not_lambent, ip, -1, nil}
375 + {:not_lambent, ip, -1, nil, nil}
373 376 end
374 377
375 378 {:error, err} ->
376 379 if ip == "172.16.15.80", do: IO.inspect(err)
377 − {:not_lambent, ip, -1, nil}
380 + {:not_lambent, ip, -1, nil, nil}
378 381 end
379 382 end
380 383
@@ -387,6 +390,15 @@ defmodule LambentEx.Scan.ESP8266x7777 do
387 390 end
388 391 end
389 392
393 + # the firmware version string, for the versions table. older builds do not
394 + # advertise one at all, and anything non-string is not worth showing
395 + defp version(json) do
396 + case Map.get(json, :version) do
397 + ver when is_binary(ver) -> ver
398 + _otherwise -> nil
399 + end
400 + end
401 +
390 402 defp rgb_shift(stream, device) do
391 403 chunked = Enum.chunk_every(stream, 3)
392 404
@@ -442,8 +454,10 @@ defmodule LambentEx.Scan.ESP8266x7777 do
442 454
443 455 Task.Supervisor.async_nolink(LambentEx.Scan.Connectivity.Supervisor, fn ->
444 456 case query_http(ip) do
445 − {:lambent, ip, cnt, ind} ->
446 − via_tuple("scan_8266") |> GenServer.cast({:scan_results, iface, ip, cnt, ind})
457 + {:lambent, ip, cnt, ind, ver} ->
458 + via_tuple("scan_8266")
459 + |> GenServer.cast({:scan_results, iface, ip, cnt, ind, ver})
460 +
447 461 publish_manual(ip, {:lambent, cnt})
448 462
449 463 _otherwise ->
@@ -548,7 +562,7 @@ defmodule LambentEx.Scan.ESP8266x7777 do
548 562
549 563 state =
550 564 to_arp
551 − |> Enum.reduce(state, fn {if, ip, count, ind}, state ->
565 + |> Enum.reduce(state, fn {if, ip, count, ind, ver}, state ->
552 566 if_fmt = Kernel.to_string(if)
553 567 ip_fmt = ip |> String.split(".") |> Enum.map(&String.to_integer/1) |> List.to_tuple()
554 568 arp = state[:arps] |> Map.get(if_fmt, %{}) |> Map.get(ip_fmt)
@@ -558,9 +572,9 @@ defmodule LambentEx.Scan.ESP8266x7777 do
558 572 state
559 573
560 574 _val ->
561 − instances = %{if_fmt => [{ip, count, ind}]}
575 + instances = %{if_fmt => [{ip, count, ind, ver}]}
562 576 state = join_new_instances_old(instances, state)
563 − %{state | in_arp: state.in_arp |> List.insert_at(-1, {if, ip, count, ind})}
577 + %{state | in_arp: state.in_arp |> List.insert_at(-1, {if, ip, count, ind, ver})}
564 578 end
565 579 end)
566 580
@@ -623,8 +637,9 @@ defmodule LambentEx.Scan.ESP8266x7777 do
623 637 |> Enum.map(fn ip ->
624 638 Task.Supervisor.async_nolink(LambentEx.Scan.Connectivity.Supervisor, fn ->
625 639 case query_http(ip) do
626 − {:lambent, ip, cnt, ind} ->
627 − via_tuple("scan_8266") |> GenServer.cast({:scan_results, i, ip, cnt, ind})
640 + {:lambent, ip, cnt, ind, ver} ->
641 + via_tuple("scan_8266")
642 + |> GenServer.cast({:scan_results, i, ip, cnt, ind, ver})
628 643
629 644 _otherwise ->
630 645 :ok
@@ -722,7 +737,7 @@ defmodule LambentEx.Scan.ESP8266x7777 do
722 737 new
723 738 |> Enum.map(fn {if, arr} ->
724 739 arr
725 − |> Enum.map(fn {ip, sox, ind} ->
740 + |> Enum.map(fn {ip, sox, ind, ver} ->
726 741 ip = IP.from_string!(ip)
727 742 mac = Map.get(arps[if], ip)
728 743
@@ -730,7 +745,8 @@ defmodule LambentEx.Scan.ESP8266x7777 do
730 745 Map.get(devices, mac, %{})
731 746 |> Map.put("ip", ip)
732 747 |> Map.put("sox", sox)
733 − |> Map.put("ind", ind)}
748 + |> Map.put("ind", ind)
749 + |> Map.put("ver", ver)}
734 750 end)
735 751 |> Map.new()
736 752 end)
modified lib/lambent_ex_web/live/devices/index.html.heex
+3 −0
@@ -15,6 +15,9 @@
15 15 <span class="text-sm opacity-60">
16 16 Probes an address directly, for devices the network scan missed.
17 17 </span>
18 + <.link patch={~p"/cfg/devices/versions"} class="btn btn-ghost normal-case">
19 + <i class="fa-solid fa-code-branch"></i> Versions
20 + </.link>
18 21 </form>
19 22 <div class="hidden lg:block">
20 23 <table class="table table-zebra w-full">
added lib/lambent_ex_web/live/devices/versions.ex
+45 −0
@@ -0,0 +1,45 @@
1 +defmodule LambentExWeb.DevicesLive.Versions do
2 + use LambentExWeb, :live_view
3 + require Logger
4 +
5 + @pubsub_name LambentEx.PubSub
6 +
7 + @impl true
8 + def mount(_params, _session, socket) do
9 + Phoenix.PubSub.subscribe(@pubsub_name, "scan-82667777")
10 + {:ok, socket |> assign(:devices, %{}) |> assign(:nonew, true)}
11 + end
12 +
13 + @impl true
14 + def handle_params(params, _url, socket) do
15 + {:noreply, apply_action(socket, socket.assigns.live_action, params)}
16 + end
17 +
18 + @impl true
19 + def handle_info({:devices_pub, devices}, socket) do
20 + n = Map.merge(socket.assigns.devices, devices)
21 + {:noreply, socket |> assign(:devices, n)}
22 + end
23 +
24 + defp apply_action(socket, :index, _params) do
25 + socket
26 + |> assign(:page_link, "Devices")
27 + |> assign(:page_title, "Device Versions")
28 + |> assign(:source, nil)
29 + end
30 +
31 + # only the esp32rs firmware reports a version, so the legacy 8266s would just
32 + # be a wall of unknowns
33 + defp versioned(devices) do
34 + devices
35 + |> Enum.filter(fn {_k, v} -> v["type"] == "7777-flex" end)
36 + |> Enum.sort_by(fn {k, v} -> {v["ver"] || "", k} end)
37 + end
38 +
39 + defp pip(map) do
40 + case Map.get(map, "ip") do
41 + nil -> "-"
42 + ip -> ip |> Tuple.to_list() |> Enum.join(".")
43 + end
44 + end
45 +end
added lib/lambent_ex_web/live/devices/versions.html.heex
+39 −0
@@ -0,0 +1,39 @@
1 +<div class="overflow-x-auto">
2 + <div class="my-2 flex flex-wrap items-center gap-2">
3 + <.link patch={~p"/cfg/devices"} class="btn btn-ghost normal-case">
4 + <i class="fa-solid fa-chevron-left"></i> All devices
5 + </.link>
6 + <span class="text-sm opacity-60">
7 + Firmware versions as reported by the 7777-flex discovery endpoint.
8 + </span>
9 + </div>
10 + <table class="table table-zebra w-full">
11 + <thead>
12 + <tr>
13 + <th>MAC</th>
14 + <th>IP</th>
15 + <th>Version</th>
16 + </tr>
17 + </thead>
18 + <tbody>
19 + <%= if Enum.empty?(versioned(@devices)) do %>
20 + <tr>
21 + <th colspan="3">No 7777-flex devices detected, yet.</th>
22 + </tr>
23 + <% end %>
24 + <%= for {k,v} <- versioned(@devices) do %>
25 + <tr>
26 + <th><%= k %></th>
27 + <td><%= v |> pip %></td>
28 + <td>
29 + <%= if v["ver"] do %>
30 + <span class="badge badge-secondary"><%= v["ver"] %></span>
31 + <% else %>
32 + <span class="badge opacity-60">unknown</span>
33 + <% end %>
34 + </td>
35 + </tr>
36 + <% end %>
37 + </tbody>
38 + </table>
39 +</div>
modified lib/lambent_ex_web/router.ex
+1 −0
@@ -20,6 +20,7 @@ defmodule LambentExWeb.Router do
20 20 live "/", IndexLive.Index, :index
21 21
22 22 live "/cfg/devices", DevicesLive.Index, :index
23 + live "/cfg/devices/versions", DevicesLive.Versions, :index
23 24 live "/cfg/machines", MachinesLive.Index, :index
24 25 live "/cfg/machines/new", MachinesLive.Index, :new
25 26 live "/cfg/machines/library", MachinesLive.Index, :library

Parents: 6febe21