...
# Required packages: iot
################################ Configuration ################################
# Name of an existing MQTT broker that should be used for publishing
:local broker "AWS"# MQTT topic where the message should be published
:local topic "my/test/topic"# 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 ""# 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 "-40"#################################### 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 obj "\
{\
\"id\":\"$[$minimizeMac address=$address]\",\
\"ts\":$ts,\
\"rssi\":$rssi,\
\"ed\":{\
\"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 \
"{\
\"clientId\":\"$[/iot mqtt brokers get value-name=client-id \
[/iot mqtt brokers find name=$broker]]\",\
\"t\":0,\
\"v\":1,\
\"OldestAdvertisementTimestamp\":$btOldestAdvertisementTimestamp,\
\"locs\":[{\
\"id\":\"$[$minimizeMac address=$ifaceMac]\",\
\"tags\":[$advJson],\
\"ed\":{\
\"model\":\"$model\",\
\"sn\":\"$serialNumber\",\
\"ros\":\"$rosVersion\",\
\"cpu\":$cpuLoad,\
\"umem\":$usedMemory,\
\"fmem\":$freeMemory,\
\"psu\":$supplyVoltage,\
\"temp\":$boardTemp\
}\
}]\
}"
: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")
...
################################ Configuration ################################
# 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 ""# 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 "-40"#################################### 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 obj "\
{\
\"id\":\"$[$minimizeMac address=$address]\",\
\"ts\":$ts,\
\"rssi\":$rssi,\
\"ed\":{\
\"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 \
"{\
\"t\":0,\
\"v\":1,\
\"OldestAdvertisementTimestamp\":$btOldestAdvertisementTimestamp,\
\"locs\":[{\
\"id\":\"$[$minimizeMac address=$ifaceMac]\",\
\"tags\":[$advJson],\
\"ed\":{\
\"model\":\"$model\",\
\"sn\":\"$serialNumber\",\
\"ros\":\"$rosVersion\",\
\"cpu\":$cpuLoad,\
\"umem\":$usedMemory,\
\"fmem\":$freeMemory,\
\"psu\":$supplyVoltage,\
\"temp\":$boardTemp\
}\
}]\
}"
:log info "$message";
:put ("[*] Total message size: $[:len $message] bytes")
/tool fetch certificate=f79dda4ec5-certificate.pem.crt.txt_0 http-method=post output=user http-header-field="Content-Type:application/json" http-data=$message url="https://xxxxx.iot.us-east-2.amazonaws.com:8443/topics/my/test/topic":put ("[*] Done")
...