0%

Node-Red入门-从一个天气预报通知说起

前言

Node-Red 环境配置好之后,我去看了一些入门类的文章,基本上都是从各种节点组件开始讲起,要不就是一个最简单的 打印输出 的示例就完了。

但这么简单的入门教程其实跟不写一样,对于想要入门的新手来说,一点帮助都没有。

于是,我打算从一个需求点出发,通过实现该需求一步步的了解 Node-Red 的使用方法。

偶然间刷头条App时,看到顶部菜单项 北京 页面上面显示的天气,突然来了兴趣,干脆我就从实现一个天气预报的推送通知开始入门 Node-Red 吧。


获取天气接口

那么问题来了,天气接口从哪来呢?

看了看头条App上的天气页面,感觉基本的天气信息都有了。不过对头条App抓包不太好操作。于是打算看看头条PC版首页是不是好获取。

没想到天气接口直接就能拿到。那就开始吧!

打开浏览器的调试窗口。这里有一个技巧:如果第一次加载页面,无法记录到和天气相关的数据请求。

可以先 清除历史请求记录,然后选择 筛选 所有的api请求。点击顶部的 天气城市切换 ,可以看到下面已经显示出来切换后城市的天气请求数据了。

20221129014803

对获取到的天气接口做精简,得到如下:

1
https://www.toutiao.com/stream/widget/local_weather/data/?city=上海

也就是说,我们只需要提供一个 城市名称 即可。


提取天气数据

Node-Red 页面中添加一个 inject节点 作为流程的触发起点。

上面我们得到了天气api接口,我们要做的第一步就是请求接口,得到天气数据。那么就需要从 网络 组中找一个能够发起http请求的节点。这里我们选择 http request节点

20221129014848

注意,URL一栏填入的接口中,为了防止报错要将城市中文名称进行URL编码处理(说明:直接从浏览器地址栏中拷贝过来就是被URL编码后的)。

再添加一个 debug节点 用来查看请求返回的结果。点击 部署 ,触发流程。

结构如下:

20221129014954

可以看到正确请求了接口并返回了该城市天气数据。

返回的天气数据直接是一个 json对象 ,那么我们可以直接拿到想要的信息。如上图所示,我们需要的参数都在 weather 对象下。那首先,我们要先拿到这个 weather 对象。

这里选择用 function节点 来处理。根据返回的json结构,加入如下代码:

1
2
3
4
5
6
var data = msg.payload.data.weather;

// 提取数据

msg.payload=data;
return msg;

20221129015022

再次点击右上角 部署 ,执行流程:

20221129015035

可以看到,右侧的输出中打印出了 weather对象 包含的所有属性。


构造天气信息

天气数据获取到了,下面要来考虑下如何输出这些信息。

获取指定参数

天气信息中,除了包含当前天气情况,今天天气情况和明天天气情况以外,还有未来两周天气和未来24小时天气情况。某些城市还包含特殊天气提醒。

这里为了简单,我只获取当时、今日和明日天气。其他的后续再考虑扩展。

继续在 function节点 中对数据做二次处理。

20221129015053

部署 后查看输出:

20221129015111

正确得到了我们想要的指定参数。


文案组装

获取到了所需的天气属性参数,对这些信息进行拼装,整理成了如下的天气播报文案:

1
[上海]当前天气:[阴],气温[21]℃,空气质量[优]。今日天气:[中雨]转[小雨],气温[14]℃~[22]℃。明日天气:[小雨],[5]℃~[17]℃。

其中,中括号 [] 中的内容为需要的天气属性参数值。

那这里又遇到一个问题,要如何将这些天气属性参数拼接成上面的文案呢?

Node-Red 中提供了一个 template节点 ,我们可以用该节点实现文案拼接。

拖放一个 template节点 ,先来研究一下如何使用。

20221129015129

将其中模板内容改为如下:

20221129015145

然后 部署 、执行。查看输出:

20221129015211

那么,从上一个节点中传递过来的 payload 参数,就表示上面经过二次处理后的 完整数据,需要哪个参数,直接通过

1
{{payload.xxx}}

的形式就能获取到。

所以,模板中的内容对应于上面的文案,修改为:

1
{{payload.city}}当前天气:{{payload.cur_con}},气温{{payload.cur_tp}}℃,空气质量{{payload.qua_level}}。今日天气:{{payload.day_con}}转{{payload.night_con}},气温{{payload.low_tp}}℃~{{payload.high_tp}}℃。明日天气:{{payload.tom_con}},{{payload.tom_low_tp}}℃~{{payload.tom_hight_tp}}℃。

20221129015238

注意,下面的 输出为 类型要选为 纯文本

部署 后执行,查看输出内容。

20221129015254

貌似输出的内容中有一些错误。

排查问题

最终输出的结果中出现了问题,那么要如何来调试找出问题所在呢?

这里就不得不再提一下 debug节点

前面我们在执行完成每一个步骤之后,都会加一个 debug节点 来查看该步骤的输出内容。这样的话,就便于我们判断该步骤是否执行成功。

20221129015315

经过查看,原来是在 提取天气数据 阶段出了问题

20221129015330

将其改正后,再次部署查看。

20221129015342

此时,输出的天气文案就是我们想要的了。


发送通知

天气信息有了,下一步就要考虑如何接收通知了。

选择通知方案

便于实现的消息通知方式,除了企业微信、钉钉机器人、飞书机器人之外,对于iPhone用户来说,还可以选择像 Bark 这种开源方案。

这里我选择的是一款名为 PushDeer 的开源App推送方案,效果类似于 Bark

参考 PushDeer 官方文档 使用官方在线版 - PushDeer·推送说明 的说明,在安装好App后,获取相应的 key 就可以通过如下的请求方式发送消息了:

1
https://api2.pushdeer.com/message/push?pushkey=key&text=要发送的内容

实现通知请求

Node-Red 中,发送通知请求还是继续使用 http request节点 来实现。

拖放一个 http request节点,由于此时的请求链接是带有 可变化 参数的,并不是像上面获取天气的链接那样直接指定后就不再改变。所以,这里在内容下拉框中要选择 Append to query-string parameters 项,表示将前面步骤传递过来的 msg.payload 作为url请求参数来使用。

20221129015407

但我们知道,上一个步骤 构造天气信息 中,输出的是我们拼装后的天气文案。

那也就是说,我们要在这两个节点之间对数据再做一次转换,将上一步的 天气文案 经过处理后作为下一个步骤的url请求参数使用。

构造请求参数

在上面 PushDeer 的请求链接中,我们需要的是两个url请求参数: pushkeytext 。其中,pushkey 在我们安装完App后已经得到;而 text 就是上一个步骤中的天气文案。

但要怎么将这两个参数作为url请求参数呢?

在使用工具时遇到了问题,最简单的方法就是去看官方文档。

查询 Node-Red 的官方文档,我找到了这篇文章 Handle query parameters passed to an HTTP endpoint : Node-RED

参照其中的说明,我们可以将参数构造成如下的键值对结构:

1
2
3
4
{
"name": "Nick",
"colour": "blue"
}

这样作为url的请求参数后的形式就是 /hello-query?name=Nick&colour=blue

这不正是我们所需要的嘛。

于是,为了实现中间的处理操作,我们可以通过拖放一个 function节点 来实现。将函数的处理逻辑改成如下:

20221129015429

同时,修改 http request节点 发送的URL为去除参数的形式:

20221129015442

发送通知

将以上流程组合,点击 部署 后手动触发。会发现 debug节点 打印了每一步的输出结果:

20221129015457

同时,我的手机上也收到了相应的通知提醒:

20221129015511

至此,天气预报通知手动触发操作算是实现了。


定时触发

不过为了接收天气预报,我们总不能每次都要打开电脑去点一下来进行操作吧。

最基本的,我想要实现的是每天早晨7:30起床后,手机上收到一条天气播报,了解一下当天的天气情况,这样临出门前也能应对当天可能出现的恶劣天气;每天晚上20:30临睡觉前,收到一条天气播报,了解一下明天的整体天气情况,是降温还是偏热,可以提前考虑一下明天的穿衣情况。

但是在 Node-Red 中想要实现定时触发,我却找不到符合这种条件的节点。虽说 inject节点 可以实现简单的 重复触发 操作,但功能比较简单,想要实现定时功能要做的处理比较复杂。

其实,Node-Red 的节点本质上就是一些 Nodejs 的模块实现的功能,内部执行的就是 Nodejs 脚本。

那么,我们可以通过安装第三方的模块来实现更多更复杂的功能。

安装定时模块

为了实现定时任务,比较灵活的方式就是通过 cron表达式 来实现。

Node-Red 中比较有名的支持 cron表达式 的模块叫 node-red-contrib-cron-plus

要在 Node-Red 中安装模块,依次选择:右上角 菜单节点管理 – 左侧 控制板 – 右侧 安装 – 在 搜索模块 中输入名称

20221129015647

找到相应模块后点击 安装 ,等待其安装即可。

20221129015706

npm加速

在等待了大约2分钟左右,我发现该模块还没有安装成功,一直处于下面的 安装中 界面:

20221129015717

又继续等待一段时间后,直接弹出了错误信息。查看日志后发现,果然又遇到了 特殊网络 问题。

20221129015730

上面日志中也描述的很清楚 npm install 安装时,网络请求失败。

对于 npm install 的问题,可以直接通过 替换国内镜像源 的方式来解决。

登录 树莓派 ,进入之前安装的 node-red 容器中:

1
docker-compose -f docker-compose-node-red.yml exec hass-nodered bash

直接执行如下命令来为 npm 设置国内镜像源:

1
npm config set registry https://registry.npmmirror.com

然后再回到 Node-Red 节点管理设置界面,再次安装模块,会发现该模块几秒钟就安装成功了:

20221129015745

定时模块配置

模块安装好后,在左侧的节点栏中可以看到新增了一个 cronplus 节点

20221129015756

拖放该节点并双击打开配置界面,在 Schedules 区域添加我们想要的定时cron表达式。

20221129015809

配置完点击 部署 后,可以发现该节点下方直接显示出了下一次执行的时间:

20221129015821

之后,将定时组件加入流程中。为了方便处理,我保留了手动和自动两种触发方式。同时也为了便于调试,我又将整体的流程布局做了调整,最终的效果如下:

20221129015830


流程分享

为了方便流程的分享,Node-Red 支持导入导出功能。

直接在右上角 菜单 中选择即可。

20221129015855


总结

至此,一个 Node-Red 入门流程 – 天气预报通知 的功能就实现了。

俗话说,授人以鱼不如授人以渔

这里主要就是想通过如何实现一个小功能来入门 Node-Red ,关键还是要理清思路,一步一步来,遇到了问题不要慌,通过错误日志一点点分析,最终得到想要的结果。


如有疑问或需要技术讨论,请留言或发邮件到 service@itfanr.cc