From a29508f7cda507785f8f1d67925288af6f2b4eea Mon Sep 17 00:00:00 2001 From: Dr Bill Mcilhargey Date: Sun, 4 Oct 2026 19:11:37 +0000 Subject: [PATCH 1/5] adsbexchange-stats: add new package Package the ADSBexchange statistics uploader for OpenWrt, pinned to upstream commit 11647f27de3eef51fb19bcb39f0dc0b8500a6671. Keep uploads optional and disabled until the operator explicitly selects an enabled ADSBexchange feeder and consents to the separate statistics upload. Use the selected feeder UUID override before the shared station UUID. Validate live consent and identity with one UCI batch read per upload. Integrate activation, status and help with readsb-wiedehopf while keeping the uploader and its dependencies in this separate package. Provide a main-only procd service, safe generated shell settings, checked upload metrics, and post-stop cleanup of known runtime files. Preserve disabled service state during upgrades and reload on relevant configuration changes. Include a valid upstream patch and regression coverage for lifecycle, consent, identity, configuration and metrics. Upstream: https://github.com/ADSBexchange/adsbexchange-stats Upstream payload remains MIT; packaging files are GPL-2.0-only. Signed-off-by: Dr Bill Mcilhargey Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- utils/adsbexchange-stats/Makefile | 141 +++++ utils/adsbexchange-stats/README.md | 308 ++++++++++ .../files/adsbexchange-stats.config | 26 + .../files/adsbexchange-stats.functions.sh | 150 +++++ .../files/adsbexchange-stats.init | 265 +++++++++ .../adsbexchange-stats.json-status-helpers.sh | 181 ++++++ .../patches/010-openwrt-paths.patch | 115 ++++ utils/adsbexchange-stats/tests/stats.sh | 537 ++++++++++++++++++ 8 files changed, 1723 insertions(+) create mode 100644 utils/adsbexchange-stats/Makefile create mode 100644 utils/adsbexchange-stats/README.md create mode 100644 utils/adsbexchange-stats/files/adsbexchange-stats.config create mode 100644 utils/adsbexchange-stats/files/adsbexchange-stats.functions.sh create mode 100644 utils/adsbexchange-stats/files/adsbexchange-stats.init create mode 100644 utils/adsbexchange-stats/files/adsbexchange-stats.json-status-helpers.sh create mode 100644 utils/adsbexchange-stats/patches/010-openwrt-paths.patch create mode 100644 utils/adsbexchange-stats/tests/stats.sh diff --git a/utils/adsbexchange-stats/Makefile b/utils/adsbexchange-stats/Makefile new file mode 100644 index 0000000000000..f14fa8f2bda21 --- /dev/null +++ b/utils/adsbexchange-stats/Makefile @@ -0,0 +1,141 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2026 Dr Bill Mcilhargey +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +# Dual-license: OpenWrt packaging files (this Makefile, init script, +# helpers, patches) are GPL-2.0-only. The upstream json-status payload +# (ADSBexchange.com, (c) 2020) remains under its original MIT license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=adsbexchange-stats +PKG_VERSION:=2023-02-22 +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/ADSBexchange/adsbexchange-stats.git +PKG_SOURCE_VERSION:=11647f27de3eef51fb19bcb39f0dc0b8500a6671 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz +PKG_MIRROR_HASH:=b16c3c708daea4389f1d850aca1c899cfd9827785038c332c4bf28e541ae5992 + +PKG_LICENSE:=MIT GPL-2.0-only +PKG_LICENSE_FILES:=LICENSE + +PKG_MAINTAINER:=Dr Bill Mcilhargey + +include $(INCLUDE_DIR)/package.mk + +define Package/adsbexchange-stats + SECTION:=utils + CATEGORY:=Utilities + TITLE:=ADSBexchange.com statistics uploader + URL:=https://github.com/ADSBexchange/adsbexchange-stats + # Hard-depends on readsb-wiedehopf: shares feeder identity, the + # readsb-uuid CLI, and /usr/lib/readsb/functions.sh. + # gzip is intentionally omitted -- BusyBox provides the `gzip` applet + # which is what the upload path uses; +gzip would pull standalone GNU + # gzip and break opkg dep resolution on stock feeds. + DEPENDS:=+bash +jq +curl +coreutils-stat +readsb-wiedehopf + PKGARCH:=all +endef + +define Package/adsbexchange-stats/description + ADSBexchange.com statistics uploader for OpenWrt. + + Periodically reads aircraft.json from readsb (via readsb-wiedehopf), + aggregates per-aircraft RSSI and counts, and POSTs the result to + https://adsbexchange.com identified by the selected enabled feeder's + UUID (its override, or readsb.main.uuid). Installation does not enable + or start uploads. Use readsb-feeder --setup-companions to opt in. + + Service knobs live in /etc/config/adsbexchange-stats. + Manage the station UUID with `readsb-uuid`. + + Daemon control: + service adsbexchange-stats {start|stop|restart|reload|status|enable|disable|showurl} + logread -e adsbexchange-stats -- uploader logs + + Extra (non-procd) actions: + /etc/init.d/adsbexchange-stats showurl + -- print the public per-station + ADSBexchange stats URL + (derived from the selected feeder) + /etc/init.d/adsbexchange-stats about -- package and configuration help +endef + +# Pure shell payload; nothing to compile or stage-install. +Build/Configure:=: +Build/Compile:=: +Build/Install:=: + +define Package/adsbexchange-stats/conffiles +/etc/config/adsbexchange-stats +endef + +define Package/adsbexchange-stats/install + $(INSTALL_DIR) \ + $(1)/etc/config \ + $(1)/etc/init.d \ + $(1)/usr/lib/adsbexchange-stats \ + $(1)/usr/share/adsbexchange-stats + $(INSTALL_BIN) $(PKG_BUILD_DIR)/json-status $(1)/usr/share/adsbexchange-stats/json-status + $(INSTALL_CONF) ./files/adsbexchange-stats.config $(1)/etc/config/adsbexchange-stats + $(INSTALL_BIN) ./files/adsbexchange-stats.init $(1)/etc/init.d/adsbexchange-stats + $(INSTALL_DATA) ./files/adsbexchange-stats.functions.sh $(1)/usr/lib/adsbexchange-stats/functions.sh + $(INSTALL_DATA) ./files/adsbexchange-stats.json-status-helpers.sh \ + $(1)/usr/lib/adsbexchange-stats/json-status-helpers.sh + # Substitute @PKG_*@ placeholders in the init banner so values + # stay sourced from this Makefile (PKG_VERSION/PKG_MAINTAINER/...). + $(SED) 's,@PKG_VERSION@,$(PKG_VERSION)-$(PKG_RELEASE),g' $(1)/etc/init.d/adsbexchange-stats + $(SED) 's,@PKG_LICENSE@,$(PKG_LICENSE),g' $(1)/etc/init.d/adsbexchange-stats + $(SED) 's,@PKG_URL@,https://github.com/ADSBexchange/adsbexchange-stats,g' $(1)/etc/init.d/adsbexchange-stats + $(SED) 's,@PKG_MAINTAINER@,$(PKG_MAINTAINER),g' $(1)/etc/init.d/adsbexchange-stats +endef + +define Package/adsbexchange-stats/postinst +#!/bin/sh +[ -n "$${IPKG_INSTROOT}" ] && exit 0 +[ "$${PKG_UPGRADE}" = "1" ] && { +/etc/init.d/adsbexchange-stats enabled && /etc/init.d/adsbexchange-stats restart +exit 0 +} +cat <<'EOF' +adsbexchange-stats installed; statistics uploads remain disabled. + Optional setup: readsb-feeder --setup-companions + Uploads require separate explicit consent and use the selected feeder UUID. + Help: service adsbexchange-stats about +EOF +exit 0 +endef + +define Package/adsbexchange-stats/prerm +#!/bin/sh +# Stop and disable before opkg removes the init script. Output is +# silenced because procd's `service delete` ubus call emits a harmless +# "Command failed: Not found" when no live service entry exists. +[ -n "$${IPKG_INSTROOT}" ] && exit 0 +[ "$${PKG_UPGRADE}" = "1" ] && exit 0 +{ + if [ -x /etc/init.d/adsbexchange-stats ]; then + /etc/init.d/adsbexchange-stats running && \ + /etc/init.d/adsbexchange-stats stop + /etc/init.d/adsbexchange-stats disable + fi +} >/dev/null 2>&1 +exit 0 +endef + +define Package/adsbexchange-stats/postrm +#!/bin/sh +# Tidy the runtime dir; /var/run is tmpfs and would clear at reboot +# anyway. Intentionally untouched: readsb.main.uuid (shared station +# identity) and /etc/config/adsbexchange-stats (opkg `conffiles`). +[ -n "$${IPKG_INSTROOT}" ] && exit 0 +rm -rf /var/run/adsbexchange-stats +exit 0 +endef + +$(eval $(call BuildPackage,adsbexchange-stats)) diff --git a/utils/adsbexchange-stats/README.md b/utils/adsbexchange-stats/README.md new file mode 100644 index 0000000000000..d945400f411d5 --- /dev/null +++ b/utils/adsbexchange-stats/README.md @@ -0,0 +1,308 @@ +# adsbexchange-stats + +Optional ranking-dashboard statistics uploader for ADSBexchange.com on +OpenWrt. Companion to [`readsb-wiedehopf`](../readsb-wiedehopf/) -- it +periodically reads `aircraft.json` from the local readsb daemon, +aggregates per-aircraft RSSI and counts, and POSTs the result to +ADSBexchange identified by the selected feeder's effective UUID. Pure feeding does +**not** require this package; install it only if you want your station +listed on the per-station web ranking. + +## Contents + +* [Quick start](#quick-start) +* [What gets installed](#what-gets-installed) +* [Configuration](#configuration) + * [`/etc/config/adsbexchange-stats` -- main section options](#etcconfigadsbexchange-stats----main-section-options) +* [Station UUID](#station-uuid) +* [Service control](#service-control) +* [Logging and diagnostics](#logging-and-diagnostics) + * [Log levels](#log-levels) +* [Relationship to readsb-wiedehopf](#relationship-to-readsb-wiedehopf) +* [Tests](#tests) +* [License](#license) + +## Quick start + +```sh +opkg install readsb-wiedehopf # required dependency +opkg install adsbexchange-stats +readsb-uuid # station UUID, unless the feeder overrides it +readsb-feeder --setup-companions adsbx # use your enabled ADSBx feeder section name +service adsbexchange-stats showurl # print this station's stats URL +``` + +Installation **does not enable or start uploads**. OpenWrt's generic +package hooks may register and invoke the init script, but the default +`enabled=0` permission prevents any uploader process from starting. +The readsb wizard +offers the optional package only when installed or available in cached +configured-feed metadata. A separate default-No prompt explains the +statistics upload before installation or activation. Selecting No leaves +normal ADSBexchange feeding unchanged. + +For explicit noninteractive activation (this command constitutes consent +to the external statistics upload): + +```sh +service adsbexchange-stats activate adsbx +``` + +The named section must exist, use `preset adsbexchange`, be enabled, +and have a valid effective UUID. `activate` selects it, enables the +uploader's UCI setting and boot service, then restarts the uploader. +Pending readsb or uploader edits must be explicitly committed or +reverted before activation. +There is one uploader selection; changing it replaces the previous +selection rather than starting a second upload process. + +Upgrades preserve the existing boot-enable state and do not auto-enable +a previously disabled service. Older installations that have no +`feeder` selection must explicitly select one before uploading; the +package never guesses which of several feeders to use. + +To watch the uploader: + +```sh +logread -e adsbexchange-stats +``` + +## What gets installed + +| Path | Purpose | +| ----------------------------------------------------- | ------------------------------------------------------------------------------------ | +| `/usr/share/adsbexchange-stats/json-status` | patched upstream uploader (bash; runs under procd) | +| `/etc/config/adsbexchange-stats` | UCI config (declarative; see below) | +| `/etc/init.d/adsbexchange-stats` | procd service and `activate`, `showurl`, `about` actions | +| `/usr/lib/adsbexchange-stats/functions.sh` | shared sh helpers (logging, UUID, json path resolution) | +| `/usr/lib/adsbexchange-stats/json-status-helpers.sh` | upload-side helpers (curl wrapper, periodic summary) | +| `/var/run/adsbexchange-stats/` | runtime dir (env file, uuid, scratch JSON; tmpfs) | + +## Configuration + +`/etc/config/adsbexchange-stats` is **declarative-only by design** -- +it carries options, not documentation. Comments (lines starting with +`#`) do not survive `uci commit`: every committer (manual `uci`, LuCI, +this package's own reload trigger, `readsb-uuid`) rewrites the file in +canonical form and strips them. All option documentation therefore +lives in this source-repository README and in `service adsbexchange-stats about`, never +inside the conffile itself. (The same convention is used by the +companion `readsb-wiedehopf` package.) + +The init script reads the conffile together with the selected feeder's +UUID and `readsb.main.write_json` from `/etc/config/readsb`, renders an env +file at `/var/run/adsbexchange-stats/env`, and supervises the uploader +under procd. +Scalar values in that generated file are shell-quoted, including log +tags and runtime paths; quotes, whitespace, and shell punctuation are +preserved as data rather than interpreted as commands. + +Reload triggers are registered on **both** `adsbexchange-stats` and +`readsb`, so the recommended workflow is: + +```sh +uci set adsbexchange-stats.main.