天天看點

建構自己的 Smart Life 私有雲(二)-> 連通 IFTTT & Slack

部落格搬遷至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

建構自己的 Smart Life 私有雲(二)-> 連通 IFTTT & Slack

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

建立 Slack App

建立完畢登入之後,預設應該有

#general

#random

等 channel,但暫時不用這兩個 channel。

接下來,我們來建立一個 App。

打開 https://api.slack.com/,點選

Start Building

建構自己的 Smart Life 私有雲(二)-> 連通 IFTTT & Slack

輸入 App 名稱和你要添加到的 workspace。

建構自己的 Smart Life 私有雲(二)-> 連通 IFTTT & Slack

設定 Bot 資訊

建立完畢之後,我們需要設定這個 app 的機器人相關資訊,打開 app 設定頁面,選擇

Bot Users

建構自己的 Smart Life 私有雲(二)-> 連通 IFTTT & Slack

設定機器人的名稱(Display name 和 Default name)。勾選

Always Show My Bot as Online

,點選

Save Changes

設定 Events API

Event API 可以在各種時間發生的時候觸發調用,比如 消息發送的時候、channels 改變的時候等等。

我們先回到我們的 web 服務,打開上一章建立的

AngeliaController

,新增一個處理 Event 的 api:

@PostMapping("/say/at")
fun say(@RequestBody request: BotEventRequestVo): JSONObject {
    logger.info("[slack event request]request -> \n$request")
    return JsonResult.success(
                    "token" to request.token,
                    "challenge" to request.challenge,
                    "message" to message
            )
}

data class BotEventRequestVo(
        val challenge: String?,

        val token: String?,
        val team_id: String?,
        val api_app_id: String?,
        val event: BotEventVo?,
        val type: String?,
        val event_id: String?,
        val event_time: String?,
        val authed_users: List<String>?
)

data class BotEventVo(
        val type: String?,
        val user: String?,
        val text: String?,
        val client_msg_id: String?,
        val ts: String?,
        val channel: String?,
        val event_ts: String?,
        val channel_type: String?
)
           

建構,部署到伺服器。

打開 Slack App 設定頁面的

Event Subscriptions

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

Request URL

中填寫剛剛在我們 web 服務上建立的接口

http://[server ip]:xxx/angelia/say/at

,并且點選驗證。

注意:這裡認證的依據是,你的接口 Response 需要傳回請求中的

challenge

資料就算認證成功。

然後在

Subscribe to Bot Events

中添加訂閱的事件,需要增加的是 message.im

message.im

表示當你跟 bot 的私聊中産生消息的時候(有可能是你發送消息給 Bot,也有可能是 Bot 發消息給你),事件就會觸發。
建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

點選儲存。

這時,當你在 Slack 中發送消息給機器人的時候,你的 web 服務端就能收到請求了。

處理事件

你的 web 伺服器收到請求之後,需要對此進行處理,是以你需要去解析發的消息中的資訊,然後打開/關閉對應裝置(插座)的開關。完善之前的

say

接口:

@Autowired
lateinit var tuyaClientService: TuyaClientService
@Autowired
lateinit var angeliaSlackProperties: AngeliaSlackProperties

/**
* Angelia 機器人 對話入口
*/
@PostMapping("/say/at")
fun say(@RequestBody request: BotEventRequestVo): JSONObject {
    try {
       val text = request.event?.text
       val eventType = request.event?.type
       if (eventType == "message" // 直接對話
            ||
            request.event.user != angeliaSlackProperties.angelia_id // angelia自己發的忽略掉
       ) {
          val message = angeliaBotService.parseTuyaClient(text)
                          ?: "Sorry, I can not understand."

          angeliaSlackService.postMessage(JSONObject().apply {
              this["text"] = "$message"
              this["channel"] = request.event.channel
              this["as_user"] = true
          })
       }
       return JsonResult.success(
               "token" to request.token,
               "challenge" to request.challenge,
               "message" to "Request eventId(${request.event_id}) done."
       )
   } catch (e: Exception) {
       angeliaSlackService.postMessage(JSONObject().apply {
           this["text"] = "Sorry! Something is wrong: ${e.message}"
           this["channel"] = request.event?.channel
           this["as_user"] = true
       })
       return JsonResult.error(e.message)
   }
}
           

上面代碼的邏輯很簡單:

  • 首先,eventType是直接對話的(與機器人 bot 私聊),并且是我發給機器人的(機器人發給我的消息不用處理)才會去處理
  • 然後通過

    angeliaBotService.parseTuyaClient()

    方法進行文本解析和處理
  • 如果解析不出來,則傳回 null,message 就是 "Sorry, I can not understand."
  • 最後傳回 Response(帶上 message),這裡的 message 就是 Bot 發送給我的資料。

這裡需要做一些 Slack 的配置 slack.properties:

# token for bot
angelia.slack.bot_token=Bearer xoxb-2923xxxxxxxxxxxxxxxxxxxx

# slack api
angelia.slack.api_base_url=https://slack.com/api
angelia.slack.api_chat_post_message=/chat.postMessage

angelia.slack.angelia_id=UCWxxxxxx
           

angelia.slack.bot_token

:是 Bot 發送消息到 Slack 的token,這個 token 可以在 app 設定頁面的

OAuth & Permissions

中拿到

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack
注意:是下面的那個

Bot User OAuth Access Token

,并且添加到配置檔案的時候需要加上

Bearer

(注意後面有個空格)

angelia.slack.api_base_url

angelia.slack.api_chat_post_message

是發送消息的 url,不用改動。

angelia.slack.angelia_id

表示機器人的id,可以通過在 slack 左側選中機器人右鍵複制連結,path 最後部分就是 id

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

最後,你就能在 slack 中打開與機器人聊天框,發送“關閉插座a”來控制插座:

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

內建 Google Assistant 和 IFTTT

首先確定你的手機裝有 Google Assistant(Google Home 先不讨論。。。是的,我沒買- -)。

首先我們需要在 web 伺服器端再建立如下一個接口:

/**
* 插座控制接口
*/
@PostMapping("/control/plug")
fun controlPlug(@RequestBody request: PlugRequestVo): JSONObject {
   val dev = tuyaClientProperties.findDev(request.alias)
   return try {
       if (null == dev) {
           JsonResult.error("Device named ${request.alias} is not found")
       } else {
           tuyaClientService.controlPlug(dev.devId, request.turnOn)
           JsonResult.success()
       }
   } catch (e: Exception) {
       JsonResult.error(e.message)
   }
}

data class PlugRequestVo(
     val alias: String,
     val turnOn: Boolean
)
           

建構部署到伺服器。

然後打開IFTTT、注冊(如果還沒有賬戶)登入,建立 Applet

This:選擇 Google Assistant:

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

That:選擇 Webhook:

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

注意:POST 請求,在 body 中填寫如上 json 資料。

關閉的 Applet 也是類似,把 body 中的 turnOn 改成 false 就可以了

最後,你就可以通過 “OK, Google” 喚醒 Google Assistant,然後說"Turn on plug a"來打開插座了。

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

吐槽下塗鴉的 Google Assistant

本來想直接使用 Google Assistant 的 Smart Life 的,但是一直沒成功,很多人也在反映這個事情,不過貌似沒什麼效果(看下面這個評分,估計反映一直是被無視的- -):

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack
建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack
建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

使用 Slack 的 Slash Command 控制

在 web 服務中再新增兩個接口用于 Slash Command:

/**
* 插座控制接口,For Slack command line(slash commands)
*/
@PostMapping("/plug/turnon")
fun plugTurnOnForCommand(@RequestBody body: String): JSONObject {
   return JsonResult.success("text" to plugControlForCommand(body, true))

}

/**
* For Slack command line(slash commands)
*/
@PostMapping("/plug/turnoff")
fun plugTurnOffForCommand(@RequestBody body: String): JSONObject {
   return JsonResult.success("text" to plugControlForCommand(body, false))
}

/**
* For Slack command line(slash commands) control
*/
private fun plugControlForCommand(body: String, turnOn: Boolean): String {
   try {
       return body.split("&").map {
           val pair = it.split("=")
           Pair(pair[0], URLDecoder.decode(pair[1], "UTF-8"))
       }.firstOrNull {
           it.first == "text"
       }?.let {
           val dev = tuyaClientProperties.findContainsDev(it.second)
           if (null == dev) {
               "Sorry for failed command, Device named ${it.second} is not found."
           } else {
               tuyaClientService.controlPlug(dev.devId, turnOn)
               "${if (turnOn) "Turn On" else "Turn Off"} Done(${it.second})."
           }
       } ?: "Sorry for failed command, Device name required."
   } catch (e: Exception) {
       return "Sorry for failed command, ${e.message}."
   }
}
           

打開 App 設定頁面的

Slash Commands

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

點選

Create New Command

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

然後在聊天的輸入框中就可以通過"/"顯示 command 提示,選擇指令,後面跟上你要執行該指令的裝置别名就行了。

建構自己的 Smart Life 私有雲(二)-&gt; 連通 IFTTT &amp; Slack

其它場景

還有其它很多場景可以實作。比如:

  • 結合 IFTTT,當離開家門100m遠的時候,自動觸發 webhook,讓你的私有雲幫你把電源、智能們關閉。
  • 實時檢測你的位置和家門,如果你不在家,自動調用 Google Calendar 确定你的日程安排,如果又沒有外出的安排,則通過 Slack 發送 Interactive messages 到你手機上提醒,提供按鈕一鍵鎖門。
  • 小細節,晚上手機充電的時候,可以設定手機一旦充滿,關閉電源,又如果手機電源掉電過快,低于90%的電量,重新自動開啟電源,確定你早上起床的時候手機電量肯定在某個值之上。
  • 等等等等,太多的智能場景可以去實作。

章尾

現在越來越多的廠商制作着各種各樣的智能裝置,但是又在自己的一畝三分地固步自封。做個插座,提供一個 app 控制下開關、定個時、做個 schedule 就是所謂的智能了,你買了我的裝置就必須要用我的軟硬體産品。那些需要使用者花心思去考慮什麼時候我該怎麼的裝置不是冰冷的,沒有生命的麼?智能是人類賦予了裝置生命,掌握了“思考”的能力,現在的生活如此多元化,再牛的公司也不可能覆寫你的所有生活領域,如果買了這樣的智能裝置但自此被囚困在這裡,我想,這才是我非智能生活的開始吧。

繼續閱讀