use openweathermap weather codes
This commit is contained in:
parent
80b4e65ab2
commit
5352457032
8 changed files with 121 additions and 46 deletions
|
|
@ -35,7 +35,7 @@ test "render with imperial units" {
|
||||||
.temp_c = 10.0,
|
.temp_c = 10.0,
|
||||||
.temp_f = 50.0,
|
.temp_f = 50.0,
|
||||||
.condition = "Clear",
|
.condition = "Clear",
|
||||||
.weather_code = 113,
|
.weather_code = .clear,
|
||||||
.humidity = 60,
|
.humidity = 60,
|
||||||
.wind_kph = 16.0,
|
.wind_kph = 16.0,
|
||||||
.wind_dir = "N",
|
.wind_dir = "N",
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ const weather_icons = [_][]const u8{
|
||||||
"☁️", // 300-399
|
"☁️", // 300-399
|
||||||
};
|
};
|
||||||
|
|
||||||
fn getWeatherIcon(code: u16) []const u8 {
|
fn getWeatherIcon(code: types.WeatherCode) []const u8 {
|
||||||
const idx = @min(code / 100, weather_icons.len - 1);
|
const idx = @min(@intFromEnum(code) / 100, weather_icons.len - 1);
|
||||||
return weather_icons[idx];
|
return weather_icons[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@ test "render custom format with location and temp" {
|
||||||
.temp_c = 7.0,
|
.temp_c = 7.0,
|
||||||
.temp_f = 44.6,
|
.temp_f = 44.6,
|
||||||
.condition = "Overcast",
|
.condition = "Overcast",
|
||||||
.weather_code = 122,
|
.weather_code = .clouds_overcast,
|
||||||
.humidity = 76,
|
.humidity = 76,
|
||||||
.wind_kph = 11.0,
|
.wind_kph = 11.0,
|
||||||
.wind_dir = "NNE",
|
.wind_dir = "NNE",
|
||||||
|
|
@ -112,7 +112,7 @@ test "render custom format with newline" {
|
||||||
.temp_c = 10.0,
|
.temp_c = 10.0,
|
||||||
.temp_f = 50.0,
|
.temp_f = 50.0,
|
||||||
.condition = "Clear",
|
.condition = "Clear",
|
||||||
.weather_code = 113,
|
.weather_code = .clear,
|
||||||
.humidity = 65,
|
.humidity = 65,
|
||||||
.wind_kph = 8.0,
|
.wind_kph = 8.0,
|
||||||
.wind_dir = "E",
|
.wind_dir = "E",
|
||||||
|
|
@ -138,7 +138,7 @@ test "render custom format with humidity and pressure" {
|
||||||
.temp_c = 5.0,
|
.temp_c = 5.0,
|
||||||
.temp_f = 41.0,
|
.temp_f = 41.0,
|
||||||
.condition = "Cloudy",
|
.condition = "Cloudy",
|
||||||
.weather_code = 119,
|
.weather_code = .clouds_overcast,
|
||||||
.humidity = 85,
|
.humidity = 85,
|
||||||
.wind_kph = 12.0,
|
.wind_kph = 12.0,
|
||||||
.wind_dir = "W",
|
.wind_dir = "W",
|
||||||
|
|
@ -165,7 +165,7 @@ test "render custom format with imperial units" {
|
||||||
.temp_c = 10.0,
|
.temp_c = 10.0,
|
||||||
.temp_f = 50.0,
|
.temp_f = 50.0,
|
||||||
.condition = "Clear",
|
.condition = "Clear",
|
||||||
.weather_code = 113,
|
.weather_code = .clear,
|
||||||
.humidity = 60,
|
.humidity = 60,
|
||||||
.wind_kph = 16.0,
|
.wind_kph = 16.0,
|
||||||
.wind_dir = "N",
|
.wind_dir = "N",
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ test "render json format" {
|
||||||
.temp_c = 15.0,
|
.temp_c = 15.0,
|
||||||
.temp_f = 59.0,
|
.temp_f = 59.0,
|
||||||
.condition = "Partly cloudy",
|
.condition = "Partly cloudy",
|
||||||
.weather_code = 116,
|
.weather_code = .clouds_few,
|
||||||
.humidity = 72,
|
.humidity = 72,
|
||||||
.wind_kph = 13.0,
|
.wind_kph = 13.0,
|
||||||
.wind_dir = "SW",
|
.wind_dir = "SW",
|
||||||
|
|
|
||||||
|
|
@ -116,17 +116,17 @@ fn renderCustom(allocator: std.mem.Allocator, data: types.WeatherData, format: [
|
||||||
return output.toOwnedSlice(allocator);
|
return output.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getConditionEmoji(code: u16) []const u8 {
|
fn getConditionEmoji(code: types.WeatherCode) []const u8 {
|
||||||
return switch (code) {
|
return switch (@intFromEnum(code)) {
|
||||||
113 => "☀️",
|
800 => "☀️", // Clear
|
||||||
116 => "⛅️",
|
801, 802 => "⛅️", // Few/scattered clouds
|
||||||
119, 122 => "☁️",
|
803, 804 => "☁️", // Broken/overcast clouds
|
||||||
143, 248, 260 => "🌫",
|
701, 741 => "🌫", // Mist/fog
|
||||||
176, 263, 266, 293, 296 => "🌦",
|
300...321 => "🌦", // Drizzle
|
||||||
185, 281, 284, 311, 314, 317, 350, 362, 365, 374, 377 => "🌧",
|
500...531 => "🌧", // Rain
|
||||||
200, 386, 389, 392, 395 => "⛈",
|
200...232 => "⛈", // Thunderstorm
|
||||||
227, 230, 320, 323, 326, 329, 332, 335, 338, 368, 371 => "🌨",
|
611...616 => "❄️", // Sleet/freezing (check before snow)
|
||||||
179, 182 => "❄️",
|
600...610, 617...622 => "🌨", // Snow
|
||||||
else => "🌡️",
|
else => "🌡️",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +138,7 @@ test "format 1" {
|
||||||
.temp_c = 15.0,
|
.temp_c = 15.0,
|
||||||
.temp_f = 59.0,
|
.temp_f = 59.0,
|
||||||
.condition = "Clear",
|
.condition = "Clear",
|
||||||
.weather_code = 113,
|
.weather_code = .clear,
|
||||||
.humidity = 65,
|
.humidity = 65,
|
||||||
.wind_kph = 10.0,
|
.wind_kph = 10.0,
|
||||||
.wind_dir = "N",
|
.wind_dir = "N",
|
||||||
|
|
@ -162,7 +162,7 @@ test "custom format" {
|
||||||
.temp_c = 15.0,
|
.temp_c = 15.0,
|
||||||
.temp_f = 59.0,
|
.temp_f = 59.0,
|
||||||
.condition = "Clear",
|
.condition = "Clear",
|
||||||
.weather_code = 113,
|
.weather_code = .clear,
|
||||||
.humidity = 65,
|
.humidity = 65,
|
||||||
.wind_kph = 10.0,
|
.wind_kph = 10.0,
|
||||||
.wind_dir = "N",
|
.wind_dir = "N",
|
||||||
|
|
@ -186,7 +186,7 @@ test "format 2 with imperial units" {
|
||||||
.temp_c = 10.0,
|
.temp_c = 10.0,
|
||||||
.temp_f = 50.0,
|
.temp_f = 50.0,
|
||||||
.condition = "Cloudy",
|
.condition = "Cloudy",
|
||||||
.weather_code = 119,
|
.weather_code = .clouds_overcast,
|
||||||
.humidity = 70,
|
.humidity = 70,
|
||||||
.wind_kph = 20.0,
|
.wind_kph = 20.0,
|
||||||
.wind_dir = "SE",
|
.wind_dir = "SE",
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ test "render v2 format" {
|
||||||
.temp_c = 12.0,
|
.temp_c = 12.0,
|
||||||
.temp_f = 53.6,
|
.temp_f = 53.6,
|
||||||
.condition = "Overcast",
|
.condition = "Overcast",
|
||||||
.weather_code = 122,
|
.weather_code = .clouds_overcast,
|
||||||
.humidity = 80,
|
.humidity = 80,
|
||||||
.wind_kph = 15.0,
|
.wind_kph = 15.0,
|
||||||
.wind_dir = "NW",
|
.wind_dir = "NW",
|
||||||
|
|
@ -105,7 +105,7 @@ test "render v2 format with imperial units" {
|
||||||
.temp_c = 10.0,
|
.temp_c = 10.0,
|
||||||
.temp_f = 50.0,
|
.temp_f = 50.0,
|
||||||
.condition = "Clear",
|
.condition = "Clear",
|
||||||
.weather_code = 113,
|
.weather_code = .clear,
|
||||||
.humidity = 65,
|
.humidity = 65,
|
||||||
.wind_kph = 16.0,
|
.wind_kph = 16.0,
|
||||||
.wind_dir = "N",
|
.wind_dir = "N",
|
||||||
|
|
|
||||||
|
|
@ -126,29 +126,29 @@ fn parseMetNoResponse(allocator: std.mem.Allocator, coords: Coordinates, json: s
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbolCodeToWeatherCode(symbol: []const u8) u16 {
|
fn symbolCodeToWeatherCode(symbol: []const u8) types.WeatherCode {
|
||||||
if (std.mem.indexOf(u8, symbol, "clearsky")) |_| return 113;
|
if (std.mem.indexOf(u8, symbol, "clearsky")) |_| return .clear;
|
||||||
if (std.mem.indexOf(u8, symbol, "fair")) |_| return 116;
|
if (std.mem.indexOf(u8, symbol, "partlycloudy")) |_| return .clouds_scattered;
|
||||||
if (std.mem.indexOf(u8, symbol, "partlycloudy")) |_| return 116;
|
if (std.mem.indexOf(u8, symbol, "fair")) |_| return .clouds_few;
|
||||||
if (std.mem.indexOf(u8, symbol, "cloudy")) |_| return 119;
|
if (std.mem.indexOf(u8, symbol, "cloudy")) |_| return .clouds_overcast;
|
||||||
if (std.mem.indexOf(u8, symbol, "fog")) |_| return 143;
|
if (std.mem.indexOf(u8, symbol, "fog")) |_| return .fog;
|
||||||
if (std.mem.indexOf(u8, symbol, "rain")) |_| return 296;
|
if (std.mem.indexOf(u8, symbol, "thunder")) |_| return .thunderstorm;
|
||||||
if (std.mem.indexOf(u8, symbol, "sleet")) |_| return 362;
|
if (std.mem.indexOf(u8, symbol, "rain")) |_| return .rain_moderate;
|
||||||
if (std.mem.indexOf(u8, symbol, "snow")) |_| return 338;
|
if (std.mem.indexOf(u8, symbol, "sleet")) |_| return .sleet;
|
||||||
if (std.mem.indexOf(u8, symbol, "thunder")) |_| return 200;
|
if (std.mem.indexOf(u8, symbol, "snow")) |_| return .snow;
|
||||||
return 113;
|
return .clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbolCodeToCondition(symbol: []const u8) []const u8 {
|
fn symbolCodeToCondition(symbol: []const u8) []const u8 {
|
||||||
if (std.mem.indexOf(u8, symbol, "clearsky")) |_| return "Clear";
|
if (std.mem.indexOf(u8, symbol, "clearsky")) |_| return "Clear";
|
||||||
if (std.mem.indexOf(u8, symbol, "fair")) |_| return "Fair";
|
|
||||||
if (std.mem.indexOf(u8, symbol, "partlycloudy")) |_| return "Partly cloudy";
|
if (std.mem.indexOf(u8, symbol, "partlycloudy")) |_| return "Partly cloudy";
|
||||||
|
if (std.mem.indexOf(u8, symbol, "fair")) |_| return "Fair";
|
||||||
if (std.mem.indexOf(u8, symbol, "cloudy")) |_| return "Cloudy";
|
if (std.mem.indexOf(u8, symbol, "cloudy")) |_| return "Cloudy";
|
||||||
if (std.mem.indexOf(u8, symbol, "fog")) |_| return "Fog";
|
if (std.mem.indexOf(u8, symbol, "fog")) |_| return "Fog";
|
||||||
|
if (std.mem.indexOf(u8, symbol, "thunder")) |_| return "Thunderstorm";
|
||||||
if (std.mem.indexOf(u8, symbol, "rain")) |_| return "Rain";
|
if (std.mem.indexOf(u8, symbol, "rain")) |_| return "Rain";
|
||||||
if (std.mem.indexOf(u8, symbol, "sleet")) |_| return "Sleet";
|
if (std.mem.indexOf(u8, symbol, "sleet")) |_| return "Sleet";
|
||||||
if (std.mem.indexOf(u8, symbol, "snow")) |_| return "Snow";
|
if (std.mem.indexOf(u8, symbol, "snow")) |_| return "Snow";
|
||||||
if (std.mem.indexOf(u8, symbol, "thunder")) |_| return "Thunderstorm";
|
|
||||||
return "Clear";
|
return "Clear";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,9 +171,9 @@ test "degreeToDirection" {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "symbolCodeToWeatherCode" {
|
test "symbolCodeToWeatherCode" {
|
||||||
try std.testing.expectEqual(@as(u16, 113), symbolCodeToWeatherCode("clearsky_day"));
|
try std.testing.expectEqual(types.WeatherCode.clear, symbolCodeToWeatherCode("clearsky_day"));
|
||||||
try std.testing.expectEqual(@as(u16, 116), symbolCodeToWeatherCode("fair_night"));
|
try std.testing.expectEqual(types.WeatherCode.clouds_few, symbolCodeToWeatherCode("fair_night"));
|
||||||
try std.testing.expectEqual(@as(u16, 119), symbolCodeToWeatherCode("cloudy"));
|
try std.testing.expectEqual(types.WeatherCode.clouds_overcast, symbolCodeToWeatherCode("cloudy"));
|
||||||
try std.testing.expectEqual(@as(u16, 296), symbolCodeToWeatherCode("lightrain"));
|
try std.testing.expectEqual(types.WeatherCode.rain_moderate, symbolCodeToWeatherCode("lightrain"));
|
||||||
try std.testing.expectEqual(@as(u16, 338), symbolCodeToWeatherCode("snow"));
|
try std.testing.expectEqual(types.WeatherCode.snow, symbolCodeToWeatherCode("snow"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ test "mock weather provider" {
|
||||||
.temp_c = 15.0,
|
.temp_c = 15.0,
|
||||||
.temp_f = 59.0,
|
.temp_f = 59.0,
|
||||||
.condition = "Clear",
|
.condition = "Clear",
|
||||||
.weather_code = 113,
|
.weather_code = .clear,
|
||||||
.humidity = 65,
|
.humidity = 65,
|
||||||
.wind_kph = 10.0,
|
.wind_kph = 10.0,
|
||||||
.wind_dir = "N",
|
.wind_dir = "N",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,80 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
/// Weather condition codes based on OpenWeatherMap standard
|
||||||
|
/// https://openweathermap.org/weather-conditions
|
||||||
|
pub const WeatherCode = enum(u16) {
|
||||||
|
// Thunderstorm group (2xx)
|
||||||
|
thunderstorm_light_rain = 200,
|
||||||
|
thunderstorm_rain = 201,
|
||||||
|
thunderstorm_heavy_rain = 202,
|
||||||
|
thunderstorm_light = 210,
|
||||||
|
thunderstorm = 211,
|
||||||
|
thunderstorm_heavy = 212,
|
||||||
|
thunderstorm_ragged = 221,
|
||||||
|
thunderstorm_light_drizzle = 230,
|
||||||
|
thunderstorm_drizzle = 231,
|
||||||
|
thunderstorm_heavy_drizzle = 232,
|
||||||
|
|
||||||
|
// Drizzle group (3xx)
|
||||||
|
drizzle_light = 300,
|
||||||
|
drizzle = 301,
|
||||||
|
drizzle_heavy = 302,
|
||||||
|
drizzle_rain_light = 310,
|
||||||
|
drizzle_rain = 311,
|
||||||
|
drizzle_rain_heavy = 312,
|
||||||
|
drizzle_shower_light = 313,
|
||||||
|
drizzle_shower = 314,
|
||||||
|
drizzle_shower_heavy = 321,
|
||||||
|
|
||||||
|
// Rain group (5xx)
|
||||||
|
rain_light = 500,
|
||||||
|
rain_moderate = 501,
|
||||||
|
rain_heavy = 502,
|
||||||
|
rain_very_heavy = 503,
|
||||||
|
rain_extreme = 504,
|
||||||
|
rain_freezing = 511,
|
||||||
|
rain_shower_light = 520,
|
||||||
|
rain_shower = 521,
|
||||||
|
rain_shower_heavy = 522,
|
||||||
|
rain_shower_ragged = 531,
|
||||||
|
|
||||||
|
// Snow group (6xx)
|
||||||
|
snow_light = 600,
|
||||||
|
snow = 601,
|
||||||
|
snow_heavy = 602,
|
||||||
|
sleet = 611,
|
||||||
|
sleet_shower_light = 612,
|
||||||
|
sleet_shower = 613,
|
||||||
|
rain_snow_light = 615,
|
||||||
|
rain_snow = 616,
|
||||||
|
snow_shower_light = 620,
|
||||||
|
snow_shower = 621,
|
||||||
|
snow_shower_heavy = 622,
|
||||||
|
|
||||||
|
// Atmosphere group (7xx)
|
||||||
|
mist = 701,
|
||||||
|
smoke = 711,
|
||||||
|
haze = 721,
|
||||||
|
dust_whirls = 731,
|
||||||
|
fog = 741,
|
||||||
|
sand = 751,
|
||||||
|
dust = 761,
|
||||||
|
ash = 762,
|
||||||
|
squall = 771,
|
||||||
|
tornado = 781,
|
||||||
|
|
||||||
|
// Clear group (800)
|
||||||
|
clear = 800,
|
||||||
|
|
||||||
|
// Clouds group (80x)
|
||||||
|
clouds_few = 801, // 11-25%
|
||||||
|
clouds_scattered = 802, // 25-50%
|
||||||
|
clouds_broken = 803, // 51-84%
|
||||||
|
clouds_overcast = 804, // 85-100%
|
||||||
|
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
pub const WeatherError = error{
|
pub const WeatherError = error{
|
||||||
LocationNotFound,
|
LocationNotFound,
|
||||||
ApiError,
|
ApiError,
|
||||||
|
|
@ -31,7 +106,7 @@ pub const CurrentCondition = struct {
|
||||||
temp_c: f32,
|
temp_c: f32,
|
||||||
temp_f: f32,
|
temp_f: f32,
|
||||||
condition: []const u8,
|
condition: []const u8,
|
||||||
weather_code: u16,
|
weather_code: WeatherCode,
|
||||||
humidity: u8,
|
humidity: u8,
|
||||||
wind_kph: f32,
|
wind_kph: f32,
|
||||||
wind_dir: []const u8,
|
wind_dir: []const u8,
|
||||||
|
|
@ -44,7 +119,7 @@ pub const ForecastDay = struct {
|
||||||
max_temp_c: f32,
|
max_temp_c: f32,
|
||||||
min_temp_c: f32,
|
min_temp_c: f32,
|
||||||
condition: []const u8,
|
condition: []const u8,
|
||||||
weather_code: u16,
|
weather_code: WeatherCode,
|
||||||
hourly: []HourlyForecast,
|
hourly: []HourlyForecast,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -52,7 +127,7 @@ pub const HourlyForecast = struct {
|
||||||
time: []const u8,
|
time: []const u8,
|
||||||
temp_c: f32,
|
temp_c: f32,
|
||||||
condition: []const u8,
|
condition: []const u8,
|
||||||
weather_code: u16,
|
weather_code: WeatherCode,
|
||||||
wind_kph: f32,
|
wind_kph: f32,
|
||||||
precip_mm: f32,
|
precip_mm: f32,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue