Email notification on the MikroTik BLE tag's accelerometer triggers

在本指南中,我们将快速分步展示如何设置您的 KNOT,使其在检测到 TG-BT5-IN 或 TG-BT5-OUT 标签报告的"已触发"条件时发送电子邮件通知。

简介

在本指南中,我们将快速分步展示如何设置您的 KNOT,使其在检测到 TG-BT5-IN 或 TG-BT5-OUT 标签报告的"已触发"条件时发送电子邮件通知。

这两个标签都有一个内置加速度计,能够检测自由落体、唤醒/移动和倾斜状态。当标签设置为广播 MikroTik 格式的载荷,并且加速度计触发器已启用(使用 MikroTik Beacon Manager 应用)→ 每当将要检测到触发器时,标签将立即广播一个广播载荷/报告。

对于 iOS,触发器设置如下所示(处于禁用状态/默认设置):

对于 Android,触发器设置如下所示(处于禁用状态/默认设置):

要激活触发器检测,只需勾选相应的"复选框"。

标签广播 Bluetooth 载荷后 → 载荷的第 21 个八位字节将指示检测到的确切触发器。您可以在 IoT>Bluetooth>Advertisng reports 选项卡下查看载荷:

如上图所示,第 21 个八位字节为 "04",这表明该载荷是在标签检测到自由落体条件时发送的(这些载荷是在我们"意外"掉落或抛出标签时广播的)。

一切配置完成后,将发生以下情况:

  • KNOT 将按计划运行一个脚本。
  • 脚本将"读取/扫描"显示在 IoT>Bluetooth>Advertising reports 选项卡中的载荷。
  • 如果存储/捕获的载荷的第 21 个八位字节值等于任何"已触发"值 → 将发送电子邮件通知。

换言之,当 KNOT 扫描载荷并发现其中一个载荷的第 21 个八位字节指示触发器已激活时 → 您将收到一封检测到触发器的电子邮件通知。

TG-BT5 标签配置

在此特定示例中,我们需要将标签设置为以 MikroTik 格式工作。在 MikroTik 格式中,每个载荷的第 21 个八位字节将指示其被触发的原因。

您可以按照 iOS 和/或 Android 指南("Advertisement"/Beacon 设置部分)找到如何启用触发器的说明。

为了更容易地"激活"触发器,我们还可以按照 iOS 和/或 Android 指南(Free Fall Threshold 和 Duration 部分)更改触发器的设置。为了测试目的,基本上为了更快地"触发"检测,我们可以将 "Free Fall Duration" 参数更改为 "0" 秒(这将确保所有轴上处于阈值内的任何加速度都会被立即检测为"自由落体"事件)。

RouterOS 配置

信息

需要 iot 软件包。您可以从我们的下载页面——在 "Extra packages" 下获取它。 配置可以在 4 个步骤内完成:

  • 启用 scanner(并且最好确认标签在检测到触发器时正在广播载荷);
  • 设置电子邮件服务器;
  • 导入脚本(并根据需求修改几行脚本);
  • 设置调度器。

Bluetooth Scanner

转到 IoT>Bluetooth>Scanners 选项卡并确保它已启用:

转到 Advertising reports 选项卡,并使用 MAC 地址过滤选项过滤列表(您可以在标签本身上印制的标签上找到 MikroTik 标签的 MAC 地址)。

尝试"触发"已配置的检测,并通过检查第 21 个八位字节的值来确认它。

在我们的示例中,我们为标签配置了"自由落体"检测,并将其掉落。我们收到来自标签的报告,指示"下落"状态(第 21 个八位字节 = 04):

我们已经确认标签正确报告了触发器。

电子邮件

导航到 Tools>Email 部分并设置您选择的电子邮件服务器。

在本指南中,我们将使用所示的 GMAIL 示例。

尝试发送一封测试电子邮件以确保设置正确。

脚本

选项 (a)

导航到 System>Scripts 菜单并在其中添加一个新脚本。

您可以复制下面的脚本。将下面的脚本复制到"记事本"中,然后再次将其复制到脚本的 "Source:" 字段中。

## Input MAC address of the tag within ""
:local addressRegex "2C:C8:1B:E2:15:29"

#enter the subject for the email within the ""
:local emailsubject "RouterOS report!"

#enter the email address wthin the ""
:local emailaddress "YOUR_EMAIL@gmail.com"

#Script:
################################## Bluetooth ##################################
:local flagStr do={
    :local str ""

    :if ($1 & 0x01) do={ :set $str " switch" }
    :if ($1 & 0x02) do={ :set $str "$str tilt" }
    :if ($1 & 0x04) do={ :set $str "$str free_fall" }
    :if ($1 & 0x08) do={ :set $str "$str impact_x" }
    :if ($1 & 0x10) do={ :set $str "$str impact_y" }
    :if ($1 & 0x20) do={ :set $str "$str impact_z" }

    :if ([:len $str] = 0) do={ :return "" }

    :return [:pick $str 1 [:len $str]]
}

:local triggernameF "free_fall"
:local triggernameT "tilt"
:local triggernameX "impact_x"
:local triggernameY "impact_y"
:local triggernameZ "impact_z"
:local triggernameS "switch"

## Find fresh Bluetooth advertisements
:global btOldestAdvertisementTimestamp
:if ([:typeof $btOldestAdvertisementTimestamp] = "nothing") do={
    # First time this script has been run since booting, need to initialize
    # persistent variables
    :set $btOldestAdvertisementTimestamp 0
}
:local advertisements [/iot bluetooth scanners advertisements print detail \
    as-value where \
        epoch > $btOldestAdvertisementTimestamp and \
        address ~ $addressRegex
]
:local advCount 0
:local lastAdvTimestamp 0
:local triggerlist ""

:local triggerF
:local triggerT
:local triggerX
:local triggerY
:local triggerZ
:local triggerS

:local messageF ""
:local messageT ""
:local messageX ""
:local messageY ""
:local messageZ ""
:local messageS ""

:local 21st ""

:foreach adv in=$advertisements do={
    :local address ($adv->"address")
    :local rssi ($adv->"rssi")
    :local epoch ($adv->"epoch")
    :local rtime ($adv->"time")
    :local ad ($adv->"data")
    :local flags [:tonum "0x$[:pick $ad 40 42]"]
    :local obj "$[$flagStr $flags]"

    :set $advCount ($advCount + 1)
    :set $lastAdvTimestamp $epoch
    :set $triggerlist "$triggerlist$obj"

:set triggerF [:pick $triggerlist ([find $triggerlist "free_fall"]-0) ([find $triggerlist "free_fall"]+9)]
:if ($triggerF=$triggernameF) do={:set messageF "$triggernameF";:set 21st "not00";}
:set triggerT [:pick $triggerlist ([find $triggerlist "tilt"]-0) ([find $triggerlist "tilt"]+4)]
:if ($triggerT=$triggernameT) do={:set messageT "$triggernameT";:set 21st "not00";}
:set triggerX [:pick $triggerlist ([find $triggerlist "impact_x"]-0) ([find $triggerlist "impact_x"]+8)]
:if ($triggerX=$triggernameX) do={:set messageX "$triggernameX";:set 21st "not00";}
:set triggerY [:pick $triggerlist ([find $triggerlist "impact_y"]-0) ([find $triggerlist "impact_y"]+8)]
:if ($triggerY=$triggernameY) do={:set messageY "$triggernameY";:set 21st "not00";}
:set triggerZ [:pick $triggerlist ([find $triggerlist "impact_z"]-0) ([find $triggerlist "impact_z"]+8)]
:if ($triggerZ=$triggernameZ) do={:set messageZ "$triggernameZ";:set 21st "not00";}
:set triggerS [:pick $triggerlist ([find $triggerlist "switch"]-0) ([find $triggerlist "switch"]+6)]
:if ($triggerS=$triggernameS) do={:set messageS "$triggernameS";:set 21st "not00";}

}
:if ($advCount > 0) do={
    :set $btOldestAdvertisementTimestamp $lastAdvTimestamp
}

#Message structure:
:local message "$messageF
$messageT
$messageX
$messageY
$messageZ
$messageS
--trigger(s) reported by the tag!"

:if ($21st="not00") do={/tool e-mail send to=$emailaddress subject="$emailsubject" body="$message"} else={:put "21st octet does not have triggers detected!"}

需要考虑以下 3 行:

:local addressRegex "2C:C8:1B:E2:15:29"

行,我们在其中输入您希望监控的标签的 MAC 地址;

:local emailsubject "RouterOS report!"

行,您可以在其中更改电子邮件的主题;

:local emailaddress "YOUR_EMAIL@gmail.com"

电子邮件地址行,您需要在其中输入电子邮件地址。即您希望将报告发送到何处。

您还可以使用以下行更改电子邮件消息的结构:

#Message structure:
:local message "$messageF
$messageT
$messageX
$messageY
$messageZ
$messageS
--trigger(s) reported by the tag!"

随意为脚本命名,例如 triggernotification。点击 Apply 和 OK。

信息

此外,在此示例中,我们专门展示了电子邮件通知场景。但是! 如果您想使用其他方法发送通知,只需修改下面这一行:

:if ($21st="not00") do={/tool e-mail send to=$emailaddress subject="$emailsubject" body="$message"}

您可以将该行中的 do={/tool e-mail... 部分更改为例如 do={/tool fetch... 或 do={/iot mqtt publish...。这样,您就可以改为发送 HTTP post 或 MQTT 发布消息。

如果您希望在检测到触发器时收到手机通知,您还可以利用 IFTTT 服务(向 IFTTT webhook 发送 HTTP post),如我们在此处的另一份指南中所述。 您可以通过命令 "/system script run triggernotification" 手动运行脚本,或点击 Script List 部分下的 "Run Script" 按钮。

您应确保在手动启动脚本后收到了电子邮件通知。

当脚本 (a) 被启动时,RouterOS 将检查每一个接收/存储的 Bluetooth 载荷,如果载荷列表中发现任何触发器 → 将构造并发送一封电子邮件。此电子邮件将仅指出列表中检测到了哪些触发器,没有附加信息。

选项 (b)
## Input MAC address of the tag within ""
:local addressRegex "2C:C8:1B:E2:15:29"

## POSIX regex for filtering Bluetooth advertisements based on their data. Same
## usage as with 'addressRegex'.
:local advertisingDataRegex ""

## Signal strength filter. E.g. -40 would only include Bluetooth advertisements
## whose signal strength is stronger than -40dBm.
## To disable this filter, set it to ""
:local rssiThreshold ""

#enter the subject for the email within the ""
:local emailsubject "RouterOS report!"

#enter the email address wthin the ""
:local emailaddress "YOUR_GMAIL@gmail.com"

#Script:
################################## Bluetooth ##################################
:local flagStr do={
    :local str ""

    :if ($1 & 0x01) do={ :set $str " switch" }
    :if ($1 & 0x02) do={ :set $str "$str tilt" }
    :if ($1 & 0x04) do={ :set $str "$str free_fall" }
    :if ($1 & 0x08) do={ :set $str "$str impact_x" }
    :if ($1 & 0x10) do={ :set $str "$str impact_y" }
    :if ($1 & 0x20) do={ :set $str "$str impact_z" }

    :if ([:len $str] = 0) do={ :return "" }

    :return [:pick $str 1 [:len $str]]
}

:local triggernameF "free_fall"
:local triggernameT "tilt"
:local triggernameX "impact_x"
:local triggernameY "impact_y"
:local triggernameZ "impact_z"
:local triggernameS "switch"

## Find fresh Bluetooth advertisements
:global btOldestAdvertisementTimestamp
:if ([:typeof $btOldestAdvertisementTimestamp] = "nothing") do={
    # First time this script has been run since booting, need to initialize
    # persistent variables
    :set $btOldestAdvertisementTimestamp 0
}
:local advertisements [/iot bluetooth scanners advertisements print detail \
    as-value where \
        epoch > $btOldestAdvertisementTimestamp and \
        address ~ $addressRegex and \
        data ~ $advertisingDataRegex and \
        rssi > $rssiThreshold
]
:local advCount 0
:local lastAdvTimestamp 0
:local triggerlist ""

:local triggerF
:local triggerT
:local triggerX
:local triggerY
:local triggerZ
:local triggerS

:local messageF ""
:local messageT ""
:local messageX ""
:local messageY ""
:local messageZ ""
:local messageS ""

:local 21st ""

:foreach adv in=$advertisements do={
    :local address ($adv->"address")
    :local rssi ($adv->"rssi")
    :local epoch ($adv->"epoch")
    :local rtime ($adv->"time")
    :local ad ($adv->"data")
    :local flags [:tonum "0x$[:pick $ad 40 42]"]
    :local fflags "$[$flagStr $flags]"
    :if ($fflags="") do={:set $fflags "none - periodically broadcasted payload"}

    :local obj "# $advCount:
                              time: $rtime
                              trigger: $fflags

"
    :set $advCount ($advCount + 1)
    :set $lastAdvTimestamp $epoch
    :set $triggerlist "$triggerlist$obj"

:set triggerF [:pick $triggerlist ([find $triggerlist "free_fall"]-0) ([find $triggerlist "free_fall"]+9)]
:if ($triggerF=$triggernameF) do={:set messageF "$triggernameF";:set 21st "not00";}
:set triggerT [:pick $triggerlist ([find $triggerlist "tilt"]-0) ([find $triggerlist "tilt"]+4)]
:if ($triggerT=$triggernameT) do={:set messageT "$triggernameT";:set 21st "not00";}
:set triggerX [:pick $triggerlist ([find $triggerlist "impact_x"]-0) ([find $triggerlist "impact_x"]+8)]
:if ($triggerX=$triggernameX) do={:set messageX "$triggernameX";:set 21st "not00";}
:set triggerY [:pick $triggerlist ([find $triggerlist "impact_y"]-0) ([find $triggerlist "impact_y"]+8)]
:if ($triggerY=$triggernameY) do={:set messageY "$triggernameY";:set 21st "not00";}
:set triggerZ [:pick $triggerlist ([find $triggerlist "impact_z"]-0) ([find $triggerlist "impact_z"]+8)]
:if ($triggerZ=$triggernameZ) do={:set messageZ "$triggernameZ";:set 21st "not00";}
:set triggerS [:pick $triggerlist ([find $triggerlist "switch"]-0) ([find $triggerlist "switch"]+6)]
:if ($triggerS=$triggernameS) do={:set messageS "$triggernameS";:set 21st "not00";}

}
:if ($advCount > 0) do={
    :set $btOldestAdvertisementTimestamp $lastAdvTimestamp
}

:if ($21st="not00") do={/tool e-mail send to=$emailaddress subject="$emailsubject" body="$triggerlist"} else={:put "21st octet does not have triggers detected!"}

当脚本 (b) 被启动时,RouterOS 将检查每一个接收/存储的 Bluetooth 载荷,如果载荷列表中发现任何触发器 → 将构造并发送一封电子邮件。与脚本 (a) 相比,此电子邮件将包含稍微更详细的信息。在这种情况下,消息将指示每个载荷的接收时间。

调度器

要自动化此过程,请在 System>Scheduler 选项卡下添加一个新的调度器:

在 "On Event:" 字段下输入 "/system script run triggernotification",并设置您希望运行脚本以检查/扫描广播报告的 interval(例如 10 秒)。

点击 Apply 和 OK。

结果验证

  1. 确认标签广播广告报告并且标签的触发器被检测到:

  1. 确认您的电子邮件服务器设置正确,并且您能够从 KNOT (RouterOS) 发送电子邮件。

  2. 在您手动运行脚本或将调度器应用于脚本后,电子邮件通知应能成功发送,如下所示:

     Script (a):

     Script (b):