my eye

author Angelo Gladding

name Weather

published 2025-06-27T19:09:35.729178-07:00

type entry

updated 2025-06-28T16:38:11.349918-07:00

url /weather, /2025/06/28/j4

visibility public

Content

$ zip_code = web.form(zip=91030).zip
$ geocoding = web.get(f"https://api.zippopotam.us/us/{zip_code}").json["places"][0]

$ weather = web.get("https://api.open-meteo.com/v1/forecast", params={
$   "latitude": geocoding["latitude"],
$   "longitude": geocoding["longitude"],
$   "current_weather": True,
$   "temperature_unit": "fahrenheit",
$   "windspeed_unit": "mph",
$   "precipitation_unit": "inch",
$   "timeformat": "iso8601",
$   "timezone": "auto",
$   "hourly": ",".join([
$     "temperature_2m", "apparent_temperature", "dewpoint_2m", "relative_humidity_2m",
$     "precipitation", "rain", "snowfall", "showers", "precipitation_probability",
$     "weathercode", "pressure_msl", "visibility", "cloudcover", "cloudcover_low",
$     "cloudcover_mid", "cloudcover_high", "windspeed_10m", "windspeed_80m",
$     "windspeed_120m", "windspeed_180m", "windgusts_10m", "winddirection_10m",
$     "shortwave_radiation", "direct_radiation", "diffuse_radiation",
$     "sunshine_duration", "uv_index", "uv_index_clear_sky",
$     "soil_temperature_0cm", "soil_temperature_6cm",
$     "soil_moisture_0_1cm", "snow_depth", "freezinglevel_height"
$   ]),
$   "daily": ",".join([
$     "temperature_2m_max", "temperature_2m_min",
$     "apparent_temperature_max", "apparent_temperature_min",
$     "precipitation_sum", "rain_sum", "snowfall_sum",
$     "precipitation_hours", "precipitation_probability_max",
$     "windspeed_10m_max", "windgusts_10m_max",
$     "sunrise", "sunset", "weathercode",
$     "uv_index_max", "uv_index_clear_sky_max",
$     "shortwave_radiation_sum", "et0_fao_evapotranspiration"
$   ])
$ }).json

$ weather_codes = {
$   0: "Clear sky",
$   1: "Mainly clear",
$   2: "Partly cloudy",
$   3: "Overcast",
$   45: "Fog",
$   48: "Depositing rime fog",
$   51: "Drizzle: Light",
$   53: "Drizzle: Moderate",
$   55: "Drizzle: Dense intensity",
$   56: "Freezing Drizzle: Light",
$   57: "Freezing Drizzle: Dense intensity",
$   61: "Rain: Slight",
$   63: "Rain: Moderate",
$   65: "Rain: Heavy intensity",
$   66: "Freezing Rain: Light",
$   67: "Freezing Rain: Heavy intensity",
$   71: "Snow fall: Slight",
$   73: "Snow fall: Moderate",
$   75: "Snow fall: Heavy intensity",
$   77: "Snow grains",
$   80: "Rain showers: Slight",
$   81: "Rain showers: Moderate",
$   82: "Rain showers: Violent",
$   85: "Snow showers: Slight",
$   86: "Snow showers: Heavy",
$   95: "Thunderstorm: Slight or moderate",
$   96: "Thunderstorm with slight hail",
$   99: "Thunderstorm with heavy hail"
$ }

$ wind_directions = [
$   "N", "NNE", "NE", "ENE",
$   "E", "ESE", "SE", "SSE",
$   "S", "SSW", "SW", "WSW",
$   "W", "WNW", "NW", "NNW"
$ ]

<form>
<label>Zip: <input name=zip value="$zip_code"></label>
<button>Update</button>
</form>

$weather.pop("latitude"), $weather.pop("longitude"), $round(weather.pop("elevation")*3.28084) ft  
$weather.pop("timezone")

<h2>Current Conditions</h2>
$ current = weather.pop("current_weather")
$ current_units = weather.pop("current_weather_units")

$current.pop("temperature") $current_units["temperature"], $weather_codes[current.pop("weathercode")].lower(),
$current.pop("windspeed") $current_units["windspeed"]
$ wind_direction = current.pop("winddirection")
<abbr title="$wind_direction$current_units['winddirection']">$wind_directions[round(wind_direction / 22.5) % 16]</abbr>

<h2>Forecast</h2>
$ daily = weather.pop("daily")
$ daily_units = weather.pop("daily_units")
$ hourly = weather.pop("hourly")
$ hourly_units = weather.pop("hourly_units")

<style>
  .chart {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 200px;
    width: 100%;
    padding: 1em;
    background: #002b36;
    color: white;
    font: 12px sans-serif;
    box-sizing: border-box;
  }
  .bar {
    flex: 1;
    background: #268bd2;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    width:4px;
  }
  .bar span {
    display:none;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    padding: 0 2px;
  }
</style>

<table>
<thead>
<tr>
<th></th>
$for day in daily.pop("time"):
    <th>$day</th>
</tr>
<thead>
<tbody>
$ apparent_temperature_max_unit = daily_units.pop("apparent_temperature_max")
$ apparent_temperature_min_unit = daily_units.pop("apparent_temperature_min")
$ apparent_temperature_hourly = hourly.pop("apparent_temperature")
<tr>
<th>Feels like</th>
$ all_apparent_temperature_max = daily.pop("apparent_temperature_max")
$ all_apparent_temperature_min = daily.pop("apparent_temperature_min")
$ weekly_apparent_temperature_max = max(all_apparent_temperature_max)
$ weekly_apparent_temperature_min = min(all_apparent_temperature_min)
$for n, (apparent_temperature_min, apparent_temperature_max, weathercode) in enumerate(zip(all_apparent_temperature_min, all_apparent_temperature_max, daily.pop("weathercode"))):
    <td>$apparent_temperature_min $apparent_temperature_min_unit - $apparent_temperature_max $apparent_temperature_max_unit <br>$weather_codes[weathercode].lower()
    <div class=chart>
    $ current_apparent_temperature_hourly = apparent_temperature_hourly[24*n:24*(n+1)]
    $for current, normalized in zip(current_apparent_temperature_hourly, [round((t - weekly_apparent_temperature_min) / (weekly_apparent_temperature_max - weekly_apparent_temperature_min) * 100, 1) for t in current_apparent_temperature_hourly]):
        <div class=bar title="$current" style="height:$(normalized)%"><span>$current</span></div>
    </div>
    </td>
</tr>
$ temperature_2m_max_unit = daily_units.pop("temperature_2m_max")
$ temperature_2m_min_unit = daily_units.pop("temperature_2m_min")
<tr>
<th>Actual</th>
$for temperature_2m_min, temperature_2m_max in zip(daily.pop("temperature_2m_min"), daily.pop("temperature_2m_max")):
    <td>$temperature_2m_min - $temperature_2m_max</td>
</tr>
<tr>
<th>Sun</th>
$for sunrise, sunset, uv_index_max, uv_index_clear_sky_max in zip(daily.pop("sunrise"), daily.pop("sunset"), daily.pop("uv_index_max"), daily.pop("uv_index_clear_sky_max")):
    <td>$sunrise.partition("T")[2] $sunset.partition("T")[2] ($uv_index_max/$uv_index_clear_sky_max)</td>
</tr>
$ windspeed_10m_max_unit = daily_units.pop("windspeed_10m_max")
$ windgusts_10m_max_unit = daily_units.pop("windgusts_10m_max")
<tr>
<th>Wind</th>
$for windspeed_10m_max, windgusts_10m_max in zip(daily.pop("windspeed_10m_max"), daily.pop("windgusts_10m_max")):
    <td>$round(windspeed_10m_max)G$round(max(windgusts_10m_max, windspeed_10m_max))</td>
</tr>
</tbody>
</table>

<div style=color:#586e75>
<p>Other daily data available: <small><code>$:"</code>, <code>".join(daily.keys())</code></small>
<p>Other daily units available: <small><code>$:"</code>, <code>".join(daily_units.keys())</code></small>
<p>Other hourly data available: <small><code>$:"</code>, <code>".join(hourly.keys())</code></small>
<p>Other hourly units available: <small><code>$:"</code>, <code>".join(hourly_units.keys())</code></small>
</div>

<pre>$pformat(hourly)</pre>