neiam
/lambent_ex
Lambent Aether 5
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
Record the firmware version the 7777-flex devices report
46b785f · Gabriel Morell · 2026-09-16 21:00
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