Professional network equipment, such as Mikrotik routers, provides a vast amount of data about their status: from CPU temperature and fan speeds to traffic on each of dozens of ports. But how do you collect all this information in one place and turn it into clear graphs for analysis?
In this article, we'll create a comprehensive monitoring system for a Mikrotik router using the SNMP protocol, and send all collected data to VizIoT to build an informative dashboard. You'll be able to track equipment status, network load in real-time, and quickly identify problems.
Before we begin, take a look at the powerful and intuitive monitoring dashboard we'll create. It will allow you to track everything: from overall uptime and power supply status to detailed load on each SFP port.
Interested? Let's set up such a system. It's easier than it seems.
SNMP (Simple Network Management Protocol) is a standard way for network devices to provide information about their status.
public by default. This is the community name that works like a password. You can leave it or change it, but make sure it matches the settings in our script.Now your router is ready to provide data via SNMP.
On the computer that will collect data, we'll install everything necessary.
Detailed documentation: https://nodejs.org
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
\. "$HOME/.nvm/nvm.sh"
nvm install 24
node -v
npm -v
mkdir mikrotik-monitor
cd mikrotik-monitor
npm init -y
npm install net-snmp big-integer viziot-mqtt-client-nodejs
Create an index.js file:
nano index.js
Insert the following code. Don't forget to specify your data in the CONFIG section.
const snmp = require("net-snmp");
const bigInt = require("big-integer");
const viziotMQTT = require("viziot-mqtt-client-nodejs");
// Configuration
const CONFIG = {
keyDevice: "YOUR_DEVICE_KEY", // VizIoT device key
passDevice: "YOUR_DEVICE_PASSWORD", // VizIoT device password
intervalSendData: 30000, // Polling interval in milliseconds (30 seconds)
ipRouter: "192.168.0.25", // IP address of your Mikrotik router
snmpCommunity: "public", // SNMP community name (must match router settings)
};
// Value converters
const hexToBigInt = (value) => +bigInt(`0x${value.toString('hex')}`).toString(10)
const divideBy10 = (value) => value / 10
const divideBy100ToDay = (value) => value / 100 / 60 / 60 / 24
const identity = (value) => value
// OID generator for rx and tx ports
const generatePortOIDs = () => {
const oids = {}
const rxBase = '1.3.6.1.4.1.14988.1.1.14.1.1.31'
const txBase = '1.3.6.1.4.1.14988.1.1.14.1.1.61'
// SFPP1 port
oids[`${rxBase}.1`] = { key: 'rx_sfpp1', convert: hexToBigInt }
oids[`${txBase}.1`] = { key: 'tx_sfpp1', convert: hexToBigInt }
// SFP ports 1-12
for (let i = 1; i <= 12; i++) {
oids[`${rxBase}.${i + 1}`] = { key: `rx_sfp${i}`, convert: hexToBigInt }
oids[`${txBase}.${i + 1}`] = { key: `tx_sfp${i}`, convert: hexToBigInt }
}
return oids
}
// OID generator for CPU load
const generateProcessorLoadOIDs = () => {
const oids = {}
const base = '1.3.6.1.2.1.25.3.3.1.2.'
// 16-core processor
for (let i = 1; i <= 16; i++) {
oids[`${base}.${i}`] = { key: `cpu${i}`, convert: identity }
}
return oids
}
// SNMP OID configuration
const SNMP_OIDS = {
'1.3.6.1.2.1.1.3.0': { key: 'uptime', convert: divideBy100ToDay },
...generatePortOIDs(),
'1.3.6.1.4.1.14988.1.1.3.11.0': { key: 'processorTemp', convert: divideBy10 },
'1.3.6.1.4.1.14988.1.1.3.15.0': { key: 'power1State', convert: identity },
'1.3.6.1.4.1.14988.1.1.3.16.0': { key: 'power2State', convert: identity },
'1.3.6.1.4.1.14988.1.1.3.17.0': { key: 'fan1RPM', convert: identity },
'1.3.6.1.4.1.14988.1.1.3.18.0': { key: 'fan2RPM', convert: identity },
...generateProcessorLoadOIDs(),
}
// Class for working with SNMP data
class SNMPMonitor {
constructor() {
this.prevResult = null
this.mqttClient = new viziotMQTT(CONFIG.keyDevice, CONFIG.passDevice)
this.intervalId = null
}
start() {
this.mqttClient.connect(() => {
console.log(new Date(), 'MQTT connected')
this.startPolling()
})
}
startPolling() {
if (this.intervalId) {
clearInterval(this.intervalId)
}
this.intervalId = setInterval(() => this.poll(), CONFIG.intervalSendData)
}
async poll() {
try {
const result = await this.getSNMPData()
if (!result) {
console.log(new Date(), 'SNMP result is empty')
return
}
if (!this.prevResult) {
this.prevResult = result
console.log(new Date(), 'First SNMP result received')
return
}
const packet = this.buildPacket(result)
this.prevResult = result
// console.log(packet)
this.mqttClient.sendDataToVizIoT(packet, (err) => {
if (!err) console.log(new Date(), 'Packet sent')
})
} catch (error) {
console.error(new Date(), 'Polling error:', error)
}
}
getSNMPData() {
return new Promise((resolve) => {
const session = snmp.createSession(CONFIG.ipRouter, CONFIG.snmpCommunity)
const oids = Object.keys(SNMP_OIDS)
session.get(oids, (error, varbinds) => {
session.close()
if (error) {
console.error(new Date(), 'SNMP varbinds:', varbinds)
console.error(new Date(), 'SNMP error:', error)
resolve(null)
return
}
const result = { timeGet: Date.now() }
varbinds.forEach((varbind) => {
if (snmp.isVarbindError(varbind)) {
console.error(new Date(), snmp.varbindError(varbind))
return
}
const config = SNMP_OIDS[varbind.oid]
if (config) {
result[config.key] = config.convert(varbind.value)
}
})
resolve(result)
})
})
}
// Calculate CPU load statistics
calculateCPUStats(current) {
const cpuLoads = []
// Collect load values for all cores
for (let i = 1; i <= 16; i++) {
const cpuKey = `cpu${i}`
if (current[cpuKey] !== undefined) {
cpuLoads.push(current[cpuKey])
}
}
if (cpuLoads.length === 0) {
return { avg: 0, min: 0, max: 0 }
}
// Calculate average, minimum, and maximum
const sum = cpuLoads.reduce((acc, val) => acc + val, 0)
const avg = Math.round((sum / cpuLoads.length) * 100) / 100
const min = Math.min(...cpuLoads)
const max = Math.max(...cpuLoads)
return { avg, min, max }
}
buildPacket(current) {
const elapsedSec = Math.round((current.timeGet - this.prevResult.timeGet) / 1000)
// Calculate CPU statistics
const cpuStats = this.calculateCPUStats(current)
const packet = {
date: Math.floor(Date.now() / 1000),
uptime: current.uptime,
processorTemp: current.processorTemp,
cpuAvg: cpuStats.avg, // Average CPU load
cpuMin: cpuStats.min, // Minimum load across cores
cpuMax: cpuStats.max, // Maximum load across cores
power1State: current.power1State,
power2State: current.power2State,
fan1RPM: current.fan1RPM,
fan2RPM: current.fan2RPM,
aggRxMb: 0,
aggTxMb: 0,
}
// Calculate speeds for all ports
const ports = ['sfpp1', ...Array.from({ length: 12 }, (_, i) => `sfp${i + 1}`)]
ports.forEach((port) => {
const rxKey = `rx_${port}`
const txKey = `tx_${port}`
if (current[rxKey] !== undefined && this.prevResult[rxKey] !== undefined) {
const rxMb = this.calcBandwidth(current[rxKey], this.prevResult[rxKey], elapsedSec)
const txMb = this.calcBandwidth(current[txKey], this.prevResult[txKey], elapsedSec)
const portName = port.charAt(0).toUpperCase() + port.slice(1)
packet[`rx${portName}Mb`] = rxMb
packet[`tx${portName}Mb`] = txMb
packet.aggRxMb += rxMb
packet.aggTxMb += txMb
}
})
return packet
}
calcBandwidth(current, previous, seconds) {
return ((current - previous) / seconds / 1024 / 1024) * 8
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId)
this.intervalId = null
}
}
}
// Start monitoring
const monitor = new SNMPMonitor()
monitor.start()
// Process termination handling
process.on('SIGINT', () => {
console.log('\nStopping monitoring...')
monitor.stop()
process.exit(0)
})
To keep the script running 24/7, we'll use the PM2 process manager.
Install PM2 globally:
npm install pm2 -g
Start the script via PM2:
pm2 start index.js --name "mikrotik-monitor"
Configure PM2 autostart on system boot:
pm2 startup
Copy and execute the command that PM2 provides.
Save the current process list:
pm2 save
Now your collector script will reliably run in the background.
The most interesting part! Data is coming in, and now we can visualize it.
Create a new dashboard named "Mikrotik Router".
Start adding widgets. VizIoT will automatically create parameters when receiving the first data. Here are some widget ideas:
uptime, power1State, power2State.processorTemp or fan1RPM.aggRxMb (incoming) and aggTxMb (outgoing) parameters to one chart.processorTemp, fan1RPM, fan2RPM on another chart.rx...Mb and tx...Mb parameters to them.Experiment with widget types and layouts to create a dashboard that perfectly suits your needs.
You've created a powerful and flexible monitoring system for your Mikrotik router. Now you'll always be aware of your network equipment's status and can quickly respond to any anomalies in traffic or device operation.