SillyTavern Extension: Weather Checker
I have created another extension for SillyTavern.
This extension uses the “OpenMeteo” open source weather API.
I have previously tried the “Accuweather” plugin for SillyTavern, but this didn’t work for me, it did not return any results. I did manage to get the WebSearch plugin working, and this can be used to generate weather reports/forecasts in SillyTavern, but the formatting is inconsistent, and I found this to be a poor solution.
My solution using OpenMeteo works well and produces easily understood and correctly formatted output, in the following form:
The following content is weather data starting from today:
Coordinates: <REMOVED>
Timezone: Europe/London GMT+1
12/10/25 Overcast
13/10/25 Light Drizzle
14/10/25 Overcast
15/10/25 Overcast
16/10/25 Overcast
17/10/25 Overcast
18/10/25 Light Drizzle
19/10/25 Light Drizzle
20/10/25 Overcast
21/10/25 Light Drizzle
22/10/25 Light Drizzle
23/10/25 Light Drizzle
24/10/25 Overcast
25/10/25 Moderate Drizzle
26/10/25 Overcast
27/10/25 Moderate Drizzle
[WEATHERDATA]
Currently, the extension only displays a 16 day weather forecast with a human-readable weather code, as shown above, however it is very easy to improve this to display any desired data. OpenMeteo has a very large amount of data available, including rainfall, temperature, wind speed, sunset/sunrise times, etc, etc.
I haven’t added this extension to github yet, so I will just post the code here. This code is based on my earlier Email Checker extension.
You will need to do an NPM install for openmeteo to make this code work.
You will also need to enter your latitude and longitude in the “const params” section of the server script below.
In addition,
On the server, add this at the top of index.js:
const { fetchWeatherApi } = require('openmeteo');
Then, to access the API:
async function fetchweather(ws)
{
const params = {
"latitude": <ENTER LATITUDE HERE>
"longitude": <ENTER LONGITUDE HERE>
"daily": "weather_code",
"timezone": "Europe/London",
"forecast_days": 16,
};
const url = "https://api.open-meteo.com/v1/forecast";
const responses = await fetchWeatherApi(url, params);
// Process first location. Add a for-loop for multiple locations or weather models
const response = responses[0];
// Attributes for timezone and location
const latitude = response.latitude();
const longitude = response.longitude();
const elevation = response.elevation();
const timezone = response.timezone();
const timezoneAbbreviation = response.timezoneAbbreviation();
const utcOffsetSeconds = response.utcOffsetSeconds();
var retdta = "";
console.log(
`\nCoordinates: ${latitude}°N ${longitude}°E`,
`\nElevation: ${elevation}m asl`,
`\nTimezone: ${timezone} ${timezoneAbbreviation}`,
`\nTimezone difference to GMT+0: ${utcOffsetSeconds}s`,
);
retdta +=
`\nCoordinates: ${latitude}°N ${longitude}°E` +
`\nTimezone: ${timezone} ${timezoneAbbreviation}` + "\n\n";
const daily = response.daily();
// Setup
const startTime = Number(daily.time());
const endTime = Number(daily.timeEnd());
const interval = daily.interval();
const weatherCodes = daily.variables(0).valuesArray();
const timeArray = [];
for (let i = 0, timestamp = startTime; timestamp < endTime; i++, timestamp += interval) {
const date = new Date((timestamp + utcOffsetSeconds) * 1000);
// Format as DD/MM/YY
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
const year = String(date.getFullYear()).slice(-2); // Get last two digits
const weatherCode = parseInt(weatherCodes[i], 10);
const weathercodetext = getweathercodetext(weatherCode);
// Combine with weather code
console.log(day + "/" + month + "/" + year + " " + weatherCode + " " + weathercodetext);
retdta += day + "/" + month + "/" + year + " " + weathercodetext + "\n";
timeArray.push(`${day}/${month}/${year} - ${weatherCode}`)
}
retdta+= "[WEATHERDATA]";
ws.send(retdta);
const weatherData = {
daily: {
time: timeArray,
weather_code: weatherCodes,
},
};
}
function getweathercodetext(weathercode)
{
var ret = "";
switch(weathercode) {
case 0:
ret = "Fair";//"Clear Sky";
break;
case 1:
ret = "Mainly Clear";
break;
case 2:
ret = "Partly Cloudy";
break;
case 3:
ret = "Overcast";
break;
case 45:
ret = "Fog";
break;
case 48:
ret = "Depositing Rime Fog";
break;
case 51:
ret = "Light Drizzle";
break;
case 53:
ret = "Moderate Drizzle";
break;
case 55:
ret = "Dense Drizzle";
break;
case 56:
ret = "Light Freezing Drizzle";
break;
case 57:
ret = "Dense Freezing Drizzle";
break;
case 61:
ret = "Light Rain";
break;
case 63:
ret = "Moderate Rain";
break;
case 65:
ret = "Heavy Rain";
break;
case 66:
ret = "Light Freezing Rain";
break;
case 67:
ret = "Heavy Freezing Rain";
break;
case 71:
ret = "Slight Snow Fall";
break;
case 73:
ret = "Moderate Snow Fall";
break;
case 75:
ret = "Heavy Snow Fall";
break;
case 77:
ret = "Snow Grains";
break;
case 80:
ret = "Slight Rain Showers";
break;
case 81:
ret = "Moderate Rain Showers";
break;
case 82:
ret = "Violent Rain Showers";
break;
case 85:
ret = "Slight Snow Showers";
break;
case 86:
ret = "Heavy Rain Showers";
break;
case 95:
ret = "Slight or Moderate Thunderstorm";
break;
case 96:
ret = "Thunderstorm with Slight Hail";
break;
case 99:
ret = "Thunderstorm with Heavy Hail";
break;
default:
ret = "INVALID WEATHER CODE: " + weathercode;
break;
}
console.log("getweathercodetext: " + weathercode + " " + ret);
return ret;
}
Then, on the client, use this function to display the weather data:
async function printweatherdata(txt){
const context = getContext();
if(txt == "STARTUPMESSAGE")
return;
console.log("printweatherdata:" + txt);
context.executeSlashCommands('/reasoning-set The following content is weather data starting from today:\n ' + txt + ' ').pipe
}



























