Community discussions

MikroTik App
 
Jonty
just joined
Topic Author
Posts: 14
Joined: Wed Mar 27, 2024 9:05 am

3rd party bluetooth sensor

Thu Apr 04, 2024 3:44 pm

Good day
is there anyone that could help me, I have a bluetooth gas level sensor for a gas bottle. And need some help on how to make the script I have been trying but not to sure what I am doing.
here is a example of the hex payload I get: 0dff5900035e41000024684e24eb0302e5fe

I am needing to decode the PDU payload regularly would a script on the router work or would it be better to send it via MQTT

Here is the breakdown of the sensor.
Name Offset Length Description
Packet Length 2 1 Per BLE specificion - length of manufacturer specific data
BLE Flag 4 1 Per BLE specification - Identifies manufacturer specific data follows
Manufacturer ID 6,8 2 Per BLE specification - Identifies microcontroller manufacturer. Transmitted least significant byte first
Hardware ID 10 1 Bit 0-6: This ID represents the specific type of PRO sensor as follows: 0x03 = Pro Check, Bottom-up propane sensor 0x04 = Pro-200, top down BLE sensor, wired power 0x05 = Pro Check H20, bottom-up water sensor 0x08 = PRO+ Bottom-up Boosted BLE sensor, all commodities 0x09 = PRO+ Bottom-up BLE+Cellular Sensor, all commodities 0x0A = Top-down Boosted BLE sensor 0x0B = Top-down BLE+Cellular Sensor 0x0C = Pro Universal Sensor, bottom up, all commodities Other = Reserved for OEM or future applications, or documented in other integration guides Bit 7: Raw Tank Level extension bit - this bit will only be set when time of flight extends past 16384us. It is more than just a 15th extension bit, but rather changes the resolution to 4us with a 16384us offset, when set. Thus full scale range is 0 to 16383us with 1us resolution like all prior sensors, and then when this bit is set, 16384 to 81920us can be represented with 4us resolution. See sample code below for conversion
Battery Voltage 12 1 Bit 7: Reserved Bits 0-6: Battery voltage scaled such that [0 to 127] represents value [0 to 3.96875 volts]. In other words, read the lower 7 bits into an integer, and divide by 32 to get the battery voltage
Temperature 14 1 Bit 7: Sync button state Bit 0-6: Temperature, in units of C, with an offset of -40. Full range is thus -40 to 87C in 1C increments
Raw Tank Level 16,18 2 Sent least significant byte first Bits 14-15: Sensor measurement quality “stars” from 0 to 3. This is an arbitrary number that represents that quality or confidence level of the ultrasonic reading and how it is mounted on the tank Bits 0-13: Raw tank level time-of-flight in microseconds, see sample function ‘get_tank_height_lpg’ below for scaling information.
UID/MACaddress 20,22,24 3 Least 3 significant bytes of MAC address. Should always be validated that is matches a sensor the user has specifically "Synced" to. These 3 bytes represent the sensor ID
Sensor mount 26,28 2 Byte 10: X acceleration (signed integer from -128 to 127) Byte 11: Y acceleration (signed integer from -128 to 127) These two bytes are the accelerometer reading which indicates the angle the sensor is currently mounted in relation to the horizon. The readings measure the gravity vector current applied to the sensor in the range of +/- 0.125G. If held beyond that angle, the reading will saturate or clip to the extremes in a similar manner as a “bubble level” might hit the ends. To convert to G, take the signed integer and divide by 1024
UUID Length 30 1 Per BLE Specification - Length of the following UUID service length descriptor
UUID Flag 32 1 Per BLE Specification - Indicates a 16-bit service UUID packet follows
UUID Service 34,36 2 Per BLE Specification - Reported service UUID. On certain phones this can be used to allow filtering for Mopeka Pro ✓ packets and should be used when possible to prevent falsely identifying other BLE devices as a Mopeka Pro ✓ sensor. The least significant byte is sent first.

got chatGPT to help me but this is not workable in the mikrotik router
# Function to extract 16-bit little-endian value from hex string
:local le16ToHost do={
    :local lsb [:tonum [:pick $1 0 2]]
    :local msb [:tonum [:pick $1 2 4]]
    :return (($msb << 8) | $lsb)
}

# Function to extract 32-bit little-endian value from hex string
:local le32ToHost do={
    :local lsb [:tonum [:pick $1 0 2]]
    :local midL [:tonum [:pick $1 2 4]]
    :local midH [:tonum [:pick $1 4 6]]
    :local msb [:tonum [:pick $1 6 8]]
    :return (($msb << 24) | ($midH << 16) | ($midL << 8) | $lsb)
}

# Function to extract battery voltage from payload
:local getBatteryVoltage do={
    :local voltageRaw [:pick $1 12]
    :return (($voltageRaw & 0x7F) / 32.0)
}

# Function to extract temperature from payload
:local extractTemperature do={
    :local temperatureRaw [:tonum [:pick $1 14]]
    :return (($temperatureRaw & 0x7F) - 40)
}

# Function to extract raw tank level from payload
:local extractRawTankLevel do={
    :local tankLevelRaw [:tonum [:pick $1 16 18]]
    :return ($tankLevelRaw & 0x3FFF)
}

# Function to extract MAC address from payload
:local extractMACAddress do={
    :local macAddress [:pick $1 20 24]
    :return $macAddress
}

# Function to extract UUID service from payload
:local extractUUIDService do={
    :local uuidService [:pick $1 32 34]
    :return $uuidService
}

# Function to parse Bluetooth advertisement
:local parseBluetoothAdvertisement do={
    :local payload $1

    # Decode payload
    :local packetLength [:tonum [:pick $payload 2]]
    :local bleFlag [:tonum [:pick $payload 4]]
    :local manufacturerID [:tonum [:pick $payload 6 8]]
    :local hardwareID [:tonum [:pick $payload 10]]
    :local batteryVoltage ($getBatteryVoltage $payload)
    :local temperature ($extractTemperature $payload)
    :local rawTankLevel ($extractRawTankLevel $payload)
    :local macAddress ($extractMACAddress $payload)
    :local uuidService ($extractUUIDService $payload)

    # Print decoded values
    :put ("Packet Length: $packetLength")
    :put ("BLE Flag: $bleFlag")
    :put ("Manufacturer ID: $manufacturerID")
    :put ("Hardware ID: $hardwareID")
    :put ("Battery Voltage: $batteryVoltage V")
    :put ("Temperature: $temperature °C")
    :put ("Raw Tank Level: $rawTankLevel")
    :put ("MAC Address: $macAddress")
    :put ("UUID Service: $uuidService")
}

# Scheduler to run Bluetooth advertisement parsing script on new advertisements
:local lastAdvertisementCount 0
:local advertisementCount [/interface bluetooth-monitor get count]
:if ($advertisementCount > $lastAdvertisementCount) do={
    :local advertisementData [/interface bluetooth-monitor get 0 data]
    :if ([:typeof $advertisementData] = "string") do={
        ($parseBluetoothAdvertisement $advertisementData)
    }
    :set lastAdvertisementCount $advertisementCount
}

Who is online

Users browsing this forum: No registered users and 4 guests