Aussie Broadband publishes CVC (Connectivity Virtual Circuit) capacity graphs for each of their POIs (Points of Interconnect) once per day. They're PNG images showing 24 hours of bandwidth data — download usage, upload usage, and provisioned capacity.
The problem is they're just images. No API, no raw data, no CSV export. If you want to track your POI's utilisation over time or alert on congestion, you're stuck eyeballing a graph.
This script fixes that. It takes the graph image, extracts the actual data points using computer vision, and outputs InfluxDB line protocol (or CSV) suitable for ingestion into a time-series database.
The ABB CVC graphs have a consistent structure:
- Blue line at the top: provisioned CVC capacity
- Black line: download bandwidth usage
- Green line near the bottom: upload bandwidth usage
- 5 horizontal gridlines with Y-axis labels (Mbps values)
- 13 X-axis labels:
00:00through24:00in 2-hour intervals
The script:
- Downloads the graph PNG from
cvcs.aussiebroadband.com.au(or reads a local file) - Finds the gridlines by scanning for uniform gray horizontal rows
- Detects the Y-axis scale by measuring the pixel width of each label's text. A 5-digit number like "10600" is physically wider than a 4-digit "7950", so comparing the top label width to the others tells us the scale without needing OCR
- Locates the X-axis labels by finding dark text clusters in the bottom margin
- Traces each colored line column-by-column, using color masks to isolate the black (download), green (upload), and blue (capacity) lines. Takes the median Y at each X to handle line thickness
- Maps pixels to real values using linear interpolation between the calibrated gridlines and label positions
- Downsamples to a configurable interval (default 60 seconds) by averaging points within each bucket
- Outputs InfluxDB line protocol or CSV
The result is ~860 data points per line per graph, downsampled to whatever resolution you want.
pip install opencv-python-headless numpyPython 3.10+.
# Extract a POI by name (downloads from ABB automatically)
python3 abb-cvc-extract.py --poi peakhurst --date 2026-03-24
# Extract all link variants for a POI (peakhurst, peakhurstlink2, peakhurstlink4, etc.)
python3 abb-cvc-extract.py --poi peakhurst --all-links --date 2026-03-24
# Extract from a local image file
python3 abb-cvc-extract.py /path/to/graph.png --date 2026-03-24
# CSV output instead of InfluxDB line protocol
python3 abb-cvc-extract.py --poi peakhurst --date 2026-03-24 --format csv
# Custom downsample interval (e.g. 5 minutes)
python3 abb-cvc-extract.py --poi peakhurst --date 2026-03-24 --interval 300Pipe the output straight into the InfluxDB v2 write API:
python3 abb-cvc-extract.py --poi peakhurst --date 2026-03-24 | \
curl -s "$INFLUXDB_URL/api/v2/write?org=$INFLUXDB_ORG&bucket=homeassistant&precision=s" \
-H "Authorization: Token $INFLUXDB_TOKEN" \
--data-binary @-abb_cvc,metric=download,poi=peakhurst value=3724.3 1774270860
abb_cvc,metric=upload,poi=peakhurst value=245.1 1774270860
abb_cvc,metric=capacity,poi=peakhurst value=10027.0 1774270860
timestamp,poi,metric,value_mbps
2026-03-24T00:01:00+11:00,peakhurst,download,3724.3
2026-03-24T00:01:00+11:00,peakhurst,upload,245.1
2026-03-24T00:01:00+11:00,peakhurst,capacity,10027.0
ABB uses different Y-axis scales depending on the POI size. Common maxes are 2650, 5300, 10600, and 15900 Mbps. The gridline step is always max / 4.
The script figures out the scale by comparing Y-axis label widths in pixels:
| Digit pattern (top → 4th label) | Scale max |
|---|---|
[4, 4, 4, 4] |
2650 or 5300 |
[5, 4, 4, 4] |
10600 |
[5, 5, 4, 4] |
15900 |
[5, 5, 5, 4] |
21200 |
If the candidates are ambiguous, the blue capacity line position is used as a tiebreaker.
ABB lists all POIs at aussiebroadband.com.au/network/cvc-graphs. The image URLs follow the pattern https://cvcs.aussiebroadband.com.au/{poi}.png. Larger POIs have multiple links: {poi}link2.png, {poi}link3.png, etc.
- Date is not extracted from the image (no OCR). You need to pass
--dateor it defaults to today. - Accuracy is limited by image resolution (960×300px). Each pixel on the X-axis represents roughly 1.5 minutes, and on the Y-axis roughly 70 Mbps (at 10600 scale). The 60-second downsample smooths this out.
- Graphs with fewer than 5 gridlines (low-utilisation links) may produce incorrect scale detection.
- Requires the standard ABB graph format. If they change the layout, the calibration logic will need updating.