A mobile weather deck is a response: HTTP status, a media type, and a short document that a constrained browser can show. The historical TNET URL /wap.php was that response for Cumulus observations—the script or template that served the deck—not the project plan that decided WAP was worth building, and not the second markup family at /wap2.php.
This article is about serving: content negotiation, what belongs in a complete observation on a small screen, and how to fail when the Cumulus file is missing or stale. Units and time are not optional chrome. They are how a four-line screen stays a measurement.
Historical context
Phones advertised WAP by requesting a URL and sending Accept headers that might list text/vnd.wap.wml, later application/vnd.wap.xhtml+xml, or ordinary text/html. A single /wap.php endpoint was a convenient bookmark on a station site. Behind it, PHP read a local processed include or realtime.txt and printed a deck.
The WAP project page explains why TNET had a feature-phone workstream (payload, WML cards, no banners). This URL is the server half: given a request, emit a document that is still a complete observation. TNET does not restore the old PHP, a WAP emulator, or a live deck fed by a historical station. The serving rules do not need that code.
Content negotiation is not a theme switch
HTTP content negotiation lets the server choose a representation using the request’s Accept (and related) headers (RFC 9110, §12). For a weather deck the honest representations were:
- WML (
text/vnd.wap.wml) for WAP 1.x browsers. - XHTML Mobile Profile (
application/vnd.wap.xhtml+xmlorapplication/xhtml+xml) for WAP 2-class browsers—the/wap2.phpfamily. - HTML for desktop or modern mobile browsers that followed a “mobile” bookmark by habit.
Negotiation fails when the server ignores Accept and always sends desktop HTML with a “download a WAP browser” note, or always sends WML to a Safari user-agent. It also fails when the numbers change between representations: WML showing °C and HTML showing °F from a different template. Representations of the same resource should bind the same Cumulus fields. Markup may change; the observation must not.
If the endpoint cannot honor the requested type, it should say so with a proper status and a small text body, not with a 200 OK PNG banner. A weather deck that answers an Accept: text/vnd.wap.wml request with image/png is a different product.
User-agent sniffing was common and remains brittle. Prefer Accept. If you must sniff, still serve the same scalars. The second-generation page exists in part because sniffing two markup families from one script became a tangle; splitting URLs made the contract visible.
What a complete observation looks like on a small screen
Completeness is not “as many Cumulus tags as possible.” Completeness is: a reader can interpret every number without leaving the deck and without guessing the station’s country.
Required on the now-card:
- Outside temperature with unit (
<#temp>and<#tempunitnodeg>, or realtime fields 3 and 15). - Packet time (
<#timehhmmss>/ field 2), in a form the phone can display. If the font lacks a second field,hh:mmis acceptable; omitting the clock is not. - At least one other independent scalar with unit, typically a named wind (
<#wspeed>or<#wgust>plus<#windunit>) or pressure plus<#pressunit>. A temperature-only deck is an avatar in text form; it can be a card, but it is not a complete station snapshot. - Station identity as a short name in the title or first line, because bookmarks travel.
Still required, even if they cost a line:
- Missing-value policy visible as
--or a fault word, never as0unless the logger actually reported zero. - Stale-file policy: if the Cumulus upload is older than two intervals, the deck must say the time is old. A small screen makes LIVE badges especially dishonest.
Optional cards, not mixed into “now” without labels:
- Today’s high/low with their event times (
<#tempTH>,<#TtempTH>, …). Those clocks are not the packet time. - Rain today with unit and the implication of station rollover.
- Extra sensors, each named.
Not a substitute for completeness:
- A forecast-number phrase.
- A webcam thumbnail the phone cannot load.
- A color bar without numbers.
- A Zambretti scenario presented as an official warning. Direct hazard decisions to NWS or the local authority.
The web-tag vocabulary is the binding list. Serving does not invent aliases. If the include does not define a field, the deck does not print it.
Layout that preserves the contract
WML cards should keep label and value on the same card. Splitting “Temp” on card 1 and “C” on card 2 is how units get lost when the user stops at card 1. Tables, if the browser supports them, are secondary to a definition-list rhythm: Temp 21.4 C, Wind avg 3.2 m/s W, Time 16:03:45.
Whitespace is payload. Do not pad with decorative separator cards. Do not include a second copy of the same temperature “for emphasis.”
Character encoding must be declared and must match what Cumulus wrote. MX extra files have a UTF-8 tick for a reason. A WML deck declared as ISO-8859-1 that contains UTF-8 bytes will mojibake the unit or the station name—the two strings completeness depends on.
Caching and methods
/wap.php is a GET resource. It should not require cookies or a login to read public observations. It should read a local file written by Cumulus, not proxy an upstream URL on each handset hit (gateway retries multiply).
Send Last-Modified from the source file and a Cache-Control max-age on the order of the realtime or extra-file interval (RFC 9111). A WAP gateway that ignores cache headers is not a reason to disable cache for everyone else; it is a reason not to paint LIVE.
HEAD requests, if honored, should not rebuild GD or parse more than the file mtime. This endpoint is markup, not the banner renderer.
Errors are part of serving
| Condition | Honest response | |---|---| | No Cumulus file | 503 or 404 with a text explanation, not a deck of zeros | | File older than policy | 200 with the old time visible, or 503 if you refuse stale | | Unknown tag / MX error string | omit field or show fault; do not parse as float | | Client accepts only WML, you only have HTML | 406 or a tiny WML “HTML only” card—choose one and document it |
A 200 OK deck of empty cards looks like a working station in a gateway cache.
Modern relevance
Most clients today send text/html and have viewports. The serving URL still has a job as the bookmark that meant “small observation.” You can emit modern HTML from the same completeness rules without pretending to be a 2004 Nokia. Keep negotiation if you still have WML clients; otherwise keep the URL and the contract: units, time, named fields, local file, visible staleness.
How TNET talks about observed versus derived information is how the service works. Which atmospheric families are worth putting on a short display is evidence families. File provenance is data sources and methodology. The Cumulus hub indexes the cluster.
Sources
- RFC 9110: HTTP Semantics (content negotiation)
- RFC 9111: HTTP Caching
- WAP Forum, WML 1.3 (WAP-191)
- Cumulus Wiki: realtime.txt (last checked 13 August 2026)
- Cumulus Wiki: Webtags (last checked 13 August 2026)
- NWS
- TNET, How the service works
- TNET, The evidence families behind a connection outlook