IPerfect UDP Data Plotter
User Guide
Open the Plotter
1

What this tool does

The UDP Data Plotter draws numbers out of UDP datagrams sent to iperfect.net:49152 onto a live time-series chart. It is the UDP twin of the MQTT Live Data Plotter: same chart, same console, same configuration — only the transport differs. It does not know anything about your payload format; you tell it how to pull the numbers out, using one regular expression and one short line of JavaScript per line on the chart.

Your device sends a datagram
Listener udp://iperfect.net:49152
This page polls for new packets
Expression 1 splits it into regEx[ ]
Expressions 2…n addPoint() per series
Live chart redrawn per datagram

Nothing about your data leaves this server: the page talks to ajax/udp_monitor.php on iperfect.net, which reads the Node listener over the loopback interface. That is the same path the UDP Monitor tab uses.

2

Before you start

Only datagrams that arrive after you press Start are plotted. The listener keeps a rolling buffer, but replaying it would stamp every old datagram with the time of the replay, so the page skips whatever was already buffered and begins from the next packet.
  • Send to iperfect.net on UDP port 49152. Both fields are fixed — that is the only port the listener service binds.
  • Your payload has to be text. Binary bytes are shown as dots in the console and cannot be matched by a regular expression. Send temp=25.5, not a packed struct.
  • UDP is fire-and-forget. A datagram can be lost, duplicated or arrive out of order, and nothing tells the sender. Gaps in a line are normal on a busy or distant link — the plotter draws what arrived.
  • Keep a datagram under 8 KB; larger ones are dropped before they reach the buffer.
  • Use a current Chrome, Edge or Firefox. The page only reads — it never sends anything back to your device.
3

Sending test data

If nothing is publishing yet, send a datagram by hand and watch it land in the console. Run one of these from any machine with internet access.

Shell — netcat

echo "node1,2340,17,1.42,-0.87,9.61" | nc -u -w1 iperfect.net 49152

Shell — a stream of readings

while true; do
  echo "node1,2340,17,$RANDOM.0,$RANDOM.0,$RANDOM.0" | nc -u -w0 iperfect.net 49152
  sleep 1
done

Python

import socket, time, random
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
    msg = "node1,2340,17,%.2f,%.2f,%.2f" % (random.uniform(-2, 2),
                                            random.uniform(-2, 2),
                                            random.uniform(8, 11))
    s.sendto(msg.encode(), ("iperfect.net", 49152))
    time.sleep(1)

ESP32 / ESP8266 — Arduino

#include <WiFiUdp.h>
WiFiUDP udp;

void sendReading(float t) {
  udp.beginPacket("iperfect.net", 49152);
  udp.printf("node1,temp=%.2f", t);
  udp.endPacket();
}
Press Start Monitoring first, then send. The console shows <source ip>:<port> → <your text> for every datagram that arrives — that is your proof the path works, before any parsing is involved.
4

Quick start

  1. Start monitoring. Leave Host and UDP Port as they are and press Start Monitoring. The status pill turns green and reads Monitoring :49152.
  2. Read one datagram. Send something (see section 3) and copy one line out of the Incoming UDP Datagrams console. Everything after the arrow is what your expressions will see as data.
  3. Name your lines. In Axis Configuration set X-Axis data types to plot to how many lines you want, press Apply, then type a name into each row.
  4. Write the expressions. In RegEx Configuration set Expressions to plot to one + one per line and press Apply. Row 1 splits the datagram (tick Is RegEx); the rest plot (leave it unticked).
  5. Save Configuration. The page reloads with your settings, so press Start Monitoring again. Points appear as datagrams arrive.
Saving reloads the page, which stops the monitor. That is expected — configure first, then start.
5

How parsing works

Every row in RegEx Configuration runs once per datagram, top to bottom. The Is RegEx tick is what decides how it runs:

Is RegEx What the row does
Ticked The text is treated as a regular expression. The plotter matches it against the datagram text and stores every match in the regEx array. It draws nothing by itself.
Unticked The text is treated as a line of JavaScript and executed as written. This is where you call addPoint().

What you can use inside a row

Name Meaning
data The text of the datagram that just arrived.
pkt The whole packet record — pkt.from (sender IP), pkt.sport (sender port), pkt.len (bytes), pkt.hex, pkt.seq, pkt.time (server clock). This one has no counterpart on the MQTT plotter.
regEx The array produced by your Is RegEx row. Counts from zero.
dt The time the datagram was picked up, in milliseconds. Use it as the x-value of every point.
highcharts The chart. highcharts.series[0] is your first named line, [1] the second, and so on.
dt is the moment the browser read the datagram, not the moment it landed. With a 1000 ms poll, several datagrams from the same poll share almost the same x-value. Lower the poll interval for finer spacing, or plot Date.parse(pkt.time.replace(" ","T")) to use the server's arrival stamp instead.

Counting the index

/([^|,]+)/g means “every run of characters that is not a comma or a pipe” — in other words, every field. Suppose a datagram reads:

Zone,2340,e1:0b:6f:40:82:fb,17,1.42,-0.87,9.61|ok

Splitting it gives these positions:

0Zone
12340
2e1:0b:…
317
41.42
5-0.87
69.61
7ok

So the three numbers you want are regEx[4], regEx[5] and regEx[6]. Do this with a datagram copied from your own console — the layout above is only an illustration of the counting.

Four rules worth remembering

  • Put the Is RegEx row first. Rows run in order, so the array has to be filled before anything reads from it.
  • Use only one Is RegEx row. A second one replaces the first one's result.
  • End each addPoint with ,false. That skips a redraw per point; the chart redraws once after all rows have run, which keeps it smooth when a poll brings in a burst of datagrams.
  • Multiply by 1. Matches come out as text. (regEx[4])*1 turns "1.42" into the number 1.42. Without it the point plots as zero or not at all.
6

Worked example — three accelerometer axes

This is a complete, working configuration that plots AccelX, AccelY and AccelZ from a node sending the datagram shown above. Copy it field for field.

Field Value
Host / UDP Port iperfect.net / 49152 — fixed
Poll Interval 1000 ms
Source Filter left empty — plot every sender
X-Axis data types 3 → named AccelX, AccelY, AccelZ
Expressions to plot 4 — one to split, three to plot
Expression 1  Is RegEx ticked /([^|,]+)/g
Expression 2 highcharts.series[0].addPoint([dt,(regEx[4])*1],false)
Expression 3 highcharts.series[1].addPoint([dt,(regEx[5])*1],false)
Expression 4 highcharts.series[2].addPoint([dt,(regEx[6])*1],false)

Read it as: row 1 chops the datagram into fields; rows 2–4 take fields 5, 6 and 7 and push them onto the first, second and third line of the chart, stamped with the arrival time.

Load this example in the plotter
It loads the settings but does not start monitoring — press Start Monitoring. If nothing is sending, the chart stays empty; the console tells you whether anything is arriving.
7

Field reference

Top bar

Control What it does
Status pill Not Monitoring · Starting · Monitoring :49152 · Listener Offline · Error. The dot pulses while the poll loop is running.
Start Monitoring Begins polling for new datagrams, from the next one onwards.
Stop Stops polling. The chart keeps whatever it has drawn.
Help Opens this guide.
UDP Monitor Opens the raw monitor tab on iperfect.net in a new tab — see section 10.

Connection strip

Field What it does
Host Fixed at iperfect.net. The listener can only see traffic that lands on this server.
UDP Port Fixed at 49152, the open testing port the listener service binds.
Poll Interval (ms) How often the page asks for new datagrams: 250–10000 ms, default 1000. Changing it while monitoring takes effect at once, no restart needed. Lower means finer x-spacing and more requests.
Source Filter Optional. Only datagrams whose sender IP starts with this text are logged and plotted — 192.168. for a subnet, a full address for one device. Everything else is ignored, not queued.

Chart and console

Control What it does
1M / 5M / All Range selector. 1M keeps the last minute in view, which is usually what you want while watching live data.
Legend Click a name to hide or show that line.
☰ menu Export as PNG, SVG or PDF, and View data table / download CSV of everything plotted so far.
Datagram console Shows sender:port → text for each datagram, plus start/stop notes. Holds the last 500 lines.
pkt counter Datagrams accepted since the page loaded. System notes are not counted; filtered-out datagrams are not counted either.
Autoscroll / Clear Follow the newest line, or empty the console. Clearing does not touch the chart.

Configuration

Field What it does
X-Axis data types to plot How many lines the chart has. Apply redraws the name rows below.
Series name The label in the legend. The row's grey tag tells you which highcharts.series[i] it is.
Visible Series Tick boxes that hide or show a line without deleting its data.
Expressions to plot How many expression rows. Apply redraws them.
Is RegEx Ticked = match and fill regEx; unticked = run as JavaScript.
Save Configuration Stores everything in the page URL and reloads. Nothing you type takes effect until you press it.
Dump Parsed Data to Console A stub kept for parity with the MQTT plotter; it does nothing on its own. To inspect a parse, open the browser console (F12) and read regEx after a datagram has arrived.
8

Expression cookbook

Copy a row, change the index, done.

Splitting rows — tick Is RegEx

Expression Splits on
/([^|,]+)/g commas and pipes — a,b|c
/([^,]+)/g commas only — a,b,c
/([^\s]+)/g spaces — a b c
/(-?\d+\.?\d*)/g every number, ignoring all labels and separators
/"(?:temp|hum)":(-?\d+\.?\d*)/g two named values out of JSON

Plotting rows — leave Is RegEx unticked

Expression What it plots
highcharts.series[0].addPoint([dt,(regEx[4])*1],false) field 5 onto the first line
highcharts.series[0].addPoint([dt,parseFloat(data.split("temp=")[1])],false) a value straight out of key=value text, no split row needed
highcharts.series[0].addPoint([dt,pkt.len],false) datagram size in bytes — a cheap traffic graph
highcharts.series[0].addPoint([dt,JSON.parse(data).temp],false) a field of a JSON payload
if(pkt.from=="192.168.1.50"){highcharts.series[0].addPoint([dt,(regEx[4])*1],false)} one device onto one line, when several send the same format
highcharts.series[0].addPoint([Date.parse(pkt.time.replace(" ","T")),(regEx[4])*1],false) the same value, stamped with the server's arrival time instead of the poll time
A row that throws — a missing index, malformed JSON — stops the rows below it for that datagram. If one line plots and the next does not, look at the row above it first.
9

Troubleshooting

What you see Why Fix
Status goes to Error with a red bar The monitor endpoint answered with a problem, or could not be reached The bar carries the server's own message. Reload; if it persists the listener service is down
Listener Offline The service is running but is not bound to UDP 49152 Nothing to do from here — the port has to be rebound on the server
Monitoring but the console stays empty Nothing is arriving on port 49152 Send a test datagram (section 3). If that shows up, your device is the problem — check its destination host, port and that outbound UDP is not blocked
Test datagram arrives, the device's does not A firewall, NAT or mobile network is dropping outbound UDP Try the device on another network; many corporate and some mobile networks allow only DNS over UDP
Only some datagrams appear UDP loss, or a Source Filter that does not match Clear the filter first. Remember the filter is a prefix match on the sender IP
older datagram(s) skipped in the console More datagrams arrived between two polls than one poll returns (200) Lower the poll interval, or send less often
Console fills but the chart stays flat Your regEx[…] indices point at the wrong fields Recount from a real datagram; open the browser console and read regEx
Lines plot as 0 The field is text, not a number Add *1, and check you are not pointing at a label
Points arrive in steps, not smoothly Everything in one poll shares nearly the same dt Lower the poll interval, or stamp with pkt.time (see the cookbook)
Console shows dots where text should be The payload is binary Send text. pkt.hex is available if you must work with raw bytes
Chart shows one point at 05:30 The placeholder point every new line starts with Normal. It disappears from view once real data arrives; use 1M or 5M
Edits appear to do nothing Save Configuration was not pressed Press it — the page reloads with the new settings, then start again
Chart area shows a red “library unavailable” box Highcharts could not be downloaded Check internet access to code.highcharts.com or cdn.jsdelivr.net
It slows down after a long run Every point is kept in memory Reload the page to start a fresh capture
10

Plotter vs. UDP Monitor

Both read the same listener through the same endpoint. They differ in what they do with what arrives.

UDP Data Plotter UDP Monitor tab
Shows A chart, plus a text console A terminal: text, hex, or both
History Skipped — starts from the next datagram Replays the listener's buffer when you start
Good for Watching a value move over time Seeing exactly what a device sent, byte for byte
Extras Series, expressions, CSV/PNG export Hex dump, packet/byte/source counters, save log, clear buffer, send a test packet

A useful pairing: open the monitor first to see the raw shape of a datagram, copy one line out of it, then come here and write the expressions against it.

Open the UDP Monitor