kann deployed werde (zum ersten Mal)

This commit is contained in:
2025-08-19 13:43:37 +00:00
parent b3b411db1a
commit e7e6cb97ca
12 changed files with 453 additions and 92 deletions

6
beschreibung.md Normal file
View File

@@ -0,0 +1,6 @@
# Beschreibung von esp2senor
rxf 2025-08-19
### Aufruf
~~~~
esp2sensor.

63
build_and_copy.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/bin/bash
# Build Docker-Container
#
# Call: buildit.sh name [target]
#
# The Dockerfile must be named like Dockerfile_name
#
# 2018-09-20 rxf
# - before sending docker image to remote, tag actual remote image
#
# 2018-09-14 rxf
# - first Version
#
set -x
port=""
orgName=esp2sensor
name=esp2sensor
usage()
{
echo "Usage build_and_copy.sh [-p port] [-n name] target"
echo " Build docker container $name and copy to target"
echo "Params:"
echo " target: Where to copy the container to "
echo " -p port: ssh port (default 22)"
echo " -n name: new name for container (default: $orgName)"
}
while getopts n:p:h? o
do
case "$o" in
n) name="$OPTARG";;
p) port="-p $OPTARG";;
h) usage; exit 0;;
*) usage; exit 1;;
esac
done
shift $((OPTIND-1))
while [ $# -gt 0 ]; do
if [[ -z "$target" ]]; then
target=$1
shift
else
echo "bad option $1"
# exit 1
shift
fi
done
docker build -f Dockerfile_$orgName --no-cache -t $name .
dat=`date +%Y%m%d%H%M`
if [ "$target" == "localhost" ]
then
docker tag $name $name:V_$dat
exit
fi
ssh $port $target "docker tag $name $name:V_$dat"
docker save $name | bzip2 | pv | ssh $port $target 'bunzip2 | docker load'

View File

@@ -1,38 +1,41 @@
import { MongoClient } from 'mongodb';
import dotenv from 'dotenv';
dotenv.config();
const MONGO_ROOT_USER = process.env.MONGO_ROOT_USER;
const MONGO_ROOT_PASSWORD = process.env.MONGO_ROOT_PASSWORD;
let MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017';
/* if (MONGO_ROOT_USER && MONGO_ROOT_PASSWORD) {
const uriParts = MONGO_URI.split('://');
if (uriParts.length === 2) {
const protocol = uriParts[0];
const rest = uriParts[1];
MONGO_URI = `${protocol}://${encodeURIComponent(MONGO_ROOT_USER)}:${encodeURIComponent(MONGO_ROOT_PASSWORD)}@${rest}`;
}
const MONGOHOST = process.env.MONGOHOST || 'localhost'
const MONGOPORT = process.env.MONGOPORT || 27017
const MONGOAUTH = process.env.MONGOAUTH || false
const MONGOUSRP = process.env.MONGOUSRP || ''
const MONGOBASE = process.env.MONGOBASE || 'sensor_data'
let MONGO_URL = 'mongodb://'+MONGOHOST+':'+MONGOPORT; // URL to mongo database
if (MONGOAUTH === 'true') {
MONGO_URL = 'mongodb://'+MONGOUSRP+'@' + MONGOHOST + ':' + MONGOPORT + '/?authSource=admin'; // URL to mongo database
}
*/
const DB_NAME = MONGOBASE
const DB_NAME = process.env.DB_NAME || 'sensor_data';
let db, entriesCollection, usersCollection, prop_fluxCollection, propertiesCollection;
let db, usersCollection, prop_fluxCollection, propertiesCollection;
let client = null;
export async function initMongo() {
const client = new MongoClient(MONGO_URI);
const client = new MongoClient(MONGO_URL);
await client.connect();
db = client.db(DB_NAME);
entriesCollection = db.collection('entries');
usersCollection = db.collection('users');
prop_fluxCollection = db.collection('prop_flux');
propertiesCollection = db.collection('properties')
return { db, entriesCollection, usersCollection };
return { db, usersCollection, prop_fluxCollection, propertiesCollection};
}
export const clientClose = async () => {
if (client) {
client.close()
}
}
export function getCollections() {
return { db, entriesCollection, usersCollection, prop_fluxCollection };
return { db, usersCollection, prop_fluxCollection, propertiesCollection};
}
export const update_pflux = async(sn, doc) => {

36
deploy.sh Executable file
View File

@@ -0,0 +1,36 @@
# Deplay ein Sensor-File auf das docker registry (docker.citysensor.de)
#
# v 1.0 2024-09-01 rxf
# erste Version
#set -x
registry=docker.citysensor.de
name=esp2sensor
usage()
{
echo "Usage ./deploy.sh"
echo " Build docker container '$name' and deploy to $registry"
echo "Params:"
echo " -h show this usage"
}
while getopts h? o
do
case "$o" in
h) usage; exit 0;;
*) usage; exit 1;;
esac
done
shift $((OPTIND-1))
./build_and_copy.sh localhost
docker tag $name docker.citysensor.de/$name:latest
dat=`date +%Y%m%d%H%M`
docker tag $name docker.citysensor.de/$name:V_$dat
docker push docker.citysensor.de/$name

View File

@@ -1,18 +1,15 @@
services:
app:
build: .
container_name: esp-app
container_name: esp2sensor
ports:
- "3000:3000"
environment:
- PORT=3000
- MONGO_URI=mongodb://mongo:27017
- DB_NAME=espdb
depends_on:
- mongo
volumes:
- .:/app # bind mount für Live-Reload
- /app/node_modules # node_modules vom Host nicht überschreiben
- ./log:/var/log
restart: unless-stopped
mongo:

311
log/esp2sensor.log Normal file
View File

@@ -0,0 +1,311 @@
[dotenv@17.2.1] injecting env (10) from .env -- tip: 🛠️ run anywhere with `dotenvx run -- yourcommand`
[dotenv@17.2.1] injecting env (0) from .env -- tip: 🔐 prevent building .env in docker: https://dotenvx.com/prebuild
/app/node_modules/mongodb/lib/sdam/topology.js:326
const timeoutError = new error_1.MongoServerSelectionError(`Server selection timed out after ${timeout?.duration} ms`, this.description);
^
MongoServerSelectionError: connect ECONNREFUSED 192.168.16.2:2017
at Topology.selectServer (/app/node_modules/mongodb/lib/sdam/topology.js:326:38)
at async Topology._connect (/app/node_modules/mongodb/lib/sdam/topology.js:200:28)
at async Topology.connect (/app/node_modules/mongodb/lib/sdam/topology.js:152:13)
at async topologyConnect (/app/node_modules/mongodb/lib/mongo_client.js:258:17)
at async MongoClient._connect (/app/node_modules/mongodb/lib/mongo_client.js:271:13)
at async MongoClient.connect (/app/node_modules/mongodb/lib/mongo_client.js:196:13)
at async initMongo (file:///app/db/mongo.js:21:3)
at async file:///app/server.js:35:1 {
errorLabelSet: Set(0) {},
reason: TopologyDescription {
type: 'Unknown',
servers: Map(1) {
'mongo:2017' => ServerDescription {
address: 'mongo:2017',
type: 'Unknown',
hosts: [],
passives: [],
arbiters: [],
tags: {},
minWireVersion: 0,
maxWireVersion: 0,
roundTripTime: -1,
minRoundTripTime: 0,
lastUpdateTime: 72112013,
lastWriteDate: 0,
error: MongoNetworkError: connect ECONNREFUSED 192.168.16.2:2017
at Socket.<anonymous> (/app/node_modules/mongodb/lib/cmap/connect.js:286:44)
at Object.onceWrapper (node:events:639:26)
at Socket.emit (node:events:524:28)
at emitErrorNT (node:internal/streams/destroy:169:8)
at emitErrorCloseNT (node:internal/streams/destroy:128:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
errorLabelSet: Set(1) { 'ResetPool' },
beforeHandshake: false,
[cause]: Error: connect ECONNREFUSED 192.168.16.2:2017
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1611:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '192.168.16.2',
port: 2017
}
},
topologyVersion: null,
setName: null,
setVersion: null,
electionId: null,
logicalSessionTimeoutMinutes: null,
maxMessageSizeBytes: null,
maxWriteBatchSize: null,
maxBsonObjectSize: null,
primary: null,
me: null,
'$clusterTime': null,
iscryptd: false
}
},
stale: false,
compatible: true,
heartbeatFrequencyMS: 10000,
localThresholdMS: 15,
setName: null,
maxElectionId: null,
maxSetVersion: null,
commonWireVersion: 0,
logicalSessionTimeoutMinutes: null
},
code: undefined,
[cause]: MongoNetworkError: connect ECONNREFUSED 192.168.16.2:2017
at Socket.<anonymous> (/app/node_modules/mongodb/lib/cmap/connect.js:286:44)
at Object.onceWrapper (node:events:639:26)
at Socket.emit (node:events:524:28)
at emitErrorNT (node:internal/streams/destroy:169:8)
at emitErrorCloseNT (node:internal/streams/destroy:128:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
errorLabelSet: Set(1) { 'ResetPool' },
beforeHandshake: false,
[cause]: Error: connect ECONNREFUSED 192.168.16.2:2017
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1611:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '192.168.16.2',
port: 2017
}
}
}
Node.js v20.19.4
[dotenv@17.2.1] injecting env (10) from .env -- tip: ⚙️ specify custom .env file path with { path: '/custom/path/.env' }
[dotenv@17.2.1] injecting env (0) from .env -- tip: ⚙️ override existing env vars with { override: true }
[dotenv@17.2.1] injecting env (10) from .env -- tip: ⚙️ specify custom .env file path with { path: '/custom/path/.env' }
[dotenv@17.2.1] injecting env (0) from .env -- tip: 📡 version env with Radar: https://dotenvx.com/radar
Server läuft auf http://localhost:3000
Address lookup failed: TypeError: fetch failed
at node:internal/deps/undici/undici:13510:13
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async file:///app/routes/address.js:44:19 {
[cause]: Error: getaddrinfo EAI_AGAIN sensorapi
at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:120:26) {
errno: -3001,
code: 'EAI_AGAIN',
syscall: 'getaddrinfo',
hostname: 'sensorapi'
}
}
file:///app/routes/address.js:59
await client.close();
^
ReferenceError: client is not defined
at file:///app/routes/address.js:59:5
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Node.js v20.19.4
[dotenv@17.2.1] injecting env (10) from .env -- tip: 🔐 prevent committing .env to code: https://dotenvx.com/precommit
[dotenv@17.2.1] injecting env (0) from .env -- tip: ⚙️ load multiple .env files with { path: ['.env.local', '.env'] }
Server läuft auf http://localhost:3000
Address lookup failed: TypeError: fetch failed
at node:internal/deps/undici/undici:13510:13
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async file:///app/routes/address.js:44:19 {
[cause]: Error: getaddrinfo EAI_AGAIN sensorapi
at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:120:26) {
errno: -3001,
code: 'EAI_AGAIN',
syscall: 'getaddrinfo',
hostname: 'sensorapi'
}
}
file:///app/routes/address.js:59
await client.close();
^
ReferenceError: client is not defined
at file:///app/routes/address.js:59:5
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Node.js v20.19.4
[dotenv@17.2.1] injecting env (10) from .env -- tip: ⚙️ specify custom .env file path with { path: '/custom/path/.env' }
[dotenv@17.2.1] injecting env (0) from .env -- tip: ⚙️ load multiple .env files with { path: ['.env.local', '.env'] }
Server läuft auf http://localhost:3000
[dotenv@17.2.1] injecting env (9) from .env -- tip: 🔐 prevent building .env in docker: https://dotenvx.com/prebuild
[dotenv@17.2.1] injecting env (0) from .env -- tip: ⚙️ enable debug logging with { debug: true }
Server läuft auf http://localhost:3000
[dotenv@17.2.1] injecting env (9) from .env -- tip: ⚙️ specify custom .env file path with { path: '/custom/path/.env' }
[dotenv@17.2.1] injecting env (0) from .env -- tip: ⚙️ specify custom .env file path with { path: '/custom/path/.env' }
Server läuft auf http://localhost:3000
[dotenv@17.2.1] injecting env (9) from .env -- tip: ⚙️ suppress all logs with { quiet: true }
[dotenv@17.2.1] injecting env (0) from .env -- tip: ⚙️ enable debug logging with { debug: true }
Server läuft auf http://localhost:3000
https://noise.fuerst-stuttgart.de/srv/getaddressgetaddress/?sensorid=37833
https://noise.fuerst-stuttgart.de/srv/getaddressgetaddress/?sensorid=37833
[dotenv@17.2.1] injecting env (9) from .env -- tip: ⚙️ write to custom object with { processEnv: myObject }
[dotenv@17.2.1] injecting env (0) from .env -- tip: ⚙️ write to custom object with { processEnv: myObject }
Server läuft auf http://localhost:3000
https://noise.fuerst-stuttgart.de/srv/getaddress/?sensorid=37833
https://noise.fuerst-stuttgart.de/srv/getaddress/?sensorid=79222
https://noise.fuerst-stuttgart.de/srv/getaddress/?sensorid=79222
https://noise.fuerst-stuttgart.de/srv/getaddress/?sensorid=79222
https://noise.fuerst-stuttgart.de/srv/getaddress/?sensorid=79222
https://noise.fuerst-stuttgart.de/srv/getaddress/?sensorid=79222
https://noise.fuerst-stuttgart.de/srv/getaddress/?sensorid=37833
https://noise.fuerst-stuttgart.de/srv/getaddress/?sensorid=37833
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4
node:internal/modules/cjs/loader:1215
throw err;
^
Error: Cannot find module '/app/server.js'
at Module._resolveFilename (node:internal/modules/cjs/loader:1212:15)
at Module._load (node:internal/modules/cjs/loader:1043:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v20.19.4

View File

@@ -5,7 +5,7 @@
"description": "Kleine Webapp ESP-ID <-> Sensornummer, speichern in MongoDB",
"main": "server.js",
"scripts": {
"start": "node server.js",
"start": "node server.js >>/var/log/esp2sensor.log 2>&1",
"dev": "nodemon --watch server.js --watch views --watch public server.js",
"test": "jest"
},

View File

@@ -55,6 +55,7 @@ async function fetchAddressIfValid() {
try {
const res = await fetch(`/api/address/${value}`);
const data = await res.json();
console.dir(data)
if (!data.error && data.address) {
addressInput.value = data.address;
// Felder automatisch füllen, wenn props vorhanden

View File

@@ -1,8 +1,9 @@
import { MongoClient } from 'mongodb';
import { get_pflux } from '../db/mongo.js';
import { getCollections, update_pflux, clientClose } from '../db/mongo.js';
export function registerAddressRoute(app, requireLogin) {
const ADDRESS_SERVICE_URL = process.env.ADDRESS_SERVICE_URL || 'https://noise.fuerst-stuttgart.de/srv/getaddress';
const APIHOST = process.env.APIHOST || 'https://noise.fuerst-stuttgart.de/srv/';
app.get('/api/address/:sensorNumber', requireLogin, async (req, res) => {
const sensorNumber = parseInt(req.params.sensorNumber, 10);
@@ -10,18 +11,12 @@ export function registerAddressRoute(app, requireLogin) {
return res.status(400).json({ error: 'Ungültige Sensornummer' });
}
// Verbindung zur sensor_data DB
const mongoUri = process.env.MONGO_URI || 'mongodb://localhost:27017';
const client = new MongoClient(mongoUri);
await client.connect();
const sensorDb = client.db('sensor_data');
const properties = sensorDb.collection('properties');
const propFlux = sensorDb.collection('prop_flux');
const { propertiesCollection, prop_fluxCollection } = getCollections();
// Suche nach Sensornummer als _id
const propEntry = await properties.findOne({ _id: sensorNumber });
const propEntry = await propertiesCollection.findOne({ _id: sensorNumber });
if (!propEntry) {
await client.close();
await clientClose()
return res.status(404).json({ error: 'Sensor nicht gefunden' });
}
@@ -38,6 +33,8 @@ export function registerAddressRoute(app, requireLogin) {
} catch (err) {
console.error('Fehler beim Kopieren nach prop_flux:', err);
// Kein Abbruch, nur Logging
} finally {
await clientClose()
}
}
@@ -45,7 +42,8 @@ export function registerAddressRoute(app, requireLogin) {
let addressString = '';
let addrParts = {};
try {
const url = ADDRESS_SERVICE_URL + `?sensorid=${encodeURIComponent(propEntry._id)}`;
const url = APIHOST + 'getaddress/' + `?sensorid=${encodeURIComponent(propEntry._id)}`;
console.log(url)
const r = await fetch(url, { headers: { 'Accept': 'application/json' } });
if (r.ok) {
const data = await r.json();
@@ -61,8 +59,6 @@ export function registerAddressRoute(app, requireLogin) {
console.error('Address lookup failed:', err);
}
await client.close();
return res.json({
address: addressString,
parts: addrParts,

View File

@@ -3,7 +3,7 @@ import bcrypt from 'bcrypt';
import { getCollections, update_pflux } from '../db/mongo.js';
export function registerApiRoutes(app, requireLogin) {
const { entriesCollection, usersCollection, prop_fluxCollection } = getCollections();
const { usersCollection, prop_fluxCollection } = getCollections();
app.get('/api/check-email', async (req, res) => {
const email = (req.query.email || '').toLowerCase().trim();

View File

@@ -1,52 +0,0 @@
import express from 'express';
import session from 'express-session';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
dotenv.config();
import { initMongo } from './db/mongo.js';
import { registerApiRoutes } from './routes/api.js';
import { registerAuthRoutes } from './routes/auth.js';
import { registerAddressRoute } from './routes/address.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
const PORT = process.env.PORT || 3000;
const SESSION_SECRET = process.env.SESSION_SECRET || 'supersecret';
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { maxAge: 24 * 60 * 60 * 1000 }
}));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// DB verbinden
await initMongo();
// Login-Middleware
function requireLogin(req, res, next) {
// if (req.session.userId) return next();
// res.redirect('/login');
return next();
}
// Routen registrieren
registerAuthRoutes(app);
registerApiRoutes(app, requireLogin);
registerAddressRoute(app, requireLogin);
// Hauptseite
app.get('/', requireLogin, (req, res) => res.render('index'));
app.listen(PORT, () => console.log(`Server läuft auf http://localhost:${PORT}`));