Road weather message
A vehicle, a plow or a roadside device sends its snapshot of the road, and asks for the segment it is on. Storm Station 247 answers as the weather data management system of SAE J2945/3, in its own profile.
The profile
SAE J2945/3 (January 2022), section 4.2.2, sets a session between a vehicle or device and the weather data management system: the vehicle uploads a Road Weather Message (5.1.1.1) in JSON Encoding Rules over HTTP (4.2.2.1), and asks for the road (4.2.2.2). The message types are SAE J2735's. This page is Storm Station 247's profile of that dialog: what it reads, what it checks, and what it answers. It is a profile, not a claim of conformance. The normative module, and the right to use it, come from SAE International: SAE J2945/3 and SAE J2735.
1. Register a sender
A fleet, a plow, a device or a citizen registers once and is given a key, shown once and kept only as a hash. Five registrations a day from one address.
curl -X POST https://stormstation247.com/wdms/senders/register \
-H "content-type: application/json" \
-d '{"name": "Dallas yard", "kind": "fleet"}'2. Upload a snapshot
A PUT, as section 4.2.2.1 has it, or a POST, with the key. One to 32 snapshots a message. ?vehicle= names one vehicle of a fleet, so each is ranked on its own.
curl -X PUT "https://stormstation247.com/wdms/rwm/upload?vehicle=T-114" \
-H "Authorization: Bearer $SENDER_ID.$SENDER_KEY" \
-H "content-type: application/json" \
-d '{"upload":{"vehicleReport":[{"snapShot":{"thePosition":{"utcTime":{"year":2026,"month":10,"day":4,"hour":18,"minute":5,"second":30000},"long":-954006500,"lat":298565800},"safetyExt":{"events":"3000"},"dataSet":{"wipers":{"statusFront":"low","rateFront":40}}}}]}}'The answer names, for each snapshot, the segment it was snapped to, whether it is on a bridge, each check and whether it passed, and whether it votes on the road; and the hash of the checks it was judged by.
| Field read | What it is used for |
|---|---|
thePosition.utcTime | The time, needed: year, month, day, hour and minute; second in milliseconds; offset in minutes. A snapshot with no time is refused. |
thePosition.lat, long | The place, needed, in tenths of a microdegree. A snapshot with no place is refused. |
thePosition.heading | The way the vehicle is going. |
dataSet.wipers.statusFront | Precipitation: intermittent, low or high is wipers on; off is off. |
dataSet.brakeStatus.traction, abs | Friction lost: engaged. |
safetyExt.events | The same flags as bits: 2 anti lock brakes, 3 traction control lost. |
dataSet.airTemp, weatherData.airTemp | The air at the vehicle. Kept and checked; it never sets the pavement temperature. |
weatherData.pavement.surfaceTemp | The pavement, read by the vehicle's own road surface sensor, in tenths of a degree C. Two vehicles within 3 F of each other on a segment in the hour give a measured pavement where no road station reads it. |
A field the reader does not know is kept in the raw body and named in the answer, so a later revision of the message does not break an upload.
3. The checks
- Kept whole
- The body is kept as it came, under a name of its own, and never written over.
- Snapped
- To the quarter mile segment of I-45 or I-10 it lies on, within a quarter mile of the road's line; to the bridge where it is on the structure. A place off the corridors is kept and does not vote.
- Time
- No older than a day, no more than ten minutes ahead.
- Range
- Air from -40 F to 130 F, a place in the United States.
- Stuck
- An air temperature unchanged to the tenth over 12 snapshots and 2 hours.
- Jump
- Faster than 110 mph between two snapshots of one vehicle, or 15 F of air inside ten minutes.
- Agreement
- The wipers against a ranked road station reading the same segment, and against other vehicles on it in the half hour. Wipers on where a ranked road station reads the road dry disagree.
- A failed check
- Is kept, and does not move the road.
4. What a vehicle may move
- Wet
- Two vehicles, each with wipers on and no traction lost, on the same segment in the hour, where the pavement was measured above 35 F within the hour, by a road station within 10 miles or by two vehicles' own road surface sensors, move a segment that is not known to wet. One vehicle does not. An airfield's air temperature never stands in for the pavement, however warm.
- Ice
- Never called by a vehicle. One traction or brake flag with the pavement at or below 32 F is a candidate, shown, and not called.
- Pavement
- A road station within 10 miles that reported within the hour gives it first, as the rules say. Where none does, two vehicles' own road surface sensors, on the segment in the hour and within 3 F of each other, give it. A vehicle's air temperature never does.
- Silence
- No vehicle on a segment changes nothing: a gap stays not known.
5. Ask for the road
curl "https://stormstation247.com/wdms/rwm/download?lat=29.85658&lon=-95.40065&heading=330&class=truck"The answer is a Road Weather Message download: one traveler information frame for the segment, the surface and the action as ITIS codes, and where the surface is ice, the standard's own surface list (frictionInfo, DescriptionOfRoadSurface). Routing advice names the next stop when the vehicle is told to exit or route around. Beside them, as an extension a decoder of the message leaves aside, storm247: the surface, the confidence, the action for the vehicle class, why, the rule that fired, why a road is not known, the next stop whose path is no worse than the segment the vehicle is on, the alerts in full, and the rule hash.
| Asked | What it is |
|---|---|
lat, lon | The vehicle's place, in degrees. Needed. |
heading | Degrees from north. With the miles within 90 degrees of the road's heading, against them otherwise. |
class | truck (the default) or robotaxi. |
load | empty (the default) or loaded, for a truck. |
| Surface or action | ITIS code |
|---|---|
| Dry | 6011 |
| Wet | 5895 |
| Slush | 5914 |
| Snow | 5916 |
| Ice | 5906 |
| Not known | 4358 |
| Lengthen the gap | 7172 |
| Slow | 7443 |
| Route around | 8449 |
| Exit | 7188 |
Free: the surface, the confidence, the action, the reason, the rule, the next stop and every alert, in full. With an API key: the stations and vehicles that decided it, with their distance, age and 247 rank, and the figures.
6. Hooks for a command centre
A command centre names a stretch of a corridor, a vehicle and an HTTPS address. The address is sent a challenge and must answer it before the hook stands. Every ten minutes the stretch is read from the exception feed, and when its action or its alerts change, the address is sent a POST: first the stretch as it stands, then each change, naming the action before it. Three hooks a day and ten at once from one address; 96 sends a day to a hook; ten failed sends in a row stop it.
curl -X POST https://stormstation247.com/wdms/hooks \
-H "content-type: application/json" \
-d '{"url": "https://ops.example.com/storm247", "corridor": "i45", "vehicle": "truck-loaded", "fromMi": 0, "toMi": 286}'The challenge is a POST of {"type": "verify", "challenge": "..."}; the address answers 2xx with the challenge in its body. The answer to the curl is the hook's id and its secret, shown once. Each send carries two headers: x-storm247-hook, the id, and x-storm247-signature, t= the time in Unix seconds and v1= the HMAC-SHA256, in hex, of the time, a full stop and the body, keyed with the secret. A receiver checks it, and refuses a time more than five minutes off:
import { createHmac, timingSafeEqual } from "node:crypto";
function good(secret, header, body){
const [, t, v1] = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header) || [];
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const want = createHmac("sha256", secret).update(t + "." + body).digest("hex");
return timingSafeEqual(Buffer.from(want), Buffer.from(v1));
}Free: the action for the stretch, the reason, the alerts, and each exception on it with its own. Made with an API plan key (-H "Authorization: Bearer $STORM_KEY"), each send also names the instruments that decided each exception, their ages and 247 ranks, and the rule hash, for as long as the key runs and at most 30 days; then the hook is made again.
curl https://stormstation247.com/wdms/hooks/$HOOK_ID -H "Authorization: Bearer $HOOK_ID.$HOOK_SECRET"
curl -X POST https://stormstation247.com/wdms/hooks/$HOOK_ID/test -H "Authorization: Bearer $HOOK_ID.$HOOK_SECRET"
curl -X DELETE https://stormstation247.com/wdms/hooks/$HOOK_ID -H "Authorization: Bearer $HOOK_ID.$HOOK_SECRET"The first reads the hook, the second sends a signed test, the third ends it.
7. Where this profile differs
- A sender is known by the key it registered, over HTTPS; the message is not signed with the certificates of section C.2.
- The standard's surface list needs the pavement's material for dry and wet, which no instrument here measures; so dry and wet travel as ITIS codes, and the list is sent only for ice.
- No share of respondents is advertised: every upload is taken.
- The download speaks for the segment the vehicle is on, and the action beside it is Storm Station 247's, from the rules.
8. Vehicles, ranked as stations are
Each sending vehicle is ranked on its last seven days: its reports a day, the share of its snapshots that pass the checks, and its agreement with its neighbours. A vehicle that keeps failing for a week stops voting.
No vehicle has sent a snapshot yet: every exception reads mobile: none.