DIY downtime monitor with NodeRED
Tags: iot, devicemanagement, synpsenodered
Published: 2021-10-26 11:52:43

"Black box" monitoring is one of the key concepts, when monitoring any application. We will show how to deploy a free DIY downtime monitoring stack, using NodeRed and Synpse.

Similar pattern could be used to do almost any home automation. So go crazy! We use this pattern as its easy to modify, and not does much maintenance.

> Synpse is an end-to-end platform to manage your device fleet that can grow to hundreds of thousands of devices, perform OTA software updates, collect metrics, logs, deploy your containerized applications and facilitate tunnel-based SSH access to any of your device. You can find a Quick Start here .

## Technologies used

[Synpse](https://cloud.synpse.net/) for hosting and running applications anywhere
[NodeRED](https://nodered.org/) for instrumenting our monitoring

## NodeRED

We will use NodeRED as instrumentation tool to “write code without writing any code” and monitor our web pages availability. If downtime is detected, we will notify administrators via slack or discord message.

First lets deploy NodeRED into Synpse enable IoT device we own. We use simple RPI4 under the desk at home:

```yaml
name: NodeRed
description: Low-code programming for event-driven applications
type: container
scheduling:
  type: Selector
  # More on selectors https://docs.synpse.net/synpse-core/applications/scheduling
  selectors:
    nodered: master
spec:
  containers:
  - name: nodered
    image: nodered/node-red:latest-minimal
    user: root
    ports:
      - "1880:1880"
    volumes:
      - /data/nodered:/data
      - /etc/localtime:/etc/localtime
      - /root/.ssh:/root/.ssh
```
Access the remote device via Synpse proxy CLI command to configure it

```
synpse device proxy <device_name> --port 1880
```

Open the browser page [http://localhost:1880](http://localhost:1880). You should be able to see NodeRed running.

## Downtime flow

We use Discord webhook integration to send a messages and alert our developers once page is down. Discord webhook documentation can be found [here](https://discord.com/developers/docs/resources/webhook)

![Discord webhook](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/utdi3di8qhk8mo6ndecy.png)

Flow we created is very simple:

1. Every 5 seconds cloud.synpse.net health url
2. If response is not 200, go to next phase, else drop
3. Rate limit to send only 1 message every 5 min
4. Create a Webhook payload
5. Send POST request to webhook URL

Flow itself looks like this (we have left if 200 branch too, in case you want to re-use it for other purposes). Full json flow can be found bellow for you to reuse.

![NodeRED flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7k6v8n4pyoe081roheh2.png)

Press “deploy” and you are done :)

![Message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2uef3gj0bww7ke9qp6w3.png)

This is very simple way to monitor your applications or construct any other automation flows. In addition you can deploy same application to different agents across the globe, and you have free Region based downtime monitoring!

## ./wrap_up.sh

If you have any questions or suggestions, feel free to start a new discussion in our forum or drop us a line on [Discord](https://discord.gg/dkgN4vVNdm)

Originally published at [Synpse.net blog](https://synpse.net/blog/nodered/downtime-monitor-nodered/)

## Full flow

```json
[
    {
        "id": "90902c5d92f08930",
        "type": "tab",
        "label": "NodeRed on Synpse",
        "disabled": false,
        "info": ""
    },
    {
        "id": "ef34b5db67c67385",
        "type": "http request",
        "z": "90902c5d92f08930",
        "name": "<PAGE_TO_CHECK_NAME>",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "<PAGE_TO_CHECK_URL>",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "x": 370,
        "y": 260,
        "wires": [
            [
                "2109536ce55f85cf",
                "1aae7673af94fb6c"
            ]
        ]
    },
    {
        "id": "3c39826c5c2c418b",
        "type": "inject",
        "z": "90902c5d92f08930",
        "name": "ticker 5s",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "5",
        "crontab": "",
        "once": true,
        "onceDelay": "1",
        "topic": "",
        "payload": "{}",
        "payloadType": "json",
        "x": 150,
        "y": 260,
        "wires": [
            [
                "ef34b5db67c67385"
            ]
        ]
    },
    {
        "id": "2109536ce55f85cf",
        "type": "switch",
        "z": "90902c5d92f08930",
        "name": "if not 200",
        "property": "statusCode",
        "propertyType": "msg",
        "rules": [
            {
                "t": "neq",
                "v": "200",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 580,
        "y": 200,
        "wires": [
            [
                "758156729b55665f"
            ]
        ]
    },
    {
        "id": "1aae7673af94fb6c",
        "type": "switch",
        "z": "90902c5d92f08930",
        "name": "if  200",
        "property": "statusCode",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "200",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 570,
        "y": 300,
        "wires": [
            []
        ]
    },
    {
        "id": "758156729b55665f",
        "type": "delay",
        "z": "90902c5d92f08930",
        "name": "",
        "pauseType": "rate",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "5",
        "rateUnits": "minute",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": true,
        "allowrate": false,
        "x": 740,
        "y": 260,
        "wires": [
            [
                "a062d51eb49713f9"
            ]
        ]
    },
    {
        "id": "2452ffaa52e6333f",
        "type": "http request",
        "z": "90902c5d92f08930",
        "name": "discord webhook",
        "method": "POST",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "<DISCORD_WEBHOOK_URL>",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "x": 1110,
        "y": 260,
        "wires": [
            []
        ]
    },
    {
        "id": "a062d51eb49713f9",
        "type": "function",
        "z": "90902c5d92f08930",
        "name": "payload",
        "func": "var payload = {\n  \"username\": \"Downtime BOT\",\n  \"avatar_url\": \"https://i.imgur.com/zEGYUVs.jpeg\",\n  \"content\": \"cloud.synpse.net Downtime detected. Next check in 5 min\",\n}\n\nmsg.payload = payload\nreturn msg",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 920,
        "y": 260,
        "wires": [
            [
                "2452ffaa52e6333f"
            ]
        ]
    }
]
```