Neanderfunk map (beta): meshviewer, yanic, unifi_respondd

New map for Neanderfunk, still beta: https://neander.map.freifunk.space/.

Below, what differs in meshviewer, yanic and unifi_respondd from upstream and what runs around it.
Each point a pinned commit, plus the status upstream.
The forks are merged to upstream status, local changes remain one commit per feature (git log --no-merges --first-parent).

meshviewer

  • Fork: Neanderfunk/meshviewer, Branch neanderfunk, AGPL-3.0 like the original. Pinned: GitHub - Neanderfunk/meshviewer at f34bd2398b3a5850473a3a8a5e2f1d5a83d220bb · GitHub
  • Base: freifunk/meshviewer df76ed7 (26.09.2026), current status, including external GeoJSON via URL (#476).
  • One commit per feature, explained in NEANDERFUNK.md in the fork. All new configuration keys are optional; without them the branch behaves like the original.

Features

Bugfixes

Upstream status (freifunk/meshviewer, 28.09.2026)

  • Airtime: #28 „integrate features from hopglass“, closed 09.09.2023, the point „showing Radio Channel (and Airtime) on map“ in it NOT checked.
  • Charts: #388 „[FEATURE] add client side rendered charts“, merged 16.06.2026, that’s the Grafana way, on which prometheus-direct builds. Open: #402 (link to Grafana), #403 (time format for short periods), PR #417 (InfluxDB ALIAS BY for multiple series).
  • Dark theme: #423 invertInDarkMode, merged 07.08.2026. Nothing on label colors per theme.
  • Related, not the same: #82 (link to node subdomain), open since 24.12.2023.
  • No issue or PR found for WMS, coordinate line, statistics links, gear icon, pause in background, copy button, and start view.

Limits

  • Charts, airtime and value rows require a Prometheus API that the browser can reach. For us the same host under /nf/prom/, read-only.
  • Airtime knows only the bands that yanic knows: 11g (2.4 GHz) and 11a (5 GHz). 6 GHz is missing (yet).
  • Tested only on our instance, with Firefox and headless Chromium; mobile view only for the start view (400 px).
  • The pause in the background works around a Firefox bug: Firefox 149, three map tabs over hours, 35, 10 and 11 GB per tab, of which according to about:memory 11.1 GB heap/committed/unused-pages/dirty with 0.8 GB used. Chromium over 60 updates: heap constant 21 to 26 MB. Open as Mozilla bug 2070900 (NEW since 10.09.2026). If Mozilla fixes it, the pause goes away.
  • meshviewer.json at 1716 nodes: 1.9 MB, with gzip 299 KB, once per minute.

yanic

Features

Bugfixes

Upstream status (Codeberg FreifunkBremen/yanic, 28.09.2026)

  • Unicast: #21 (PR, unicast to nodes that don’t answer multicast) unmerged closed 2017, the behavior is in yanic today anyway (sendUnicasts); #13 and #121 closed. Open #209 (configurable target port, 04.01.2022). Nothing on addresses from a file.
  • Additional fields: #171 (PR, custom respondd fields), merged 29.12.2019; #142 (channel and airtime in meshviewer.json), closed 14.04.2022. Whether #171 would already bring our values into the Influx output is not tested.
  • Links: #149 (same TQ in both directions), closed 04.01.2019; #239 (PR, link type everywhere), merged 29.06.2025; open #218 (is_active for links, 02.02.2023). Nothing on APs reported via proxy and double-counted clients.
  • Remove: #81 (PR, contrib/yanic-remove-node, a script for the state file), merged 02.11.2017. Nothing on a request directory during operation.
  • Aliases: nothing; #50 affects only the hopglass output format.
  • Context: open #156 „Should yanic be also a respondd daemon“ (21.01.2019).

Limits

  • statistics.neanderfunk only reads fields from our package, they don’t exist elsewhere. Everything else is generic.
  • seeds is currently not active for us.
  • AP detection depends solely on software.firmware.base. The router of an AP is the batman neighbor that the AP reports; if the proxy assignment is wrong, the correction is also wrong.
  • Aliases and removal are tested only with our own service menu, not with a real hopglass alias file.

unifi_respondd

  • Fork: Neanderfunk/unifi_respondd, Branch neanderfunk, GPL-3.0 like the original. Pinned: GitHub - Neanderfunk/unifi_respondd at 6a0ef19520e9f87a34b2683cb8def825ea8b4e21 · GitHub
  • Base: freifunkMUC/unifi_respondd 6976651 (18.09.2026), also the current status of upstream main.
  • One commit per feature, explained in NEANDERFUNK.md. 113 tests at the final status green. Without offloader_by_ap and interfaces, the fork behaves like upstream except for bugfixes.

Features

Bugfixes

  • Null Island. APs without SNMP Location stood at 0/0 in the Gulf of Guinea, maps with calculated view pulled it there. Upstream sets lat, lon = 0, 0 as default. Fix: no location instead of 0/0, even if 0/0 is entered; the AP then stands in list and graph at its router, only not on the map. Ohne Koordinaten kein Ort statt 0/0 · Neanderfunk/unifi_respondd@727951f · GitHub
  • Airtime 0%. In rx/tx were byte counters of SSIDs instead of radio time, on the 2.4 GHz band even that of the 5 GHz band, active was missing. Fix: airtime from controller, see above.
  • Send errors ended the service. If sendto failed, the exception ended the process, systemd restarted it after 30 s. For us every five minutes, cause a full IPv6 neighbor table (EINVAL). Fix: log, continue with the next packet. Sendefehler beenden nicht mehr den Dienst · Neanderfunk/unifi_respondd@4b445cc · GitHub

Upstream status (freifunkMUC/unifi_respondd, 28.09.2026)

  • Location: #95 (don’t geocode empty SNMP Location) and #97 (limit recursion), both merged 18.09.2026; #9 (coordinates from SNMP Location), merged 02.01.2022. Nothing on renouncing Nominatim, cardinal directions, DMS or 0/0.
  • Radio: #41 (wireless infos), merged 13.05.2024; #50 (tx/rx_bytes), merged 25.08.2025. Nothing on airtime from radio_table_stats.
  • Router: #22 (neighbour/offloader), merged 10.01.2022; #35 (link to offloader sometimes missing), closed 24.08.2022. Nothing on per-AP assignment.
  • Domains: #24 (domain add), merged 13.01.2022; #39 (fallback domain), merged 26.10.2024. Nothing on multiple interfaces and site_code.
  • Controller: #21 (ask once), merged 07.01.2022; #98 (skip site on error), merged 18.09.2026; open PR #96 (reuse session).
  • Crashes: #36, closed 23.01.2025 with #43; #37 (systemd workaround), merged 31.03.2022. Nothing on sendto.
  • Open, would affect our commits on merge: PR #94 (multi-controller, omada), PR #71 (provider-agnostic: UniFi, Omada, UISP), PR #70 (abstract base classes).

Limits

  • The AP-to-router assignment is bound to our infrastructure: it arises from the translation tables of our map server. The list of manufacturer prefixes in it is maintained, not complete.
  • APs without a measured router the service does not report; a wrong router would be worse than a missing AP. Out-of-band managed installations cannot be measured this way.
  • 6 GHz is missing, yanic knows only 11g and 11a. On 25.09.2026, none of the 545 APs reported an active 6 GHz module.
  • Noise is not provided by the controller. Airtime is as old as the controller data, a few minutes.
  • Tested with one controller and only on our instance. In the field only northern hemisphere and eastern longitudes, the rest with tests.
  • Numbers, 25.09.2026, first measurement after commissioning: 544 APs online, 1021 clients on APs; sum of all clients around 3050, without subtraction at the router it would have been around 4000.

Time series, Grafana, map server

  • Repo: Neanderfunk/mapserver, BSD-3-Clause: setup scripts per layer, generators for yanic, meshviewer and nginx configuration, the Grafana dashboards as generator, Checkmk checks, documentation. Builds the three forks from their neanderfunk branch. Pinned: GitHub - Neanderfunk/mapserver at 11fcd8599d6aeb1b5c89194d8ca2d04eadc49b83 · GitHub
  • Unchanged from packages or fixed upstream commits: VictoriaMetrics 1.112.0 (Debian trixie), Grafana 13.2.2, mesh-announce 40be9a1, Tunneldigger client 9a9a427 (C).

Time series

  • yanic writes via the Influx output to VictoriaMetrics, metric names <measurement>_<field>, for example node_load, link_tq, node_airtime11g.chan_util. Retention 400 days.
  • Discarded on receipt: owner (contact information, yanic knows no no_owner for this output) and frequency labels. A channel change would otherwise create a new time series each time, a device came so to 16 in a day. The frequency remains as a measured value.
  • Read-only public: https://neander.map.freifunk.space/nf/prom/api/v1/, released only query, query_range, series, labels, label/<name>/values, export, status/tsdb, federate; everything else 403. Same source from which the node window draws.
  • 89,643 time series (28.09.2026).

Grafana

  • Grafana, readable without login.
  • Dashboards node (linked from node window), domain, community (linked at top of Statistics tab), supernode. Generated per script (zeitreihe/grafana/dashboard-erzeugen.py), not maintained by hand.
  • Community: Gluon nodes and supernodes as large numbers, progressions for firmware, hardware and targets, traffic counted only once instead of adding node and supernode sides.

Map server

  • One map for all 48 domains, all configuration from a domain table, one meshviewer build.
  • Tunnel per domain, in the mesh only one asking node: no gw_mode, no clients, no DHCP, no forwarding, only link-local, accept_ra off, fixed locally managed MACs, a speaking name at the broker.
  • mesh-announce answers for the map server as map-neanderfunk-<domaincode>, otherwise it would be a node without data for every other map. Shares port 1001 with unifi_respondd.
  • Start view without outliers: nodes up to 25 km distance form a group, even across chains; the largest group and each 10% of nodes count; 0/0 never counts. At 1002 nodes with location 977 are in the core. Startausschnitt ohne Ausreisser · Neanderfunk/mapserver@875dd68 · GitHub
  • Service menu behind Authentik, only for maintainers: remove offline nodes, override coordinates or remove from map, change names, with history. Technically via aliases_path and remove_dir in yanic.
  • Address in coordinate picker via its own cached proxy instead of directly from browser to Nominatim: only latitude and longitude on 5 decimal places onward, at most one request per second, cache 30 days.
  • Delivery with gzip since 27.09.2026; Debian’s nginx default compresses only text/html.
  • IPv6 neighbor table: gc_thresh3 1024 (Debian default) not enough for 43 batman instances, sendto failed with EINVAL. Now 16384.

Limits

  • No vector maps, base map is raster tiles via our tile proxy plus WMS NRW.
  • A second installation from the repo from scratch has not happened, the setup scripts went through only once here.

Feedback from reusers welcome.