发布于 2026-01-06 2 阅读
0

开发演示:基于 Netlify Functions 和 Preact 的 Raspberry Pi 天气应用 ⛈ ✨ 成果展示 🚀 Netlify Functions ⚙️ 使用 Web Workers 设置定时器 🎨 CSS 🍒 Raspberry Pi 部分 🔥💥 精彩呈现 💥🔥 📚 资源

展示开发:RaspberryPi Weather ⛈ 由 Netlify 函数和 Preact 提供支持

✨ 结果

🚀 Netlify 函数

⚙️ 使用 Web Workers 设置定时器

🎨 CSS

🍒 树莓部分

🔥💥 砰 💥🔥

📚 资源

把一个前端开发人员、一台闲置数月的树莓派和一段隔离期结合在一起,会发生什么?

我住在一个一天之内就能体验四季的城市。所以,我决定用一台旧的树莓派开发一个每日天气预报应用 🔥

✨ 结果

我最喜欢网络技术的一点就是,你可以用它构建任何东西,从网站到移动应用。我希望通过这个小项目展示,只需进行一些修改和优化,你也能用它构建物联网,并获得令人惊艳的效果。

📸 炫酷

浅色模式🌝

替代文字

深色模式🌚

替代文字

日落时分🌘

替代文字

🐙 源代码

GitHub 标志 moigonzalez / weather-preactpi

一个简洁的每日天气预报用户界面⛈

🚀 Netlify 函数

这是整个项目中最有趣的部分。虽然我只是浅尝辄止地使用了 Netlify 函数,但我已经爱上它了😍。我可以创建一个 Lambda 函数,根据 IP 地址获取用户位置,然后获取该位置的天气。代码如下:

get-weather.js

const fetch = require('node-fetch');
const IPinfo = require("node-ipinfo");
const ipinfo = new IPinfo(process.env.IP_INFO_TOKEN);

exports.handler = async function(event) {
  // The IP comes for free
  const ip = event.headers['client-ip'];

  // IPinfo gives us the location data
  const { _city, _countryCode } = await ipinfo.lookupIp(ip);

  // And finally the weather ⛈
  const weather = await 
  fetch(`http://api.openweathermap.org/data/2.5/forecast/? q=${_city},${_countryCode}&APPID=${process.env.OPEN_WEATHER_TOKEN}&units=metric`);

  return {
    statusCode: 200,
    body: JSON.stringify(weather)
  }
}

然后,在客户端,我只需发出一个 HTTP 请求即可获取最终的天气响应:

App.js

const getWeather = () => {
  fetch('/.netlify/functions/get-weather')
    .then(x => x.json())
    .then(res => setWeather(res));
}

最棒的是,在开发环境、测试环境和生产环境中,端点调用都是相同的。🎊

⚙️ 使用 Web Workers 设置定时器

由于 Open Weather Map API 以 3 小时为周期提供天气数据,我希望用户界面能够在有新数据可用时立即更新。通过使用这 3 小时周期,我可以设置 JavaScript 超时来处理这些更新。

此外,我还添加了日落时分显示的深色模式。由于这两个计时器会在客户端并行运行两个超时,我希望每个计时器都在单独的 Web Worker 中运行,以减轻浏览器线程的负载。

为此,我设置了一个工作进程,用于计算距离下一次天气预报发布还剩多少毫秒,并向应用程序发送消息以更新用户界面。第二个工作进程则处理日出日落时间。

App.js

  useEffect(() => {
    if (weather.cod === '200') {
      const timeWorker = new Worker('../../static/update-time-worker.js');
      timeWorker.postMessage(`${weather.list[0].dt}`);

      timeWorker.onmessage = ({ data }) => {
        getWeather();
      }
    }
  }, [weather]);
update-time-worker.js

onmessage = ({ data }) => {
  const end = new Date(data * 1000);
  const start = new Date();

  const timeDiff = Math.floor((end.getTime() - start.getTime()));

  setTimeout(() => {
    postMessage('Update weather');
  }, timeDiff);
};

🎨 CSS

为了确保字体能够根据我的笔记本电脑屏幕的尺寸和分辨率以及(很小的)树莓派触摸屏的尺寸进行缩放,我使用了根据屏幕高度而变化的字体大小:

styles.css

:root {
  --font-size-l: 6vh;
  --font-size-m: 5vh;
  --font-size-sm: 3vh;
}

更改浏览器屏幕尺寸后,会出现以下结果:

替代文字

🍒 树莓部分

替代文字

首先,我安装了 Raspbian 系统,因为它预装了 Chromium 浏览器。你可以让这个浏览器全屏运行,并且不显示地址栏,看起来就像一个原生应用。今年三月,Raspberry Pi Imager 发布,它让安装变得非常简单:https://www.raspberrypi.org/downloads/

替代文字

现在,我想使用我的小型触摸屏,为此我需要一个特殊的脚本来更改启动画面:

git clone https://github.com/goodtft/LCD-show
cd LCD-show
sudo ./LCD35-show

替代文字

最后一步准备就绪!我们将以全屏模式显示 Chromium 浏览器,不显示导航栏:

/usr/bin/chromium-browser --incognito --start-maximized --kiosk https://weather-preactpi.netlify.com/

🔥💥 砰 💥🔥

替代文字

📚 资源

https://ipinfo.io/
https://openweathermap.org/
https://docs.netlify.com/functions/build-with-javascript/#format
http://frenetic.be/tricks/simple-timer.php
https://www.youtube.com/watch?v=Fj3wq98pd20
https://blog.gordonturner.com/2017/07/22/raspberry-pi-full-screen-browser-raspbian-july-2017/

文章来源:https://dev.to/moigonz/show-dev-raspberrypi-weather-fuelled-by-netlify-functions-and-preact-bne