国内分钟级降水预报做得比较好的是彩云天气,但是 App 在 iPad 上尚不支持横屏与键盘快捷键。所以有时候想看是否降水要打开 App,体验是不怎么好的。好在彩云天气有大量的数据 API 提供给了开发者,并且仅仅用其中最简单的一些,就能得到和彩云天气自家 App 一样的降水预报功能(受限于设备无法实现降水事件的主动推送)。

首先我们要到彩云天气的开放平台注册一个账户,并申请天气 API 的访问令牌(token)。在工作人员通知账户开通之前,我们可以使用测试 token 做些简单的测试以确保程序逻辑正常。

这里我们选择了注册开通后就能使用的 forecast 接口,格式如下:

https://api.caiyunapp.com/v2/{token}/{lng,lat}/forecast.json

其中尖括号内容即是我们要填充进去的,接下来就是数据的请求问题。Shortcuts 自身获取经纬度这个步骤非常慢,需要花大量时间获得语义化的地址(可以看这个 demo)。我是用 JSBox 来做数据的请求:

// 彩云天气 JSBox 系列
// ringsaturn, 2019-09-12

var token = "YOUR_TOKEN";

// 获取当地经纬度
function getLocation() {
  $location.fetch({
    handler: function (resp) {
      var lat = resp.lat;
      var lng = resp.lng;
      console.info(lat, lng);
      getWeather(lat, lng);
    },
  });
}

function getWeather(lat, lng) {
  $http.get({
    // "https://api.caiyunapp.com/v2/{token}/{lng},{lat}/daily.json"
    url: "https://api.caiyunapp.com/v2/" +
      token +
      "/" +
      lng +
      "," +
      lat +
      "/forecast.json",
    handler: function (resp) {
      var data = resp.data;
      if (data.status == "ok") {
        show(false, data);
      } else {
        $ui.toast(data.error);
      }
    },
  });
}

function show(text, data) {
  var minutely_desc = data.result.minutely.description;
  $push.schedule({
    title: "Raining Bot",
    body: minutely_desc,
    delay: 1,
    handler: function () {},
  });
}

getLocation();

效果如下:

另外,也可将这个脚本放到 Shortcuts 里:

// 彩云天气 JSBox 系列
// ringsaturn, 2019-09-12

var token = "YOUR_TOKEN";

// 获取当地经纬度
function getLocation() {
  $location.fetch({
    handler: function (resp) {
      var lat = resp.lat;
      var lng = resp.lng;
      console.info(lat, lng);
      getWeather(lat, lng);
    },
  });
}

function getWeather(lat, lng) {
  $http.get({
    // "https://api.caiyunapp.com/v2/{token}/{lng},{lat}/daily.json"
    url: "https://api.caiyunapp.com/v2/" +
      token +
      "/" +
      lng +
      "," +
      lat +
      "/forecast.json",
    handler: function (resp) {
      var data = resp.data;
      if (data.status == "ok") {
        show(false, data);
      } else {
        $ui.toast(data.error);
      }
    },
  });
}

function show(text, data) {
  var minutely_desc = data.result.minutely.description;
  $intents.finish(minutely_desc);
}

getLocation();