# Projekt Lärm-Sensoren ## Installation der Container ### Dateien #### Directory-Struktur Die Datei **noise.tgz** enthält die folgenden Dateien und Verzeichnisse: ~~~ | +- noisesensors | +- docker-compose.yml +- readarchive-stack.yml +- log +- data | +- mongo | | +- data | | +- entries | | | +- create.js | + influx | | + data : file, : directory ~~~ * **docker-compose.yml** enthält die Anweisungen für die Docker-Container. Dies kann so an das aktuelle Portainer-Stack angehängt werden. * **readarchive-stack.yml** eigenes, kleines Stack für den Einmal-Lauf *readarchive* (siehe unten). Gehört bewusst nicht ins Haupt-Stack, weil es kein Dauerdienst ist. * **log** Ablage für die Logdateien der einzelnene Container (**noise.log**, **sensorapi.log** und **readin.log**) . Diese werden täglich komprimiert. Es werden Versionen für 7 Tage aufgehoben. * **data** hier darunter befinden sich alle Daten, sowohl die Datenbanken als auch Konfigurationen. Außerdem werden jeweils die laufend eingelesenen Daten als **actdata.json** abgelegt. Diese werden bei jedem neuen Einlesen wieder überschrieben. * **data/mongo** Verzeichnis für die Mongo-Datenbank * **data/mngo/data** hier befinden sich die eingelesenen Daten * **data/mongo/entries** hier liegt die Datei **create.js**, mit deren Hilfe bei ersten Start der Datenbank die Collections und die Indexe erzeugt werden. * **data/influx** Verzeichnis für die Influx-Datenbank * **data/influx/data** Hier dann die eingelesenen Daten ### Aufrufe Entpacken des Tar-Files **noise.tgz** in einem beliebigen Verzeichnis (das Direktoty *noisesensors* wird angelegt). Der komplette Pfad zu dem Verzeichnis (also ab root) muss in der Environmentvariablen **LOCALDIR** hinterlegt werden. Nun das *docker-compose.yml* in das Portainer-Stack einfügen. Zusätzlich folgende Environment-Variablen festlegen: ~~~ DOCKER_INFLUXDB_INIT_USERNAME= DOCKER_INFLUXDB_INIT_PASSWORD= DOCKER_INFLUXTOKEN= MONGO_ROOT_USERNAME= MONGO_ROOT_PASSWORD= LOCALDIR= STORE=influx ~~~ \, \, \, \ und \ sind anzupassen. Danach einloggen in das Docker-Registry auf *citysensor.de*: ~~~ docker login docker.citysensor.de ~~~ Einloggen mit Username und Passwort (siehe mail), anschließend kann das Portainer-Stack gestartet werden (die Container werden beim ersten mal automatisch von *docker.citysensor.de* herunter geholt). Damit sollte dann Alles laufen. Das Programm holt alle 5min die neuesten Daten von *sensor.community* ab und speichert die Messwerte in der InfluxDB und die Metadaten des Sensors in der Mongo-Datenbank. Das Logfile kann via **tail -f log/noise.log** im Verzeichnise **noisesensors** mitgeschrieben werden. ### Container * **readin** Über diesen Container werden alle 5 min. die aktuellen Daten von *sensor.community* abgeholt und in den beiden Datenbanken gespeichert * **readarchive** Gegenstück zu *readin*: liest rückwirkend die Tagesdateien von *archive.sensor.community* ein, um Lücken zu füllen. Kein Dauerdienst, sondern ein Lauf mit Parametern — deshalb steht er **nicht** im Haupt-Stack, sondern in der eigenen Datei `readarchive-stack.yml`. Auf der Kommandozeile mit Argumenten: ~~~ docker compose -f readarchive-stack.yml run --rm readarchive \ -t noise -s 2026-07-22 -e 2026-07-23 -d influx ~~~ Im **Portainer** als eigenes Stack anlegen (Inhalt von `readarchive-stack.yml`) und die Parameter unten als *Environment variables* eintragen — `docker compose run` hat dort kein Gegenstück, aber `readFromcsv.js` liest jeden Parameter auch aus einer Env-Variablen: CLI | Env | Default ---- | ---- | ---- `-s` | `START` | gestern `-e` | `END` | Startdatum + 1 Tag (**exklusiv**) `-t` | `TYP` | `noise` `-d` | `DBASE` | `both`, in der Stack-Datei auf `influx` vorbelegt *Deploy the stack* startet den Lauf, der Container endet danach und bleibt als „Exited" stehen. Für den nächsten Zeitraum nur die Variablen ändern und *Update the stack*. Der Haupt-Stack wird dabei nicht angefasst. Beide Wege brauchen das Netz des laufenden Haupt-Stacks (`_default`, in `readarchive-stack.yml` als `external` eingetragen) sowie dieselben Zugangsdaten und `LOCALDIR` — auf der Kommandozeile aus einer `.env` neben der Datei, im Portainer aus den Stack-Variablen. Auch mit `-d influx` wird Mongo gebraucht, dort liegen die Metadaten der Sensoren. Ein Tag dauert etwa zwei Minuten. Schlägt ein Influx-Write fehl, werden die betroffenen Sensoren am Ende aufgelistet und der Exit-Code ist ≠ 0 (im Portainer als „Exited (1)" sichtbar). * **logrotate** Mit Hilfe dieses Containers werde die Log-Files im Unterverzeichnis *log* täglich rotiert. Es werden 7 Versionen behalten, ältere gelöscht. * **sensorapi** Über diesen Container werde die Daten aus der Mongo-Datenbank ausgelesen, aufbereitet und als JSON- oder CSV-Datei ausgegeben. * **noise** Mit diesem Container wird die Grafik aufbereitet. Auch kann darüber die API (im Container *sensorapi*) angesprochen und die Daten abgerufen werden. (Für die Parameter der Anfrage siehe die extra Beschreibung **Laerm_API**). Dieser Container sollte von außen über einen Domainnamen erreichbar sein. Ansonsten hört er auf **Port 3003** auf HTTP-Anfragen. * **mongodb** Die Mongo-Datenbank. Es gibt eine Datenbank namens **sensor_data**. Diese hat folgende Collections: * properties Hier liegen für alle Sensoren die Metadaten (wie Ortskoordinaten, Typ, Zeitpunkt der letzten Übertragung etc.) * statistics Dient nur Kontrolle, schreibt verschiedenen Statistikdaten wie Dauer des Einlesens, Dauer des Speicherns in den DBs etc. **Zugriff:** Am Besten über das Programm **MongoDB Compass**. Zugangsdaten entprechend der im Portainer hinterlegten. * **influxdb** Die Influx-Datenbank. Hier werden in dem Bucket *sensor_data* die reinen Messwert der einzelnen Sensoren gespeichert. **Zugriff:** http://\:8086 Logindaten: Entsprechen der im Portainer hinterlegten. ## Sourcen für die Container Das gesamte Projekt ist im GitHub unter **laermsensor-stack** abgelegt. Für jeden der 4 Container existiert darunter ein Verzeichnis: **readin**, **readarchive**, **sensorapi** und **noise**. In diesen Verzeichnissen sind alle benötigten Sourcen enthalten. Daneben gibt es **common** mit den Modulen, die sich *readin* und *readarchive* teilen: `mongo.js`, `influx_post.js`, `logit.js` und `statistics.js`. Sie lagen früher in beiden Komponenten doppelt und sind auseinandergelaufen. Wer dort etwas ändert, ändert es für beide — nach einer Änderung also **beide** Container neu bauen. Sollte was geändert werden, so muss mit **deploy.sh** der Container neu erzeugt und auf die Registry (siehe oben) gepushed werden. Der Build-Kontext von *readin* und *readarchive* ist wegen `common/` das Wurzelverzeichnis des Repositories; `deploy.sh` wechselt selbst dorthin und kann aus dem Komponentenverzeichnis aufgerufen werden. `deploy.sh` nimmt optional ein Tag als Argument: ~~~ ./deploy.sh # nur :latest ./deploy.sh 2026-08-01 # :2026-08-01 und zusätzlich :latest ~~~ **Ein Tag mitgeben.** Wird nur `latest` gepusht, überschreibt jeder Build den vorherigen Stand und es gibt keinen Weg zurück (siehe *Update eines laufenden Stacks*). Das Verzeichnis **noisesensors** ist nur dummy, es spiegelt die Dateistruktur für das aktuelle Stack ab, wie oben beschrieben (wird mit Hilfe von **noise.tgz** erzeugt). ## Update eines laufenden Stacks Betrifft eine Installation, die bereits läuft und auf einen neueren Stand gebracht werden soll. ### 1. Rollback-Möglichkeit sicherstellen **Vor allem anderen.** Zeigt in der Registry nur `latest` auf das Image, existiert der laufende Stand nach dem Pull nirgends mehr. Prüfen, welche Tags es gibt: ~~~ curl -H "Authorization: Basic " \ https://docker.citysensor.de/v2/readin/tags/list ~~~ Fehlt ein benanntes Tag für den laufenden Stand, ihn zuerst benennen und pushen. Das alte Image findet sich auf dem Build-Rechner meist noch unbenannt (`docker images | grep readin`): ~~~ docker tag docker.citysensor.de/readin: docker push docker.citysensor.de/readin: ~~~ ### 2. docker-compose.yml im Portainer angleichen Den Stand aus `noisesensors/docker-compose.yml` dieses Repositories übernehmen. Zu beachten: * **Zwingend** bei einem Update von einem Stand vor August 2026: das Volume von *readin* muss auf `/opt/app/readin/data` zeigen, nicht mehr auf `/opt/app/data`. Das Layout im Image spiegelt seit der Einführung von `common/` das Repository. Bleibt der alte Pfad stehen, schreibt readin `aktdata.json` in die Container-Schicht statt auf den Host. * Der Service **readarchive** gehört nicht mehr ins `docker-compose.yml`. Steht er dort noch (mit `profiles: ["tools"]`), kann er beim Update entfallen — er wird durch das eigene Stack `readarchive-stack.yml` ersetzt. * **Nicht** aufnehmen: ein Mount auf `/etc/influxdb2`. Das Entrypoint von influxdb legt dort beim Setup das CLI-Profil `default` an. Ist bereits eines vorhanden, scheitert der Setup — und das Entrypoint löscht daraufhin `influxd.bolt` und `engine/` im Datenverzeichnis und startet neu. Weil der Mount das Aufräumen überlebt, wiederholt sich das endlos und der Datenbestand ist bei jeder Runde weg. ### 3. Nur den geänderten Container ziehen Nicht den ganzen Stack neu starten — Mongo und Influx bleiben unangetastet: ~~~ docker compose pull readin docker compose up -d readin ~~~ Im Portainer entspricht das dem Aktualisieren des Stacks mit *Re-pull image and redeploy*. ### 4. Verifizieren Der nächste Lauf kommt binnen fünf Minuten: ~~~ tail -20 /noisesensors/log/readin.log ls -l /noisesensors/data/aktdata.json ~~~ Erwartet werden `Influx-Write-Time` und `Program end` sowie ein frischer Zeitstempel an `aktdata.json` — letzterer belegt, dass der Volume-Pfad stimmt. ### 5. Rollback Image-Tag im Stack auf den in Schritt 1 gesicherten Stand setzen, die Volume-Zeile auf den alten Pfad zurückdrehen, redeploy. ## Versionen Version | Datum | Bemerkung ---- | ---- | ---- 1.0.0 | 2023-11-30 | 2.0.0 | 2026-07-25 | Anpassung an Stack-Änderungen 2.1.0 | 2026-08-01 | readarchive dazu, gemeinsame Module unter common/, Zeitstempel in UTC 2.1.1 | 2026-08-02 | readarchive als eigenes Stack (readarchive-stack.yml)