Monitoring IP, Port, and Website Availability with NodeJS and VizIoT

Is your home server offline again? Has your IP camera stopped streaming video? Is the internet completely down or is just one website not loading? To get instant answers to these questions, you can create a simple yet effective monitoring system.

In this article, we'll set up a script that supports Windows, macOS, and Linux. It will regularly check the availability of any internet resources and send data to the VizIoT server.

How It Works: ICMP, TCP, and HTTP

For the most accurate monitoring, our script uses three different checking methods. This is important because a device might respond to "ping" while its specific service (like a website or video stream) may not be working.

  1. ICMP (Ping): Classic device availability check via IP address or domain. Suitable for routers, servers, and general connectivity checks.
  2. TCP (Port Check): Allows checking the availability of a specific service. For example, whether port 554 on an IP camera (RTSP) or port 3306 on a database is working. If the port is open, the service is alive.
  3. HTTP/HTTPS: Website checking. The script requests page content. This is useful if the server is running but the website itself returns an error.

Why We Use These Tools?

To run the script, we need two key libraries:

  • ping package: A convenient wrapper that allows Node.js to use system connectivity utilities. It saves us from writing complex code for each OS.
  • viziot-mqtt-client-nodejs package: Official client for the VizIoT platform. It handles all MQTT protocol work: encryption, connection maintenance, and reliable data transmission to your charts.

Data Analysis: How to Distinguish Network Issues from Service Failures

The script doesn't just send "raw" numbers—it helps you become a "network detective." Looking at the chart in VizIoT, you can immediately identify the source of the problem:

  • 📈 Sharp spikes (lags) across ALL targets simultaneously: The problem is on your side. Most likely, your router is overloaded, someone on the network is saturating the channel with file downloads, or there are issues with your internet provider.
  • 📉 Spike or outage for only ONE target: Your network is fine. The problem is specifically with the target device or server (for example, the camera froze or a specific website went down).

For measurement accuracy: The script takes three measurements for each target and calculates the arithmetic mean. This eliminates random errors (single packet "dropouts") and gives you a smooth, realistic latency chart.


Final Result: Interactive Widget

Before we move to the code, take a look at what the finished widget looks like.

1. Live Monitoring Widget

What you can track with this configuration:

  • 🌐 Google.com — reference resource for checking if you have internet access at all.
  • 🏠 Local IP address — monitoring availability of devices within your network (e.g., NAS or router).
  • 📹 IP camera RTSP port — checking if video streaming is working (standard port 554).
  • 🌍 External IP addresses — monitoring availability of branches and services.

How to interpret the chart:

  • Positive values — response time in milliseconds (lower is better).
  • Value -1 — resource is unavailable.
  • 📊 Sharp spikes — possible network issues or server overload.

This approach allows you to instantly determine the source of the problem: your local network, internet provider, or a specific remote service.

2. Failure Notifications in Telegram

Seeing a problem on the chart is good, but getting an instant notification about it is even better. VizIoT allows you to set up alerts that will come to you via Telegram or email as soon as one of your resources becomes unavailable, as well as when it comes back online.

pinger_test_notif

Interested? Let's set up such a system step by step.


Setup Instructions

Step 1: Setting Up a Device in VizIoT

  1. Create a new device named VizIoTPinger.
  2. In the Basic Settings section, copy the Access Key and Access Password. The script will need them for authorization.

Step 2: Installing Node.js

Our code is cross-platform and works equally well on Windows, Linux, and macOS.

  • Windows: Download the installer from the official website.
  • Linux/macOS: We recommend using NVM:
      curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
      nvm install 24

Step 3: Creating a Project and Installing Libraries

Create a folder and install the necessary packages we mentioned above:

mkdir ./VizIoTPinger && cd ./VizIoTPinger
npm init -y
npm i ping viziot-mqtt-client-nodejs

Step 4: Monitoring Script

Create a main.js file.

nano ./main.js

Note the runMeasurements function—it's responsible for triple-checking for data accuracy.

const net = require('net')
const ping = require('ping')
const http = require('http')
const https = require('https')
const viziotMQTT = require('viziot-mqtt-client-nodejs')

// ================= SETTINGS =================
// Paste your VizIoT device key and password here
const DEVICE_KEY = '_____________'
const DEVICE_PASSWORD = '______________________'

const CHECK_INTERVAL_SEC = 3 * 60 // Interval between checks in seconds

// ================= TARGETS =================
// key    — the parameter name that will appear in VizIoT
// target — IP address, domain, or URL
// port   — port (optional, for TCP ping)
const TARGETS = [
    { key: 'home_router_latency', target: '192.168.2.1' },
    { key: 'cloudflare_dns_latency', target: '1.1.1.1' },
    { key: 'google_dns_latency', target: '8.8.8.8' },
    { key: 'google_latency', target: 'google.com' },
    { key: 'ipCamera_latency', target: '192.168.0.158', port: 554 },
    // { key: 'my_website', target: 'https://my-site.com' },
]

// ================= MQTT =================
const client = new viziotMQTT(DEVICE_KEY, DEVICE_PASSWORD)

// ================= UTILITIES =================
// Auxiliary function for performing measurements
async function runMeasurements(measureFn, attempts = 3) {
    const results = []

    for (let i = 0; i < attempts; i++) {
        results.push(await measureFn())
    }

    const valid = results.filter((r) => r > -1)

    if (valid.length === 0) {
        return { latency: -1 }
    }

    const avg = valid.reduce((a, b) => a + b, 0) / valid.length
    return { latency: Math.round(avg) }
}

// Function for checking ICMP (ping)
function checkICMP(item) {
    const measure = () =>
        new Promise((resolveRequest) => {
            ping.promise
                .probe(item.target, {
                    timeout: 5,
                })
                .then(function (res) {
                    resolveRequest(res.alive ? res.time : -1)
                })
        })
    return runMeasurements(measure)
}

// Function for checking TCP
function checkTCP(item) {
    const measure = () =>
        new Promise((resolveRequest) => {
            const socket = new net.Socket()
            const start = Date.now()

            socket.setTimeout(5000)

            socket.connect(item.port, item.target, () => {
                socket.destroy()
                resolveRequest(Date.now() - start)
            })

            socket.on('error', (e) => {
                console.log('Socket error:', e)
                socket.destroy()
                resolveRequest(-1)
            })

            socket.on('timeout', () => {
                console.log('Socket timeout')
                socket.destroy()
                resolveRequest(-1)
            })
        })

    return runMeasurements(measure)
}

// Function for checking HTTP/HTTPS
function checkURL(item) {
    const measure = () =>
        new Promise((resolveRequest) => {
            const start = Date.now()
            const lib = item.target.startsWith('https') ? https : http

            const req = lib.get(item.target, { timeout: 5000 }, (res) => {
                res.resume()
                resolveRequest(Date.now() - start)
            })

            req.on('error', () => resolveRequest(-1))
            req.on('timeout', () => {
                req.destroy()
                resolveRequest(-1)
            })
        })

    return runMeasurements(measure)
}
// ================= CHECKS =================

let isWorking = false
async function runChecks() {
    // Preventing overlapping launches
    if (isWorking) return
    isWorking = true

    console.log('🔍 Starting checks...')

    const payload = {}

    for (const item of TARGETS) {
        let result
        if (item.target.startsWith('http')) {
            result = await checkURL(item)
        } else {
            if (item.port) {
                result = await checkTCP(item)
            } else {
                result = await checkICMP(item)
            }
        }

        payload[item.key] = result.latency

        const status = result.latency >= 0 ? '✅' : '❌'
        console.log(`${status} ${item.key}: latency=${result.latency} ms`)
    }
    isWorking = false
    console.log('📨 Sending data to VizIoT:', payload)
    // client.sendDataToVizIoT(payload, (err) => {
    //  if (err) console.error('Error sending data:', err)
    // })
}

// ================= START =================
function main() {
    console.log('🔗 Try Connected to VizIoT')

    // client.connect(() => {
    console.log('✅ Connected')
    console.log('🚀 Pinger starting…')

    runChecks()
    setInterval(runChecks, CHECK_INTERVAL_SEC * 1000)
    // })
}
main()

Step 5: Auto-start with PM2

To make your script run 24/7 and start automatically after computer reboot, use the PM2 process manager:

npm install pm2 -g
pm2 start main.js --name "VizIoTPinger"
pm2 save
pm2 startup

Step 6: Configuring Widgets and Notifications in VizIoT

Now that data is coming in, all that's left is to set up the interface.

Adding Widgets

  1. Create a dashboard, for example "Internet Services Availability".
  2. Add a "Ping Time" widget.
    • Type: Stacked area chart
    • Device: VizIoTPinger
    • Parameters: home_router_latency, google_latency, ipCamera_latency

Setting Up Notifications

  1. Go to the Notifications section and click Add Notification.
  2. Device: VizIoTPinger.
  3. Parameter: Select the one you want to monitor (e.g., ipCamera_latency).
  4. Condition: Type less than (<), value 0.
  5. Enable the "Notify when returning to range" option.
  6. Choose the delivery method (Telegram, Email) and save.

Detailed instructions on setting up notifications can be found in this article.

Setting Up Telegram Notifications

Now that data is being transmitted, go to the VizIoT dashboard:

  1. Navigate to Notifications -> Add.
  2. Select your device and parameter (e.g., ipCamera_latency).
  3. Set the condition: Value < 0 (this means the service is unavailable).
  4. Enable Telegram notifications.

Now, as soon as your camera goes "offline" or a website stops loading, you'll receive a message about it within a minute!