You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 38 Next »

Introduction

Our TG-BT5-OUT Bluetooth tag model has a temperature sensor built in. This means that it can be used to measure the surrounding temperature.

The temperature's value is "written" into the advertising payload that the tag is going to broadcast over Bluetooth advertising channels. Based on how you configure the tag, the tag can broadcast the payload periodically or/and when a trigger is detected. You can find more information about the tag's configuration options in iOS and Android Beacon Manager guides.

You can see/display the payloads using our KNOT model under IoT>Bluetooth>Advertising reports tab:

The payloads will be shown in the "Advertisement (hex)" field and they will be in the hexadecimal format.

When the tag is configured in the MikroTik format, the payload's 14th and 15th octets indicate the temperature (ambient temperature in Celsius in signed 8.8 fixed point format) that was "sensed" at the moment of the broadcast.

An example of the payload in MikroTik's format is shown below:

15ff4f09010032a500000000ffff 5019 bd5954000061

Please note that all multi-byte values in the payload are in little-endian. So, if #14 and #15 octets indicate the temperature as "50 19" → the decimal temperature value is going to be (0x1950)/256 = 25.31 C.

With this knowledge, we can then utilize RouterOS scripting to structure a message out of the received payloads and send it to the MQTT/HTTP server. The server will be responsible for the data conversion from hexadecimal format to decimal format. In this guide, we will achieve the results using MQTT post to ThingsBoard.

ThingsBoard server and MQTT configuration

You will require to have a ThingsBoard server up and running. You can find useful information on how to set up your server by following the link. You can install the server locally onto a machine or use their cloud solution.

After you have the server ready, you will need to configure it to be able to receive MQTT messages. Please follow the "ThingsBoard configuration" link to set up your "device".

RouterOS configuration

Please check the link over here on how you can set up your MQTT broker depending on the device credential used by the ThingsBoard server.

After setting up your broker, confirm that the Bluetooth tag is broadcasting information as shown in the picture above under the IoT>Bluetooth>Advertising reports tab.

System>Script

Paste in the script below (under System>Scripts>Add):

# Required packages: iot

################################ Configuration ################################
# Name of an existing MQTT broker that should be used for publishing
 :local broker "tb"

# MQTT topic where the message should be published
 :local topic "v1/devices/me/telemetry"

 # Interface whose MAC should be used as 'Locator ID'
:local locatorIface "ether1"

# POSIX regex for filtering advertisement Bluetooth addresses. E.g. "^BC:33:AC"
# would only include addresses which start with those 3 octets.
# To disable this filter, set it to ""
:local addressRegex "2C:C8:1B:4B:BB:0A"

# 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 ""

#################################### System ###################################
:put ("[*] Gathering system info...")
:local ifaceMac [/interface get [/interface find name=$locatorIface] mac-address]
:local cpuLoad [/system resource get cpu-load]
:local freeMemory [/system resource get free-memory]
:local usedMemory ([/system resource get total-memory] - $freeMemory)
:local rosVersion [/system package get value-name=version \
    [/system package find where name ~ "^routeros"]]
:local model [/system routerboard get value-name=model]
:local serialNumber [/system routerboard get value-name=serial-number]
# Health is a bit iffy since '/system health' does not have 'find' in ROS6
:local health [/system health print as-value]
:local supplyVoltage 0
:local boardTemp 0
:foreach entry in=$health do={
    :if ($entry->"name" = "voltage") do={:set $supplyVoltage ($entry->"value")}
    :if ($entry->"name" = "board-temperature1") do={:set $boardTemp ($entry->"value")}
}

################################## Bluetooth ##################################
:put ("[*] Gathering Bluetooth info...")
: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 btProcessingStart [/system clock get time]
:local advertisements [/iot bluetooth scanners advertisements print detail \
    as-value where \
        epoch > $btOldestAdvertisementTimestamp and \
        address ~ $addressRegex and \
        data ~ $advertisingDataRegex and \
        rssi > $rssiThreshold
]
:local advJson ""
:local advCount 0
:local advSeparator ""
:local lastAdvTimestamp 0
# Remove semicolons from MAC/Bluetooth addresses
:local minimizeMac do={
    :local minimized
    :local lastIdx ([:len $address] - 1)
    :for idx from=0 to=$lastIdx step=1 do={
        :local char [:pick $address $idx]
        :if ($char != ":") do={
            :set $minimized "$minimized$char"
        }
    }
    :return $minimized
}

:foreach adv in=$advertisements do={
    :local address ($adv->"address")
    :local ts ($adv->"epoch")
    :local rssi ($adv->"rssi")
    :local ad ($adv->"data")
    :local tempf [:pick ($adv->"data") 28 32]
    :local temp ("0x".[:pick $tempf 2 4].[:pick $tempf 0 2])
    :local obj "{\
        \
           \"ts\":$ts,\
           \"values\":{\
            \"id\":\"$[$minimizeMac address=$address]\",\
            \"rssi\":\"$rssi\",\
            \"temp\":\"$temp\",\
            \"ad\":\"$ad\"\
            }\
        }"
    :set $advCount ($advCount + 1)
    :set $lastAdvTimestamp $ts
    # Ensure that the last object is not terminated by a comma
    :set $advJson "$advJson$advSeparator$obj"
    :if ($advSeparator = "") do={
        :set $advSeparator ","}
}

:if ($advCount > 0) do={

    :set $btOldestAdvertisementTimestamp $lastAdvTimestamp

}

:put ("[*] Found $advCount new advertisements \
    (processing time: $[([/system clock get time] - $btProcessingStart)])")

#################################### MQTT #####################################
:local message \
    "[$advJson]"
:log info "$message";
:put ("[*] Total message size: $[:len $message] bytes")
:put ("[*] Sending message to MQTT broker...")
/iot mqtt publish broker=$broker topic=$topic message=$message
:put ("[*] Done")

Change the broker's name that you have chosen for the MQTT broker within the quotation marks (in our example, we called it tb):

 :local broker "tb"

The default topic used by the ThingsBoard is (you do not have to change it):

 :local topic "v1/devices/me/telemetry"

Change the MAC address of the tag that you wish to monitor (in our example, we have the MAC address 2C:C8:1B:4B:BB:0A):

:local addressRegex "2C:C8:1B:4B:BB:0A"

The lines below will take the payload's 14th and 15th octets and "re-structure" the values from "ABCD" to "0xCDAB" (per our example from the Introduction section, from "5019" to "0x1950"):

    :local tempf [:pick ($adv->"data") 28 32]

    :local temp ("0x".[:pick $tempf 2 4].[:pick $tempf 0 2])

The MQTT message that we are posting is structured in the following section (you do not have to change it):

    :local obj "{\

        \

           \"ts\":$ts,\

           \"values\":{\

            \"id\":\"$[$minimizeMac address=$address]\",\

            \"rssi\":\"$rssi\",\

            \"temp\":\"$temp\",\

            \"ad\":\"$ad\"\

            }\

        }"

The message that is structured per the example above will be displayed in JSON as (the only real value we are going to focus on are "timestamp"→ "ts" and "temperature"→ "temp" in hexadecimal format, so feel free to remove additional parameters):

[

  {

    "ts": 1661333913375,

    "values": {

      "id": "2CC81B4BBB0A",

      "rssi": "-43",

      "temp": "0x1939",

      "ad": "15ff4f0901002de0ffff010000003919877c54000061"

    }

  }

]

Save the script and run it:

[admin@MikroTik] > system script run name_of_the_script
[*] Gathering system info...
[*] Gathering Bluetooth info...
[*] Found 1 new advertisements (processing time: 00:00:00)
[*] Total message size: 134 bytes
[*] Sending message to MQTT broker...

[*] Done
[admin@MikroTik] > 

System>Scheduler

Apply a scheduler to the script to run it with a required interval. Please note! If you have set up a scheduler to run the script, for example, every 2 minutes, it will mean that every received payload (broadcasted by the tag) during the 2-minute interval will be "structured" into the MQTT message. You will, most likely, not need to know the temperature of the tag every 2-5 seconds, so you can either change the MQTT message that is structured to only post the latest temperature reading or just change the IoT>Bluetooth>Scanners setting Filter duplicates to "keep-newest" (that way, the Bluetooth scanner will overwrite every new report from each individual tag's MAC address) and the script will only post 1 payload that was "scanned" at the moment when the script ran.

Results

You will be able to verify the results under the Latest telemetry section under the device you have created for ThingsBoard (in our example, we called the "device" KNOT):

The result is a successful MQTT post!

But! we would like to display the temperature (temp parameter) in decimal format and we would also like to display the data easier to perceive. This is where "Widgets" come into play.

ThingsBoard widgets

After you receive the value under the Latest telemetry section, you can show it on the "Widget".

The Javascripts used in the widgets should be able to convert the data from the hexadecimal format to the decimal format.

Select the value you wish to display in the widget (in our example, tempt) and click on the "Show on widget" button:

You will be able to browse the widgets in the window that pops up:

Click on the "Add to dashboard" button:

Select a new dashboard to be created or choose an existing dashboard that you already have pre-installed/pre-made. Click on "Add".

By applying the checkbox "Open dashboard" you will be redirected to the dashboard menu or you can go there manually.

We have also added a second table and, as a result, our test dashboard looks like this:

Our first table displays the value in the hexadecimal format as "0x192a" (raw value as we've sent it from the KNOT → the javascript for the table did not convert it to a decimal value yet) and our second table displays the value in a decimal format as "6442" (the javascript used for the table did convert the value from "0x192a" to "6442").

Because of the fact that the values in our tag's payload are in signed 8.8 fixed point format, we will need to divide the result by "256".

Enter the "Edit" mode and click on the "Edit widget" button:

Click on the "edit" button to edit the parameter temp:

In the popup window "Data key configuration" enable the checkbox "Use data post-processing function" and divide the returned value by 256 (return value/256;):

Save and apply the changes.

Do the same steps for the second/first table and, after that, the result should look like this:

Now both tables show converted decimal temperature.

  • No labels