博客搬迁至https://blog.wangjiegulu.com

RSS订阅:https://blog.wangjiegulu.com/feed.xml

原文链接https://blog.wangjiegulu.com/2018/09/26/private-smart-life-cloud-b--working-with-ifttt-slack/

构建自己的 Smart Life 私有云(二)-> 连通 IFTTT & Slack

上一篇我们破解了涂鸦的插座,搭建了自己的 web 服务,暴露了一个接口来控制插座的开关。这篇我们配合 IFTTT、Slack 来控制插座:

  1. 说 "OK Google" 唤醒 Google Assistant,然后说 “帮我打开卧室的电源”,最后插座被打开。
  2. 创建 Slack 机器人 Angelia,对它发消息“帮我打开卧室的电源”,然后插座打开, Angelia 回复说 “好的,已经打开”。
  3. 通过 Slack 机器人 Angelia,发送 Slash Commands,打开关闭插座。

创建自己私人的 Slack Workspace

打开 Slack,根据提示创建自己的 Slack Workspace: https://slack.com/create

比如我的 Workspace 为 https://wangjie.slack.com

创建 Slack App

创建完毕登录之后,默认应该有 #general#random 等 channel,但暂时不用这两个 channel。

接下来,我们来创建一个 App。

打开 https://api.slack.com/,点击 Start Building

输入 App 名称和你要添加到的 workspace。

设置 Bot 信息

创建完毕之后,我们需要设置这个 app 的机器人相关信息,打开 app 设置页面,选择 Bot Users

设置机器人的名称(Display name 和 Default name)。勾选 Always Show My Bot as Online,点击 Save Changes

设置 Events API

Event API 可以在各种时间发生的时候触发调用,比如 消息发送的时候、channels 改变的时候等等。

我们先回到我们的 web 服务,打开上一章创建的 AngeliaController,新增一个处理 Event 的 api:

  1. @PostMapping("/say/at")
  2. fun say(@RequestBody request: BotEventRequestVo): JSONObject {
  3. logger.info("[slack event request]request -> \n$request")
  4. return JsonResult.success(
  5. "token" to request.token,
  6. "challenge" to request.challenge,
  7. "message" to message
  8. )
  9. }
  10. data class BotEventRequestVo(
  11. val challenge: String?,
  12. val token: String?,
  13. val team_id: String?,
  14. val api_app_id: String?,
  15. val event: BotEventVo?,
  16. val type: String?,
  17. val event_id: String?,
  18. val event_time: String?,
  19. val authed_users: List<String>?
  20. )
  21. data class BotEventVo(
  22. val type: String?,
  23. val user: String?,
  24. val text: String?,
  25. val client_msg_id: String?,
  26. val ts: String?,
  27. val channel: String?,
  28. val event_ts: String?,
  29. val channel_type: String?
  30. )

构建,部署到服务器。

打开 Slack App 设置页面的 Event Subscriptions

Request URL 中填写刚刚在我们 web 服务上创建的接口 http://[server ip]:xxx/angelia/say/at,并且点击验证。

注意:这里认证的依据是,你的接口 Response 需要返回请求中的 challenge 数据就算认证成功。

然后在 Subscribe to Bot Events 中添加订阅的事件,需要增加的是 message.im

message.im表示当你跟 bot 的私聊中产生消息的时候(有可能是你发送消息给 Bot,也有可能是 Bot 发消息给你),事件就会触发。

点击保存。

这时,当你在 Slack 中发送消息给机器人的时候,你的 web 服务端就能收到请求了。

处理事件

你的 web 服务器收到请求之后,需要对此进行处理,所以你需要去解析发的消息中的信息,然后打开/关闭对应设备(插座)的开关。完善之前的 say 接口:

  1. @Autowired
  2. lateinit var tuyaClientService: TuyaClientService
  3. @Autowired
  4. lateinit var angeliaSlackProperties: AngeliaSlackProperties
  5. /**
  6. * Angelia 机器人 对话入口
  7. */
  8. @PostMapping("/say/at")
  9. fun say(@RequestBody request: BotEventRequestVo): JSONObject {
  10. try {
  11. val text = request.event?.text
  12. val eventType = request.event?.type
  13. if (eventType == "message" // 直接对话
  14. ||
  15. request.event.user != angeliaSlackProperties.angelia_id // angelia自己发的忽略掉
  16. ) {
  17. val message = angeliaBotService.parseTuyaClient(text)
  18. ?: "Sorry, I can not understand."
  19. angeliaSlackService.postMessage(JSONObject().apply {
  20. this["text"] = "$message"
  21. this["channel"] = request.event.channel
  22. this["as_user"] = true
  23. })
  24. }
  25. return JsonResult.success(
  26. "token" to request.token,
  27. "challenge" to request.challenge,
  28. "message" to "Request eventId(${request.event_id}) done."
  29. )
  30. } catch (e: Exception) {
  31. angeliaSlackService.postMessage(JSONObject().apply {
  32. this["text"] = "Sorry! Something is wrong: ${e.message}"
  33. this["channel"] = request.event?.channel
  34. this["as_user"] = true
  35. })
  36. return JsonResult.error(e.message)
  37. }
  38. }

上面代码的逻辑很简单:

  • 首先,eventType是直接对话的(与机器人 bot 私聊),并且是我发给机器人的(机器人发给我的消息不用处理)才会去处理
  • 然后通过 angeliaBotService.parseTuyaClient() 方法进行文本解析和处理
  • 如果解析不出来,则返回 null,message 就是 "Sorry, I can not understand."
  • 最后返回 Response(带上 message),这里的 message 就是 Bot 发送给我的数据。

这里需要做一些 Slack 的配置 slack.properties:

  1. # token for bot
  2. angelia.slack.bot_token=Bearer xoxb-2923xxxxxxxxxxxxxxxxxxxx
  3. # slack api
  4. angelia.slack.api_base_url=https://slack.com/api
  5. angelia.slack.api_chat_post_message=/chat.postMessage
  6. angelia.slack.angelia_id=UCWxxxxxx

angelia.slack.bot_token:是 Bot 发送消息到 Slack 的token,这个 token 可以在 app 设置页面的 OAuth & Permissions 中拿到

注意:是下面的那个 Bot User OAuth Access Token,并且添加到配置文件的时候需要加上 Bearer (注意后面有个空格)

angelia.slack.api_base_urlangelia.slack.api_chat_post_message 是发送消息的 url,不用改动。

angelia.slack.angelia_id 表示机器人的id,可以通过在 slack 左侧选中机器人右键复制链接,path 最后部分就是 id

最后,你就能在 slack 中打开与机器人聊天框,发送“关闭插座a”来控制插座:

集成 Google Assistant 和 IFTTT

首先确保你的手机装有 Google Assistant(Google Home 先不讨论。。。是的,我没买- -)。

首先我们需要在 web 服务器端再创建如下一个接口:

  1. /**
  2. * 插座控制接口
  3. */
  4. @PostMapping("/control/plug")
  5. fun controlPlug(@RequestBody request: PlugRequestVo): JSONObject {
  6. val dev = tuyaClientProperties.findDev(request.alias)
  7. return try {
  8. if (null == dev) {
  9. JsonResult.error("Device named ${request.alias} is not found")
  10. } else {
  11. tuyaClientService.controlPlug(dev.devId, request.turnOn)
  12. JsonResult.success()
  13. }
  14. } catch (e: Exception) {
  15. JsonResult.error(e.message)
  16. }
  17. }
  18. data class PlugRequestVo(
  19. val alias: String,
  20. val turnOn: Boolean
  21. )

构建部署到服务器。

然后打开IFTTT、注册(如果还没有账户)登录,创建 Applet

This:选择 Google Assistant:

That:选择 Webhook:

注意:POST 请求,在 body 中填写如上 json 数据。

关闭的 Applet 也是类似,把 body 中的 turnOn 改成 false 就可以了

最后,你就可以通过 “OK, Google” 唤醒 Google Assistant,然后说"Turn on plug a"来打开插座了。

吐槽下涂鸦的 Google Assistant

本来想直接使用 Google Assistant 的 Smart Life 的,但是一直没成功,很多人也在反映这个事情,不过貌似没什么效果(看下面这个评分,估计反映一直是被无视的- -):


使用 Slack 的 Slash Command 控制

在 web 服务中再新增两个接口用于 Slash Command:

  1. /**
  2. * 插座控制接口,For Slack command line(slash commands)
  3. */
  4. @PostMapping("/plug/turnon")
  5. fun plugTurnOnForCommand(@RequestBody body: String): JSONObject {
  6. return JsonResult.success("text" to plugControlForCommand(body, true))
  7. }
  8. /**
  9. * For Slack command line(slash commands)
  10. */
  11. @PostMapping("/plug/turnoff")
  12. fun plugTurnOffForCommand(@RequestBody body: String): JSONObject {
  13. return JsonResult.success("text" to plugControlForCommand(body, false))
  14. }
  15. /**
  16. * For Slack command line(slash commands) control
  17. */
  18. private fun plugControlForCommand(body: String, turnOn: Boolean): String {
  19. try {
  20. return body.split("&").map {
  21. val pair = it.split("=")
  22. Pair(pair[0], URLDecoder.decode(pair[1], "UTF-8"))
  23. }.firstOrNull {
  24. it.first == "text"
  25. }?.let {
  26. val dev = tuyaClientProperties.findContainsDev(it.second)
  27. if (null == dev) {
  28. "Sorry for failed command, Device named ${it.second} is not found."
  29. } else {
  30. tuyaClientService.controlPlug(dev.devId, turnOn)
  31. "${if (turnOn) "Turn On" else "Turn Off"} Done(${it.second})."
  32. }
  33. } ?: "Sorry for failed command, Device name required."
  34. } catch (e: Exception) {
  35. return "Sorry for failed command, ${e.message}."
  36. }
  37. }

打开 App 设置页面的 Slash Commands

点击 Create New Command

然后在聊天的输入框中就可以通过"/"显示 command 提示,选择命令,后面跟上你要执行该命令的设备别名就行了。

其它场景

还有其它很多场景可以实现。比如:

  • 结合 IFTTT,当离开家门100m远的时候,自动触发 webhook,让你的私有云帮你把电源、智能们关闭。
  • 实时检测你的位置和家门,如果你不在家,自动调用 Google Calendar 确定你的日程安排,如果又没有外出的安排,则通过 Slack 发送 Interactive messages 到你手机上提醒,提供按钮一键锁门。
  • 小细节,晚上手机充电的时候,可以设定手机一旦充满,关闭电源,又如果手机电源掉电过快,低于90%的电量,重新自动开启电源,确保你早上起床的时候手机电量肯定在某个值之上。
  • 等等等等,太多的智能场景可以去实现。

章尾

现在越来越多的厂商制作着各种各样的智能设备,但是又在自己的一亩三分地固步自封。做个插座,提供一个 app 控制下开关、定个时、做个 schedule 就是所谓的智能了,你买了我的设备就必须要用我的软硬件产品。那些需要用户花心思去考虑什么时候我该怎么的设备不是冰冷的,没有生命的么?智能是人类赋予了设备生命,掌握了“思考”的能力,现在的生活如此多元化,再牛的公司也不可能覆盖你的所有生活领域,如果买了这样的智能设备但自此被囚困在这里,我想,这才是我非智能生活的开始吧。

构建自己的 Smart Life 私有云(二)-> 连通 IFTTT & Slack的更多相关文章

  1. 构建自己的 Smart Life 私有云(一)-> 破解涂鸦智能插座

    博客搬迁至https://blog.wangjiegulu.com RSS订阅:https://blog.wangjiegulu.com/feed.xml 原文链接:https://blog.wang ...

  2. 视频私有云实战:基于Docker构建点播私有云平台

    私有云是为一个客户单独使用而构建的,因而提供对数据.安全性和服务质量的最有效控制.前置条件是客户拥有基础设施,并可以使用基础设施在其上部署应用程序.其核心属性是专有的资源.本篇文章将会结合网易云信的实 ...

  3. 四种方案:将OpenStack私有云部署到Hadoop MapReduce环境中

    摘要:OpenStack与Hadoop被誉为继Linux之后最有可能获得巨大成功的开源项目.这二者如何结合成为更猛的新方案?业内给出两种答案:Hadoop跑在OpenStack上或OpenStack部 ...

  4. OpenStack 企业私有云的若干需求(6):大规模扩展性支持

    本系列会介绍OpenStack 企业私有云的几个需求: 自动扩展(Auto-scaling)支持 多租户和租户隔离 (multi-tenancy and tenancy isolation) 混合云( ...

  5. 私有云的难处—为什么需要CloudEngine?

    私有云的难处 ——我们为什么需要 CloudEngine? 郑昀 创建于2016/7/31 最后更新于2016/8/3 关键词: 容器.Docker.OpenStack.虚拟机.私有云.Mesos.配 ...

  6. OpenStack 企业私有云的若干需求(4):混合云支持 (Hybrid Cloud Support)

    本系列会介绍OpenStack 企业私有云的几个需求: 自动扩展(Auto-scaling)支持 多租户和租户隔离 (multi-tenancy and tenancy isolation) 混合云( ...

  7. OpenStack 企业私有云的若干需求(7):电信行业解决方案 NFV

    自动扩展(Auto-scaling)支持 多租户和租户隔离 (multi-tenancy and tenancy isolation) 混合云(Hybrid cloud)支持 主流硬件支持.云快速交付 ...

  8. [转]新型智慧城市总体架构 华为 新ICT 一云二网三平台

    本文转自:http://www.jpsycn.com/hangyexinwen/20160801142354.html “十三五”规划提出,充分运用现代信息技术和大数据,建设一批新型示范性智慧城市.日 ...

  9. 恒天云 3.0:打造基于OpenStack的私有云新模式

    摘自恒天云官网:http://www.hengtianyun.com/download-show-id-17.html 云计算在当今IT世界中已发展地如火如荼,越来越多的企业利用云计算改造传统的数据中 ...

随机推荐

  1. Codeforces 854C Planning 【贪心】

    <题目链接> 题目大意: 表示有n架飞机本需要在[1,n]时间内起飞,一分钟只能飞一架.但是现在[1,k]时间内并不能起飞,只能在[k+1,k+n]内起飞.ci序号为i的飞机起飞延误一分钟 ...

  2. sql语句练习50题(Mysql版)

    表名和字段–1.学生表Student(s_id,s_name,s_birth,s_sex) –学生编号,学生姓名, 出生年月,学生性别–2.课程表Course(c_id,c_name,t_id) – ...

  3. [CF543A]/[CF544C]Writing Code

    [CF543A]/[CF544C]Writing Code 题目大意: 有\(n\)种物品,每种物品分别要\(c_i\)的代价,每个物品有\(1\)的体积,每个物品可以选多个,代价不能超过\(b\), ...

  4. 老毛桃UEFI版u盘启动盘

    使用老毛桃制作UEFI启动盘 下载UEFI版本启动盘制作工具,打开官方网站http://www.laomaotao.org,当前显示页面右下下载UEFI版本.文章写作时最新版本为9.3. 使用教程见: ...

  5. Coins [POJ1742] [DP]

      Description 给出硬币面额及每种硬币的个数,求从1到m能凑出面额的个数. Input 多组数据,每组数据前两个数字为n,m.n表示硬币种类数,m为最大面额,之后前n个数为每种硬币的面额, ...

  6. Hibernate简答题

    简单题目 1.持久化对象的三种状态,代表含义. 自由状态(transient): 不曾进行持久化,未与任何Session相关联 持久化状态(persistent): 仅与一个Session相关联 游离 ...

  7. Set集合架构和常用实现类的源码分析以及实例应用

    说明:Set的实现类都是基于Map来实现的(HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的). (01) Set 是继承于Collection的接口.它是一个不允许 ...

  8. keras用vgg16做图像分类

    实际上我只是提供一个模版而已,代码应该很容易看得懂,label是存在一个csv里面的,图片是在一个文件夹里面的 没GPU的就不用尝试了,训练一次要很久很久... ## import libaries ...

  9. list-循环小练习(作业已交未交)

    报错 list index out of range : 超出下标   这个错误是因为在写stus列表的时候写成了如下stus=['小花,未交'] ,但是取下标的时候取的是stus[1]:实际该列表中 ...

  10. python正则表达式里引入变量

    import re def reg_exp(senten): jiqiren = "阿童木" matchObj1 = re.search( r'(你(.*?)(男|女))|(机器( ...