Surveillance Station meldingen automatiseren met n8n

66f78e9c f34a 4ab1 bc9a 3dc13d958652as
Samenvatting

Synology Surveillance Station is technisch volwassen, maar de standaard notificatiestrategie – een e-mail per gebeurtenis – leidt bij meerdere camera’s al snel tot ruis en verlies van overzicht.
In dit artikel beschrijf ik hoe ik deze meldingen via een webhook, die ook beschikbaar is in een Synology Surveillance Station beschikbaar is, opvang in n8n, structureer, opsla in PostgreSQL, verrijk met afbeeldingen en publiceer op één centrale webpagina.

Het resultaat is een robuuste, uitbreidbare en grotendeels vendor-neutrale oplossing die rust en overzicht brengt.

Architectuuroverzicht

Componenten

  • Synology Surveillance Station (DS218)

  • n8n (self-hosted, Docker, DS923)

  • PostgreSQL (self-hosted, Docker)

  • SSH (inter-NAS bestandsoverdracht)

  • Synology Web Station + reverse proxy (DS923)

  • WordPress REST API (DS923)

De n8n-workflow: nodes en code

1. Webhook – ontvangst van meldingen

Node: Webhook
Doel: Ontvangt POST-verzoeken van Surveillance Station

Configuratie (GUI):

  • HTTP Method: POST

  • Path: (unieke UUID)

  • Authentication: none (afgeschermd via reverse proxy)

Surveillance Station stuurt de payload als JSON-string verpakt in een body-key.

2. Code – filter en parse melding

Node: Code Filter Meldingen

// Haal de eerste key uit de body
const bodyKey = Object.keys($input.first().json.body)[0];
// Parse de key als JSON-string
const parsedData = JSON.parse(bodyKey);// Geef alleen relevante velden door
return [{
json: {
title: parsedData.title,
desc: parsedData.desc,
event: parsedData.event

}
}];

Let op: Surveillance Station wijkt af van gangbare webhook-implementaties; expliciet parsen is noodzakelijk.

3. Code – bepaal lokaal afbeeldingspad

Node: Code bepaal afbeelding pad

const title = $json.title || 'melding';
const safeTitle = title.replace(/[^a-zA-Z0-9-_]/g, '_');
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `${timestamp}_${safeTitle}.jpg`;
return [{
json: {
...$json,
localPath: `/volume1/surveillance/webhookpictures/${filename}`
}
}];

Waarom hier?

  • De bestandsnaam is reproduceerbaar.

  • Er is geen afhankelijkheid van externe benamingen.

  • Het pad wordt later in de workflow hergebruikt voor publicatie.

4. Code – normaliseer apostrofes

Node: Code apostrofe tekens weghalen

return $input.all().map(item => {
const fixedDesc = item.json.desc.replace(/camera\('\s?s\)/g, "cameras");
return {
json: {
...item.json,
desc: fixedDesc
}
};
});

Let op: het gebruik van apostrofes kan SQL- en HTML-problemen veroorzaken. Vroegtijdig corrigeren voorkomt downstream fouten.

5. PostgreSQL – opslag van de melding

Node: Postgres upload melding

INSERT INTO surveillance_station (
timestamp,
melding,
beschrijving,
event,
webhookpictures
) VALUES (
NOW() AT TIME ZONE 'Europe/Amsterdam',
'{{ $json.title }}',
'{{ $json.desc.replace(/'/g, "''") }}',
'
{{ $json.event }}',
'
{{ $json.localPath }}'
);

Ontwerpkeuze:

  • De afbeeldingen zelf worden niet in de database opgeslagen. Alleen de metadata (timestamp, meldingsinformatie) en het pad worden opgeslagen.

  • Dit geeft betere schaalbaarheid en performance

6. SSH – download afbeelding

Node: SSH download afbeelding

sh -c 'curl -L "{{ $("Code apostrofe tekens weghalen").item.json.event }}" \
-o "{{ $("Code apostrofe tekens weghalen").item.json.localPath }}"'

Belangrijk leerpunt:

  • De SSH-node draait op de host van de credential

  • Het feit dat de workflow twee NAS-stations moet benaderen (DS218 vs DS923) was aanvankelijk verwarren. De credentials (gebruiker en wachtwoord) bepalen de fysieke uitvoeringslocatie

7. PostgreSQL – ophalen recente meldingen

Node: Postgres download 10 meldingen

SELECT
melding,
beschrijving,
event,
webhookpictures,
timestamp AT TIME ZONE 'UTC'
AT TIME ZONE 'Europe/Amsterdam' AS timestamp
FROM surveillance_station
ORDER BY id DESC
LIMIT 10;
8. Code – formatteren naar HTML

Node: Code Formatteer

const meldingen = $input.all();
const BASE_URL = 'https://surveillance.adagia.eu/webhookpictures';
let formatted = meldingen.map(item => {const timestamp = new Date(item.json.timestamp)
.toLocaleString('nl-NL', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});let imageHtml = 'Geen afbeelding';if (item.json.webhookpictures) {
const filename = item.json.webhookpictures.split('/').pop();
const imageUrl = `${BASE_URL}/${filename}`;
imageHtml = `<img src="${imageUrl}" style="max-width:100%;height:auto;" />`;
}return `
<strong>Melding:</strong>
${item.json.melding}<br/>
<strong>Beschrijving:</strong><br/>
${item.json.beschrijving.replace(/\n/g, '<br/>')}<br/><br/>
<strong>Tijdstip:</strong> ${timestamp}<br/>
${imageHtml}
<hr/>
`;
}).join('\n');return [{
json: {
content: formatted
}
}];
9. HTTP PATCH – publicatie in WordPress

Node: PATCH-webpagina

Configuratie (GUI):
  • Method: PATCH

  • URL: https://adagia.eu/wp-json/wp/v2/pages/13274

  • Auth: HTTP Basic (Application Password)

  • Body:

    {
    "content": "{{ $json.content }}"
    }
Resultaat
  • Eén dynamische webpagina

  • Alle meldingen chronologisch

  • Afbeeldingen inline zichtbaar

  • Geen mailboxvervuiling

  • Volledig automatisch

Voordelen
  • Rust en overzicht

  • Vendor-neutraal ontwerp

  • Herbruikbare architectuur

  • Uitbreidbaar met dashboards, tagging, AI-analyse

Nadelen en aandachtspunten
  • Complexiteit vereist documentatie

  • Bestandsrechten + Web Station vereisen discipline

  • Publiek toegankelijke afbeeldingen → privacy-afweging

  • Webhooks altijd afschermen

Conclusie

Deze oplossing laat zien hoe je met relatief eenvoudige bouwstenen een professioneel meldingsplatform bouwt.
Niet door méér tooling toe te voegen, maar door bestaande systemen goed te orkestreren.

Voor wie al werkt met Synology, n8n en PostgreSQL is dit een logische stap richting volwassen automatisering.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *