如何用Pipedream应对恶劣天气警报(附代码)

248 阅读6分钟

几个月前,我写了一篇关于Pipedream中自定义事件的(可能是)无用的例子,"在月圆之夜启动Pipedream工作流(因为为什么不呢?)虽然不是很实用,但这篇文章展示了Pipedream的一个更酷的功能,即在任何特定的逻辑片段上创建工作流的能力。在那篇文章中,我定义了一个自定义的 "事件源"(Pipedream称之为开始工作流的方式),基于对当前月相的每日检查。今天我将分享这个功能的另一个例子,可能相当有用--恶劣天气警报。

我正在对微软的地图解决方案进行研究,当我在看文档的时候,我发现了他们的恶劣天气警报API。正如你可以想象的那样,给定一个位置,它将返回该地区任何可能的恶劣天气的信息。如果没有,它只是返回一个空数组。下面是一个例子(取自微软的文档),说明这可能是什么样子:

{
  "results": [
    {
      "countryCode": "CA",
      "alertId": 242621,
      "description": {
        "localized": "Heat Warning",
        "english": "Heat Warning"
      },
      "category": "NON-PRECIPITATION",
      "priority": 31,
      "source": "Environment Canada",
      "sourceId": 3,
      "alertAreas": [
        {
          "name": "Kirkland Lake - Englehart",
          "summary": "Heat Warning in effect until Thursday, 3:16 AM EDT.  Source: Environment Canada",
          "startTime": "2020-06-29T19:44:00+00:00",
          "endTime": "2020-07-02T07:16:03+00:00",
          "latestStatus": {
            "localized": "Continue",
            "english": "Continue"
          },
          "alertDetails": "\nA heat event continues through Thursday.\n\nDaytime high temperatures in the low thirties with overnight lows near 18 degrees Celsius are expected to continue until Thursday. Humidex values are expected to reach between 36 and 40 today. Cooler air will move into the region Thursday night. \n\nPlease refer to your public forecast for further details on expected temperatures.\n\nHot and humid air can also bring deteriorating air quality and can result in the air quality health index to approach the high risk category.\n\n###\n\nExtreme heat affects everyone.\n\nThe risks are greater for young children, pregnant women, older adults, people with chronic illnesses and people working or exercising outdoors.\n\nWatch for the effects of heat illness: swelling, rash, cramps, fainting, heat exhaustion, heat stroke and the worsening of some health conditions.\n\nPlease continue to monitor alerts and forecasts issued by Environment Canada. To report severe weather, send an email to ONstorm@canada.ca or tweet reports using #ONStorm.\n",
          "alertDetailsLanguageCode": "en-CA"
        }
      ]
    },
    {
      "countryCode": "CA",
      "alertId": 242633,
      "description": {
        "localized": "Heat Warning",
        "english": "Heat Warning"
      },
      "category": "NON-PRECIPITATION",
      "priority": 31,
      "source": "Environment Canada",
      "sourceId": 3,
      "alertAreas": [
        {
          "name": "Kirkland Lake - Englehart",
          "summary": "Heat Warning in effect until 9:25 PM EDT.  Source: Environment Canada",
          "startTime": "2020-07-01T09:25:59+00:00",
          "endTime": "2020-07-02T01:25:59+00:00",
          "latestStatus": {
            "localized": "New",
            "english": "New"
          },
          "alertDetails": "\nA heat event is expected through Thursday.  \n\nDaytime high temperatures in the low thirties on Wednesday and Thursday with overnight lows near 18 degrees Celsius are expected. This heat event may be extended into the weekend with daytime high temperatures near 30 degrees Celsius. \n\nPlease refer to your public forecast for further details on expected temperatures.  \n\nHot and humid air can also bring deteriorating air quality and can result in the Air Quality Health Index to approach the high risk category.\n\n###\n\nExtreme heat affects everyone.\n\nThe risks are greater for young children, pregnant women, older adults, people with chronic illnesses and people working or exercising outdoors.\n\nPlease continue to monitor alerts and forecasts issued by Environment Canada. To report severe weather, send an email to ONstorm@canada.ca or tweet reports using #ONStorm.\n",
          "alertDetailsLanguageCode": "en-CA"
        }
      ]
    }
  ]
}

在这个例子中,同一地区有两个不同的警报被返回。调用API是相对简单的。鉴于你有一个密钥,端点看起来像这样:

https://atlas.microsoft.com/weather/severe/alerts/json?api-version=1.1&query=48.057,-81.091&subscription-key=X

位置是经度、纬度的格式,并被传递到query 值。唯一支持的其他可选参数是截断结果或改变语言。那么,鉴于使用API是如此简单,我们如何将其作为Pipedream事件源使用呢?

我首先创建了一个文件,severeweather.js ,并使用事件源所需的格式。你可以在Pipedream网站上找到这个文件,但至少它看起来是这样的:

export default {
  name: "Source Demo",
  description: "This is a demo source",
  async run() {
    this.$emit({ message: "hello world!" });
  },
};

基本上--元数据和代码。$emit 部分是创建事件的内容,以及用于启动工作流的内容。然后可以使用Pipedream CLI将代码发布到你的账户。以下是我的事件源是如何建立的:

import fetch from "node-fetch";

export default {
  name: "Severe Weather",
  description: "I emit when a severe weather event is active in an area.",
  props: {
    timer: {
        type:"$.interface.timer",
        default: {
            intervalSeconds:60 * 60
        }
    },
    azureMapsKey: {
        type:"string",
        label:"Azure Maps Key",
        description:"Required - get it via the Azure Portal"
    },
    location: {
        type:"string",
        label:"Location",
        description:"Location in longitude,latitude format"
    },
  },
  dedupe: "unique", 
  async run() {
    let url = `https://atlas.microsoft.com/weather/severe/alerts/json?api-version=1.0&query=${this.location}&subscription-key=${this.azureMapsKey}`;
    let req = await fetch(url);
    let data = await req.json();
    data.results.forEach(r => {
        this.$emit(r, { id: r.alertId, summary: r.description.english });
    });
  },
};

让我们从头开始。namedescription 字段简单描述了源。props 部分定义了源的属性,特别是它基于一个时间表(在这个例子中,每小时一次),并且它需要两个唯一的值,一个Azure地图键,和一个位置。

值得注意的是,这些属性在事件源的每个实例中都是唯一的。所以这段代码会在不同的工作流程中使用不同的值。

让我们先跳过dedupe ,看看run 这个块。我使用node-fetch 打击Azure Severe Weather端点并获取结果。对于每个警报,我想把它作为一个不同的事件来发射。然而,警报有可能超过一个小时,我的事件可能为一个特定的警报触发一次以上。Pipedream通过使用dedupe 策略使这个问题很容易解决。当我指定unique ,我就负责为每个事件创建一个主键。你可以在this.$emit 的第二个参数中看到这一点。我还添加了可选的summary 值来描述该事件。但最酷的部分是--我不需要做任何其他事情来强制执行唯一性。Pipedream本身会抑制任何已经发出的警报。

当我通过命令行部署时,它提示我两个值,然后简单地创建配置的源并使其可用。因此,举例来说,我可以创建一个新的工作流,并将其作为一个来源来寻找。

在这一点上,你可以用这个源做任何可以想象到的事情。你可以发送一条短信。你可以向一个设备发送一个通知。你可以给可能在该地区的人的列表服务发送电子邮件作为警告。作为最简单的例子,我创建了一个工作流程,简单地给我发送了一封电子邮件。我添加了一个Python步骤,将警报(注意我说的是警报,而不是提醒,我的事件源将为每个独特的警报发射一次)并创建一个适合电子邮件的字符串:

from pipedream.script_helpers import (steps, export)

html = """
<h2>Severe Weather Alert</h2>
"""

html = html + f"""
<p>
A severe weather alert has been created for {steps['trigger']['event']['alertAreas'][0]['name']}.
</p>
<p>
Alert: <strong>{steps['trigger']['event']['description']['english']}</strong><br/>
Summary: {steps['trigger']['event']['alertAreas'][0]['summary']}
</p>

<p>
<pre>
{steps['trigger']['event']['alertAreas'][0]['alertDetails']}
</pre>
</p>
"""


# Return data for use in future steps
export("html", html)

然后将其传递给一个电子邮件步骤。Pipedream有一个 "向所有者发送电子邮件 "的步骤,使用起来非常方便,但请注意,如果我想要更精细的控制,我可以很容易地使用类似Sendgrid的东西来代替。下面是那个配置好的步骤的样子。

作为一个简短的说明,我对纯文本和HTML邮件使用相同的值,这不是很好,但因为我知道我是收到邮件的人,而且我的邮件客户端支持HTML,所以我不担心这个问题。

我做了一个快速测试,我使用Accuweather的恶劣天气页面来寻找活动事件。这是我收到的电子邮件的一个例子。