惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
Vercel News
Vercel News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
J
Java Code Geeks
M
MIT News - Artificial intelligence
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
MongoDB | Blog
MongoDB | Blog
G
Google Developers Blog
Engineering at Meta
Engineering at Meta
量子位
S
SegmentFault 最新的问题
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
A
About on SuperTechFans
P
Proofpoint News Feed
Last Week in AI
Last Week in AI
Recent Announcements
Recent Announcements
腾讯CDC
I
InfoQ
F
Fortinet All Blogs
Hugging Face - Blog
Hugging Face - Blog
Blog — PlanetScale
Blog — PlanetScale
H
Help Net Security
爱范儿
爱范儿

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
How to Use the OpenWeatherMap API in a Firefox Extension
Weather Cloc · 2026-05-04 · via DEV Community

Weather Clock Dash

How to Use the OpenWeatherMap API in a Firefox Extension

Weather data is one of the most commonly requested features in new tab extensions. The Weather & Clock Dashboard uses OpenWeatherMap's free tier. Here's a complete guide.

Getting an API Key

  1. Sign up at openweathermap.org — free tier allows 60 calls/minute, 1M calls/month
  2. Go to API keys in your account dashboard
  3. Copy the default API key (or create a new one)
  4. Keys become active within 10 minutes

Free tier limits: 60 requests/minute, 1,000,000 requests/month — more than enough for a browser extension.

The Current Weather API

const API_KEY = 'your_api_key_here';
const BASE_URL = 'https://api.openweathermap.org/data/2.5';

async function getCurrentWeather(city) {
  const url = `${BASE_URL}/weather?q=${encodeURIComponent(city)}&appid=${API_KEY}&units=imperial`;

  const response = await fetch(url);

  if (!response.ok) {
    if (response.status === 404) throw new Error(`City "${city}" not found`);
    if (response.status === 401) throw new Error('Invalid API key');
    throw new Error(`Weather API error: ${response.status}`);
  }

  return response.json();
}

// Response structure:
// {
//   name: "San Francisco",
//   sys: { country: "US" },
//   weather: [{ main: "Clear", description: "clear sky", icon: "01d" }],
//   main: { temp: 72, feels_like: 70, humidity: 65, temp_min: 68, temp_max: 75 },
//   wind: { speed: 12, deg: 270 },
//   visibility: 10000,
//   dt: 1699123456  // Unix timestamp
// }

Enter fullscreen mode Exit fullscreen mode

Handling Units

OWM supports three unit systems:

const UNITS = {
  imperial: { temp: '°F', speed: 'mph', param: 'imperial' },
  metric:   { temp: '°C', speed: 'm/s', param: 'metric' },
  standard: { temp: 'K',  speed: 'm/s', param: 'standard' }
};

async function getWeather(city, unitSystem = 'imperial') {
  const { param } = UNITS[unitSystem];
  const url = `${BASE_URL}/weather?q=${encodeURIComponent(city)}&appid=${API_KEY}&units=${param}`;
  const res = await fetch(url);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const data = await res.json();

  return {
    city: data.name,
    country: data.sys.country,
    temp: Math.round(data.main.temp),
    feelsLike: Math.round(data.main.feels_like),
    humidity: data.main.humidity,
    description: data.weather[0].description,
    icon: data.weather[0].icon,
    windSpeed: Math.round(data.wind.speed),
    unitLabel: UNITS[unitSystem].temp,
    speedLabel: UNITS[unitSystem].speed,
  };
}

Enter fullscreen mode Exit fullscreen mode

The 3-Day Forecast API

OWM's /forecast endpoint returns 5-day forecasts in 3-hour intervals:

async function getForecast(city, days = 3) {
  const url = `${BASE_URL}/forecast?q=${encodeURIComponent(city)}&appid=${API_KEY}&units=imperial`;
  const res = await fetch(url);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const data = await res.json();

  // Group by day (take the noon reading for each day)
  const dailyMap = new Map();

  data.list.forEach(item => {
    const date = new Date(item.dt * 1000);
    const dayKey = date.toLocaleDateString();
    const hour = date.getHours();

    // Prefer readings around noon (12-15h)
    if (!dailyMap.has(dayKey) || Math.abs(hour - 13) < Math.abs(dailyMap.get(dayKey).hour - 13)) {
      dailyMap.set(dayKey, {
        hour,
        date,
        temp: Math.round(item.main.temp),
        tempMin: Math.round(item.main.temp_min),
        tempMax: Math.round(item.main.temp_max),
        description: item.weather[0].description,
        icon: item.weather[0].icon,
        humidity: item.main.humidity,
      });
    }
  });

  // Skip today, return next N days
  const today = new Date().toLocaleDateString();
  return Array.from(dailyMap.values())
    .filter(d => d.date.toLocaleDateString() !== today)
    .slice(0, days);
}

Enter fullscreen mode Exit fullscreen mode

Weather Icons

OWM provides icon codes like 01d (clear day), 10n (rain night). Use their CDN:

function getIconUrl(iconCode) {
  return `https://openweathermap.org/img/wn/${iconCode}@2x.png`;
}

// Or map to your own emoji/SVG for better control:
const ICON_MAP = {
  '01d': '☀️',   // Clear sky day
  '01n': '🌙',   // Clear sky night
  '02d': '',   // Few clouds day
  '02n': '☁️',   // Few clouds night
  '03d': '☁️',   // Scattered clouds
  '03n': '☁️',
  '04d': '☁️',   // Broken clouds
  '04n': '☁️',
  '09d': '🌧️',  // Shower rain
  '09n': '🌧️',
  '10d': '🌦️',  // Rain day
  '10n': '🌧️',  // Rain night
  '11d': '⛈️',  // Thunderstorm
  '11n': '⛈️',
  '13d': '❄️',  // Snow
  '13n': '❄️',
  '50d': '🌫️',  // Mist
  '50n': '🌫️',
};

Enter fullscreen mode Exit fullscreen mode

Geolocation Fallback

For users who want automatic location detection:

async function getWeatherByCoords(lat, lon) {
  const url = `${BASE_URL}/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=imperial`;
  const res = await fetch(url);
  return res.json();
}

async function autoDetectWeather() {
  return new Promise((resolve, reject) => {
    if (!navigator.geolocation) {
      reject(new Error('Geolocation not supported'));
      return;
    }

    navigator.geolocation.getCurrentPosition(
      async (position) => {
        const data = await getWeatherByCoords(
          position.coords.latitude,
          position.coords.longitude
        );
        resolve(data);
      },
      (error) => reject(new Error(`Geolocation: ${error.message}`)),
      { timeout: 10000 }
    );
  });
}

Enter fullscreen mode Exit fullscreen mode

Storing the API Key Securely

For an extension, don't hardcode the API key in source. Use browser.storage.local and let users enter their own key:

async function getApiKey() {
  const { apiKey } = await browser.storage.local.get('apiKey');
  if (!apiKey) throw new Error('No API key configured');
  return apiKey;
}

async function setApiKey(key) {
  await browser.storage.local.set({ apiKey: key });
}

Enter fullscreen mode Exit fullscreen mode

Or for a simpler approach with a bundled key, at least use an environment variable at build time:

// In your build process:
const OWM_KEY = process.env.OWM_API_KEY;

Enter fullscreen mode Exit fullscreen mode

Rate Limiting

With 1M free requests/month, one user refreshing every 10 minutes for 30 days = 4,320 requests — well within limits. But if your extension has many users, consider:

const REFRESH_INTERVAL = 10 * 60 * 1000; // 10 minutes
let lastFetch = 0;

async function fetchWeatherIfStale(city) {
  const now = Date.now();
  if (now - lastFetch < REFRESH_INTERVAL) {
    return getCachedWeather();
  }
  lastFetch = now;
  return getWeather(city);
}

Enter fullscreen mode Exit fullscreen mode


The complete implementation is live in the Weather & Clock Dashboard Firefox extension.

firefox #javascript #webdev #api #browserextension