Weather Control is the phone-friendly companion to the weather viewer. It lets one or more phones in a room change the location, choose units, decide which dashboard pages cycle (and how long each one stays on screen), and step through pages by hand.

A single scrolling page with five sections:
The viewer is authoritative; the control is a thin client.
Outbound (control → viewer):
rc.sendFunctionCall("weather", "weather.setLocation", { name, country, latitude, longitude, timezone });
rc.sendFunctionCall("weather", "weather.setOptions", { tempUnit, windUnit, precipUnit, pageMs, pages });
rc.sendFunctionCall("weather", "weather.next");
rc.sendFunctionCall("weather", "weather.prev");
rc.sendFunctionCall("weather", "weather.refresh");
rc.sendFunctionCall("weather", "weather.randomize");
rc.sendFunctionCall("weather", "weather.requestState", rc.client);
Inbound (viewer → control):
weatherControl.receiveState({
location: { name, country, latitude, longitude, timezone },
options: { tempUnit, windUnit, precipUnit, pageMs, pages },
pageIdx: 2,
pages: ["now", "hourly", "forecast", "details", "sun"],
randomLocations: [ ... ],
current: { temperature: 21, weatherCode: 2, isDay: 1, conditionLabel: "Partly cloudy" },
updated: 1730000000000
});
The viewer broadcasts a fresh snapshot to every weather-c client whenever the location, options, page or weather data change. New controllers explicitly request a snapshot on connect via weather.requestState(rc.client), so they catch up even if they joined mid-cycle.
Written in ES5 with XMLHttpRequest-style code, simple Flexbox layout, vendor-prefixed transitions, and no CSS Grid or custom properties — works comfortably on older mobile browsers.
/weather-c/?r=<room>