Ruft dieselben Parameter (sensorid/data/span/datetime/peak) gegen zwei
"getsensordata"-Endpunkte ab und diffed die Werte zeitstempelweise, generisch
über alle Felder (funktioniert für live genauso wie für havg/davg/daynight/lden).
Diente als Verifikation der VictoriaMetrics-Anbindung: live-Werte stimmen exakt,
havg-Werte liegen weit innerhalb der Toleranz gegenüber der Influx-Produktion.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dritte, zu mongo/influx exklusive Auswahl für die laufenden Messwerte. Schreibpfad
nutzt das bestehende Influx-Line-Protocol unverändert (common/victoria_post.js);
Lesepfad (sensorapi/databases/victoria.js + victoria2json.js) holt Rohdaten per
VictoriaMetrics' /api/v1/export und bucketet/aggregiert stundenweise clientseitig,
nach Mongo-Konvention (Stunden-Start als Label, kein Zeit-Shift nötig wie bei Influx).
Scope bewusst auf die schon heute per DBASE umschaltbaren Funktionen begrenzt
(getActData/getNoiseAVGData) - getAvgData/getLongAvg/getGeigerData bleiben wie bisher.
Docker-Compose um victoriametrics-Service ergänzt (Retention explizit auf 100y
gesetzt, da VictoriaMetrics sonst nach 1 Monat Daten löscht).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
beschreibung.md auf technische Inhalte gekürzt und Bildverweise
entfernt; neue Bedienungsanleitung.md für Endanwender ergänzt
(ebenfalls ohne Bilder).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Padding und Rahmen der Inputs wurden bislang zur width:100% addiert
und ragten dadurch über den rechten Rand des Containers hinaus.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nach dem Anlegen eines Users blieben Formularfelder und die Meldung
"User erfolgreich angelegt!" beim erneuten Öffnen des User-Tabs stehen.
Werden jetzt beim (Wieder-)Betreten des Tabs zurückgesetzt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Logout-Button rechts in der Tab-Zeile ergänzt. Die Bestätigungsmeldung
nach dem Löschen eines Users blieb bisher beim erneuten Öffnen des
User-Tabs stehen; sie wird jetzt beim (Wieder-)Betreten des Tabs
zurückgesetzt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Admin-Bootstrap via ADMIN_EMAIL/ADMIN_PASSWORD für extern verwaltete
Deployments, User-Liste mit Passwort-Reset/Löschen im User-Tab, sowie
zwei Bugfixes (Absturz bei Nicht-Admin-Login, fehlende Version bei
Login-Fehler).
POST /login rendert bei Fehlermeldung wieder version/vdate/noUsers, so wie
GET /login das schon tut - vorher fielen diese Locals beim Fehlerfall weg
und der Footer war leer.
- Ersetzt window.prompt() für den Passwort-Reset in der User-Liste durch
ein eigenes, zum bestehenden Bestätigungs-Modal passendes Popup
(showInputModal), analog zum vorhandenen showModal für Löschbestätigungen.
- Behebt ReferenceError beim Login als Nicht-Admin: userCancelBtn wurde als
impliziter globaler Bezeichner referenziert statt über
document.getElementById, existiert aber nur im admin-only User-Tab-HTML.
Für Nicht-Admins riss das den kompletten Setup-Block (Tabs, Liste laden) ab.
Ersetzt das manuelle E-Mail-Eingabefeld für den Passwort-Reset durch
eine Liste aller angemeldeten User. Pro User stehen zwei Aktionen zur
Verfügung: Passwort zurücksetzen (nutzt die bestehende
/api/resetPassword-Route) und Löschen (neue DELETE /api/users/:id-Route,
admin-only, verhindert Löschen des eigenen Accounts). Neue GET
/api/users-Route liefert Email/Rolle aller User (admin-only).
Für extern verwaltete Deployments (Portainer, kein direkter Mongo-Zugriff)
wird beim Start automatisch ein Admin-User angelegt, falls die
user-Collection leer ist und ADMIN_EMAIL/ADMIN_PASSWORD gesetzt sind.
Login-Seite zeigt einen Hinweis, solange noch kein User existiert.
Version auf 1.5.0 angehoben.
espid2sensor: Selfservice-Passwortänderung fuer alle User und
Admin-gesteuerter Passwort-Reset (kein Mail-Versand noetig).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- POST /api/changePassword: jeder eingeloggte User kann sein eigenes
Passwort ändern (erfordert aktuelles Passwort), neuer Profil-Tab
- POST /api/resetPassword: Admin kann das Passwort eines Users per
Email zuruecksetzen, neue Karte im bestehenden User-Tab
- Login-Seite: Hinweis fuer "Passwort vergessen" (Kontakt zum Admin,
da keine Mail-Infrastruktur im Projekt existiert)
- Bugfix beim Umsetzen: express-session's MemoryStore serialisiert
Sessions per JSON, wodurch die ObjectId aus req.session.userId zu
einem String wird - vor der Mongo-Query per ObjectId(...) casten
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
espid2sensor in den Hauptstack integriert: verschachteltes Git-Repo
aufgeloest, Dockerfile/deploy.sh an die anderen Services angeglichen,
als Service in noisesensors/docker-compose.yml aufgenommen (Port 3004,
gemeinsame Mongo-Instanz), APIHOST-Bugfix fuer die Adressaufloesung,
Versionsbump auf 1.3.2.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ueberfluessig, seit deploy.sh direkt ueber docker build + push
arbeitet (wie bei den anderen Services) statt ueber das alte
scp-basierte Kopieren auf einen Zielhost.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
REGISTRY per Env-Variable konfigurierbar (Default ghcr.io/dnms-org/laermkarte-sensor-community),
Build direkt ueber docker build -f Dockerfile_esp2sensor statt ueber das
alte scp-basierte build_and_copy.sh, einheitlicher Aufbau/Ausgabe wie bei
noise/sensorapi/readin/readarchive.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ohne APIHOST griff der externe Default (https://noise.fuerst-stuttgart.de/srv/),
der im Container mit einem TLS-Fehler (self-signed certificate) fehlschlug. Die
dadurch leere Adresse wurde vom Frontend faelschlich als "Sensor unbekannt"
interpretiert, obwohl der Sensor in Mongo existierte.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
espid2sensor lief bisher nur per eigenem Dev-Compose mit isolierter
Wegwerf-Mongo. Jetzt Teil von noisesensors/docker-compose.yml, Port 3004,
Zugriff auf die dort laufende mongodb-Instanz (sensor_data). DEV_AUTO_LOGIN
explizit aus, SESSION_SECRET ueber neue Env-Variable statt Code-Default.
Dockerfile_esp2sensor an das Muster der anderen Services angeglichen
(node:22-alpine, /opt/app, npm ci, tzdata/Europe-Berlin, deluser node).
espid2sensor/.git entfernt (war eigenes verschachteltes Repo) und der
komplette Verzeichnisinhalt ins laermsensor-stack-Repo uebernommen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Alle vier Skripte schieben das gebaute Image jetzt auch nach
gitea.fuerst-stuttgart.de/admin, damit es nicht nur an einer Stelle liegt.
Der zweite Push laeuft nach dem ersten und ist bewusst nicht fatal: schlaegt
er fehl, liegt das Image bereits in docker.citysensor.de, aus der der Stack
zieht. Das Skript meldet dann nur, dass die Zweitablage fehlt, statt den
ganzen Deploy als gescheitert auszuweisen.
Abschalten mit REGISTRY2= ./deploy.sh
Voraussetzung ist ein docker login gitea.fuerst-stuttgart.de (Access Token
mit write:package genuegt).
Geprueft: noise, sensorapi, readarchive und readin liegen in beiden
Registries unter demselben Digest.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beide Komponenten wurden fuer die Korrektur der Stadtsuche angefasst, die
Versionen im Log und in der Oberfläche sollen das zeigen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wer auf dem Kartenreiter die Einstellungen oeffnete und eine Stadt eingab,
bekam danach nur noch ein graues Fenster. Drei Fehler wirkten zusammen:
1. getCityCoords() rief Nominatim ohne eigenen User-Agent auf. Nominatim
beantwortet den axios-Default mit 403, und zwar fuer jede Stadt. Die
Schwesterfunktion getAddress() setzt seit jeher einen User-Agent -
deshalb funktionierten die Adressen an den Sensoren, nur die
Stadtsuche nicht. Beide nutzen jetzt dieselbe Konstante.
2. cityCoords() lieferte im Fehlerfall den String "no coordinates". Der
landete als Kartenzentrum in L.map().setView(), Leaflet warf "Invalid
LatLng object" - und weil showMap() die alte Karte vorher schon
entfernt hat, blieb der Container leer. Daher grau statt Fehlermeldung.
cityCoords() liefert jetzt {coords, err}; schlaegt die Suche fehl,
bleibt das bisherige Zentrum stehen und der Text wird angezeigt.
3. Der Proxy in noise/routes/api.js kodierte die bereits prozentkodierte
req.originalUrl ein zweites Mal. 'Goettingen' kam als 'G%c3%b6ttingen'
an. Das fiel bisher nicht auf, weil schon Punkt 1 alles abfing.
Ausserdem: Tippfehler getCityCoord.name, fehlendes encodeURI bei der
Stadtsuche, Koordinaten als Zahl statt String, und eine eigene Meldung
(ENOCITY), wenn Nominatim den Ort nicht kennt.
Geprueft ueber die volle Kette noise -> sensorapi -> Nominatim:
Stuttgart, Goettingen (Umlaut), Bad Cannstatt (Leerzeichen) liefern
Koordinaten, ein erfundener Ort eine saubere Meldung.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Laufzeit steckt fast vollstaendig im Warten auf die CSV-Dateien von
archive.sensor.community - je Sensor rund 0,24 s, davon nur 0,02 s der
Influx-Write und 0,01 s die Mongo-Abfrage. Die Schleife ueber die Sensoren
laeuft deshalb jetzt mit mehreren Arbeitern gleichzeitig (-p bzw. PARALLEL,
Default 4, 1 = altes Verhalten).
Gemessen fuer 2026-08-01 (280 Laermsensoren, 344660 Werte, -d influx):
1 -> 79 s, 4 -> 33 s, 8 -> 35 s, 16 -> 31 s. Ab etwa 4 gleichzeitigen
Abrufen liefert das Archiv nicht mehr schneller; derselbe Verlauf zeigt
sich mit blossem curl ohne Datenbank (71 / 32 / 28 / 29 / 29 s bei 1, 4,
8, 16, 32 Abrufen). Der Default steht deshalb auf 4 und nicht hoeher -
mehr erzeugt nur Last beim fremden Server.
checkProperties() wird jetzt awaited - der Aufruf lief bisher ohne await
gegen das bulkWrite am Ende von main(), was mit parallelen Sensoren kein
Randfall mehr waere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das docker-compose.yml des Haupt-Stacks deklariert kein Netz - Compose
legt <projektname>_default selbst an. Bei Portainer ist der Projektname
der Stack-Name, der in readarchive-stack.yml eingetragene Wert
noisesensors_default passt also nur, wenn das Stack auch so heisst. Sonst
bricht der Lauf mit "declared as external, but could not be found" ab.
Dazu als Option das Umbenennen des Default-Netzes (fester Name, unabhaengig
vom Stack-Namen) und der Hinweis, dass ein networks: an einem Service
dessen automatische Zuordnung aufhebt - wer dort etwas eintraegt, muss
default mit auffuehren.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
readarchive ist kein Dauerdienst, sondern ein Lauf mit Parametern. Als
Service mit profiles: ["tools"] liess er sich aus Portainer gar nicht
starten - eine Profil-Auswahl gibt es dort nicht, und ein Gegenstueck zu
"docker compose run" ebenso wenig.
Jetzt steht er in noisesensors/readarchive-stack.yml. Dieselbe Datei
bedient beide Wege: auf der Kommandozeile mit Argumenten via
"docker compose -f readarchive-stack.yml run --rm readarchive ...", im
Portainer als eigenes Stack mit den Parametern als Environment-Variablen
(readFromcsv.js liest -s/-e/-t/-d auch aus START/END/TYP/DBASE).
- eigener Projektname "name: readarchive", damit die Datei auf der
Kommandozeile nicht das Projekt des Haupt-Stacks uebernimmt
- Netz des Haupt-Stacks als external eingebunden
- README: readarchive-Abschnitt neu, Profil-Hinweis in der
Update-Anleitung ersetzt, Datei in Struktur und Dateiliste ergaenzt
- .env.example: Block fuer START/END/TYP/DBASE
- noise.tgz neu gepackt, damit die Datei mit ausgeliefert wird
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Der README beschrieb bisher nur die Erstinstallation. Neu:
- Abschnitt "Update eines laufenden Stacks" mit der Reihenfolge
Rollback sichern, Compose angleichen, nur den geaenderten Container
ziehen, verifizieren. Inklusive der beiden Fallen: der Volume-Pfad
von readin hat sich auf /opt/app/readin/data geaendert, und ein Mount
auf /etc/influxdb2 fuehrt zu Datenverlust.
- readarchive in der Container-Liste, mit Parametern und Aufruf ueber
das Profil tools.
- common/ unter den Sourcen, mit dem Hinweis, dass eine Aenderung dort
beide Container betrifft.
- deploy.sh: Tag mitgeben, sonst gibt es keinen Weg zurueck.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Der Mount aus d6e6cb3 war nie deployt - in /opt/stacks lief das Compose
ohne ihn. Auf einer zweiten Installation hat genau dieser Mount Datenverlust
verursacht: das Entrypoint legt dort beim Setup das CLI-Profil "default" an,
ein schon vorhandenes Profil laesst den Setup scheitern, und danach loescht
das Entrypoint bolt+engine im Datenverzeichnis und startet neu. Weil der
Mount das Aufraeumen ueberlebt, wiederholt sich das endlos.
Damit entspricht das Repo wieder dem, was tatsaechlich laeuft.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mongo.js, influx_post.js und logit.js lagen in beiden Komponenten doppelt
und waren auseinandergelaufen - so ist der Zeitzonen-Fehler entstanden, den
readin seit jeher richtig loest und readFromcsv.js zwei Jahre lang nicht.
Sie liegen jetzt einmal unter common/.
Wo die Fassungen sich widersprachen:
- MONGOAUTH wird als String verglichen. Die readarchive-Fassung pruefte nur
auf truthy, dadurch schaltete auch MONGOAUTH=false die Auth ein.
- writeDataArray(client, coll, data) nimmt den Collection-Namen direkt;
readarchive baut ihn mit dem neuen dataCollName(styp).
- getallProperties liefert das Array selbst. Die readarchive-Fassung mit
{error, properties} war dort ungenutzt.
- properties_collection heisst einheitlich property_coll.
Das Sammelobjekt statistics lag in readin/readdata.js und wurde von
mongo.js und influx_post.js importiert. Es liegt jetzt in
common/statistics.js, damit die gemeinsamen Module readin nicht kennen
muessen.
Der Build-Kontext beider Images ist dadurch das Repository-Wurzelverzeichnis;
das Layout im Image spiegelt das Repository, damit ../common/... unveraendert
aufgeht. Die Volume-Zeile von readin im Compose zieht deshalb auf
/opt/app/readin/data um.
readarchive folgt jetzt den Konventionen des Stacks: deploy.sh statt
build_and_copy.sh, Dockerfile_readarchive statt Dockerfile_rfcsv, und die
eigene docker-compose.yml entfaellt - der Dienst haengt als Profil "tools"
im Compose des Stacks und wird mit Parametern gestartet:
docker compose run --rm readarchive -t noise -s 2026-07-25 -e 2026-07-29
Getestet: beide Images gebaut, beide gegen Testdatenbanken laufen lassen.
Nicht deployt - die Images in der Registry sind unveraendert.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Gegenstueck zu readin/: waehrend readin alle 5 Minuten die Live-API
abfragt, liest readarchive rueckwirkend die Tagesdateien von
archive.sensor.community in dieselben Datenbanken ein.
Ohne History uebernommen (das Projekt lag bisher in einem eigenen
Repository unter Sensors/Laerm/laerm_readfromcsv_to_database).
Stand entspricht dort e33a7b7:
- Zeitstempel werden in UTC gespeichert, unabhaengig von der Zeitzone
der Maschine. readin/parse.js macht das seit jeher richtig,
readFromcsv.js lag zwei Stunden daneben.
- Fehlgeschlagene Influx-Writes werden gemeldet und setzen den
Exit-Code, statt still verloren zu gehen.
- Der Container nimmt Parameter entgegen (ENTRYPOINT in Exec-Form).
Hinweis: mongo.js, influx_post.js und logit.js gibt es auch unter
readin/, mit abweichendem Stand. Zusammenfuehren waere der naechste
Schritt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>