Reading Weather Display ClientRaw Files

Tutorial on Weather Display ClientRaw packets: record structure, delimiters, conceptual parse steps, and field-count plus timestamp freshness checks.

Back to Personal weather station notebooks

Weather Display (WD) publishes a compact, space-delimited packet so a website can refresh current conditions without transferring a full climate archive. This notebook is a reading tutorial: record structure, why the packet exists, conceptual parse steps, and validation. It is not a dump of field names. The ClientRaw family reference covers what each of the four files is for. The historical parser article is about a diagnostic viewer, not about how to think through a parse.

Do not paste recovered get-raw() implementations. Re-implement against current WD documentation if you still run the software.

Historical context

Personal weather sites in the 2000s needed a live dashboard on small FTP budgets. WD’s answer was a handful of text files—commonly clientraw.txt, clientrawextra.txt, clientrawdaily.txt, and clientrawhour.txt—uploaded on a short interval. Historical TNET notebooks taught PHP operators how to split those files. The method below keeps the scientific jobs (tokenize, type, validate, convert) and discards the old code. Credit Brian Hamilton / Weather Display; clientrawdescription.txt shipped with WD is the authority for field positions (weather-display.com).

Input

You need:

  • The file bytes (or a single line of ASCII text).
  • The WD version or build you believe produced it.
  • The expected field count for that version and file name.
  • A clock (UTC) to test freshness.
  • The unit system WD used in the packet (WD’s ClientRaw convention is typically °C, millimetres, knots, hPa, and meteorological degrees).

If you only have a URL, fetch it as data, not as HTML. A directory listing or an error page will tokenize into nonsense numbers.

Why a compact packet exists

A climate database answers “what happened this month.” A live page answers “what is the station doing now.” Those jobs have different payloads.

The compact packet is optimized for:

  • Frequent overwrite. One line, or a short line-oriented blob, replaced as a whole.
  • Trivial splitting. Space is the delimiter. No CSV quoting, no XML schema.
  • Stable positions. Field 4 is temperature in a given WD build whether or not you need fields 120–160.
  • Optional sensors. Extra temperature and humidity slots stay in the map even when unused, so indexes do not collapse.

The cost of that design is rigidity. Inserting a field in the middle of an old build shifts every later index. Field maps must be versioned—the reference notebook’s subject.

Record structure

Treat one ClientRaw file as:

  1. Header token. A leading label (often a numeric sentinel such as a station-style header) that marks the start of a WD packet, not a README.
  2. Ordered fields. Tokens separated by spaces. Consecutive spaces are empty fields only if your split rule says so; WD packets are usually single spaces between populated tokens.
  3. Encoded labels. If a station name or weather description contains spaces, WD replaces those spaces with underscores so the delimiter survives. Decode underscores to spaces only in label-typed fields, never in numeric fields.
  4. Time fragments. Hour, minute, second, day, month, and sometimes year as separate numeric fields. They follow the logger’s chosen clock, which may be local civil time, not UTC.
  5. Trailing version marker. Later builds append a token such as a !!…!! WD version tag. Use it as a map selector, not as weather.

Illustrative layout (synthetic values, not a live station):

12345 6.1 8.5 235 16.3 79 1010.0 0.0 17.6 376.8 ...

Conceptually: header, average wind (knots), gust (knots), direction (degrees), temperature (°C), humidity (%), pressure (hPa), rain totals (mm), then many more typed slots. Exact indexes belong in a versioned map, not in this tutorial.

The four family files share this encoding and differ in time grain. Parse them as siblings, not as one concatenated table.

Process: conceptual parse steps

Work in this order. Skipping validation and jumping to “field 4 is temp” is how dashboards publish yesterday.

  1. Acquire. Read the file as text in a single encoding (ASCII/UTF-8 without a BOM). Reject HTML doctype and FTP error banners.
  2. Trim. Strip leading and trailing whitespace. Do not trim underscores inside tokens.
  3. Tokenize. Split on spaces. Record n = token count.
  4. Select a map. From n, the trailing version token, and the file name, choose a field map. If no map matches, stop. Do not reuse a neighbor file’s map.
  5. Type. For each index, cast to number, integer, label, or enumerated icon. Fail closed on NaN for numeric slots.
  6. Decode labels. Replace underscores with spaces only where the map says “label.”
  7. Assemble time. Build a timestamp from the time fragments and the known time zone of the logger. Store both local and UTC.
  8. Convert units at the edge. Keep native ClientRaw units in the parsed object. Convert to °F or mph only in the display layer, using the metrology notebook.
  9. Emit a record. A structured object (JSON, a typed array, a database row)—not a string that still needs splitting.

A tiny original sketch of tokenization, not a WD clone:

tokens = split(trim(file_text), " ")
if count(tokens) != expected_count(version, filename):
    fail("field-count mismatch")

Stop there. Field meaning comes from the versioned map.

Validation

Two checks catch most silent failures.

Field count

Compare n to the count documented for that WD build and file. Historical WD 10.37-era maps used on the old TNET reference page listed on the order of 160 fields for clientraw.txt, several hundred for extra, and several hundred each for daily and hour files. Those numbers are historical; your build may differ. A short file is truncated. A long file is a newer build or a concatenated accident. Either way, do not realign by “looking at the numbers.”

Also check:

  • Header token present.
  • Trailing version token present if your map expects one.
  • Optional extra sensors may be zero, but they should still occupy a slot.

Timestamp freshness

Assemble the packet time and subtract from now, in the logger’s time zone.

Decide a budget that matches the upload interval. If WD is supposed to push every minute, a packet older than a few minutes is stale. If the clock is 24 hours off, you have a time-zone or PC-clock fault, not a calm weather day.

Reject or flag when:

  • Any time fragment is non-numeric or out of range (hour 24, month 13).
  • Packet time is in the future by more than clock skew (a few minutes).
  • Packet time is older than your freshness budget.
  • Date fragments disagree with the filesystem modification time by a large margin (you may be reading a backup).

Do not fill missing temperature with zero. Zero Celsius is a weather value. Use a missing sentinel and keep it visible.

Output

A successful parse returns:

  • File name and WD map version
  • n and expected n
  • Assembled timestamp (local + UTC) and age
  • A typed map of the fields you actually use (temperature, humidity, pressure, wind, rain)
  • Native units
  • A quality flag: ok, stale, count_mismatch, unmapped_version

That object can drive a dashboard. It is also what you keep when you debug a wrong gust.

Troubleshooting

All fields shifted by one. You split on whitespace and the header was missing, or you included a trailing empty token from a final space. Compare n before you look at temperature.

Station name is TNET_Weather_Station. That is the underscore rule working. Decode labels only.

Temperature looks like wind. You applied the clientraw.txt map to clientrawextra.txt. File identity is part of the map key.

Freshness always fails. Logger is in local time and your parser assumed UTC, or DST is wrong. Fix the zone; do not widen the budget to 12 hours.

Numbers are in °F already. Then you are not looking at a native ClientRaw packet, or a template already converted it. Native WD ClientRaw temperature is Celsius in the vendor description files. Confirm with a known-cold or known-hot day.

You need every field defined. Use the family reference, then the WD description file for your build.

Modern relevance

Parsing a compact observation packet is the same intellectual job as ingesting any frequently updated public weather file: know the delimiter, version the schema, and refuse stale clocks. TNET’s public notes on source freshness and quality control are in data sources and methodology. That research page does not document ClientRaw, and this notebook does not document TNET internals.

Continue with the field-family reference or the notebooks hub.

Sources

  • Weather Display, Brian Hamilton. Official software and manuals: weather-display.com. Field order: clientrawdescription.txt in the WD installation (authoritative for a given build).
  • Weather Display Live configuration notes describing clientraw.txt as live data and clientrawextra.txt as the companion extra/record file: vendor PDF documentation on weather-display.com.
  • This site’s historical diagnostic page: /wd-parser.php (article about a viewer; not a field dictionary).