Ruuvi Tag - Ready To Go

The Ruuvi Tag is distributed ready to advertise environment data packets periodically in highres (raw) mode.
The (very) faint blinking of the green LED indicates raw mode.
Be sure to enable Bluetooth in settings on the phone.
There are android apps that can display the data directly.

See the getting started video.

There are applications which issue a notification whenever a new beacon is detected.
Packets can be processed by a mobile phone with ruuviStation app or open beacon.
Another option is to establish a device, such as a raspberry pi, to receive the packets and run a progran to intrepret the data.

Blue tooth Low Energy Header for advertising packets

Reference:TI.com , Bluetooth.com Silicon labs KBA_BT_0201: Bluetooth advertising

Max length for BLE 4.0 is 31, BLE 5.0 254.

byte
offset
values
0 01
04
HCI_EVT
1 3E LE Meta PDU header

Advertisments

PDU     Name Physical Channel
type
Legacy  
5.0 extension
Scan
Initiating
                   Primary
                   secondary
L 0f ADV IND             p 
L 1f ADV DIRECT IND      p 
L 2f ADV NONCONN IND     p 
S 3f SCAN REQ            p 
S 3f AUX SCAN REQ        s 
S 4f SCAN RSP            p 
I 5f CONNECT IND         p 
I 5f AUX CONNECT REQ     s 
L 6f ADV SCAN IND        p 
5 7f ADV EXT IND         p 
5 7f AUX ADV IND         s 
S 7f AUX SCAN RSP        s 
5 7f AUX CHAIN IND       s  and Periodic
5 7f AUX SYNC IND          only Periodic
I 8f AUX_CONNECT _RSP    s 

f := ChSel+TxAdd+RxAdd
Tx:  advertiser’s   1 address is random(choosen by advertiser) 
                    0 address is public (i.e. well defined)
Rx:  target device’s     " ""
ll: length


Advertising types:
    Service UUID:
    Local Name
    one-bit flags when an advertising packet is connectable. : 
      LE Limited Discoverable Mode, LE General Discoverable Mode, 
      BR/EDR Not Supported, Simultaneous LE and BR/EDR to Same Device Capable (Controller), 
      Simultaneous LE and BR/EDR to Same Device Capable (Host).
    Manufacturer Specific Data
    TX Power
    Slave Connection Interval Range
    Service Solicitation:
    Service Data
    Appearancea ????
    Public Target Address:  
    Random Target Addres (i.e. assigned by advertiser)
    Advertising Interval    
    URL
    LE Supported Features

advertising data types, Supplement to Bluetooth Core Specification Bluetooth specs
2
2B
25
2A
1F
Packet Length. ( variable payload from 6 to 37 bytes.)
2B for fmt05
25 for fmt03
ADV_NONCONN_IND - Non connectable undirected (1F bytes )
(not ADV_IND(1F bytes ) , ADV_DIRECT_IND, 6x ADV_SCAN_IND(1F bytes )) 23 ??
2 02 subEvent: 02 LE advertising Report
3 01 numberOfReports
4
00
04
03
event type:
00 ADVERTISMENT unidir connectable
04 scan response
03 advertisment unidir Non-connectable
6 01 peerAddressType : 01: Unique Device Address
(refered to as Random, ie randomly assigned by manufacturer, a constant per device.)
7..12 zz:yy:xx:ww:vv:uu 6 byte MAC LSB first !
Highest 2 bits set indicates not standard assigned address,
i.e. will always begin with C, D, E, or F.
13 1E†
15/17/19/1F
Length max 1F (aka 31)
14..16 02 flags
15 01
16 04
17 11/15/1B Length
18 FF Manufacturer Specific
19..20 99 04 99 04 Ruuvi Mfg ID
00 59 Nordic Semiconductor
05 BF Real-World-Systems
00 C4 LG Electronics
21 03, 05, 06
08, FA
AC,AF
packet format code
08 and FA are encrypted
Vibration (ACcelerometer)

Advertisment

Legacy Advertising Packet, length: 2 bytes used by LengthField and Type max of 29 bytes for the payload.
With Mfg Specific data include IIDD leaving 27 bytes for data

Advertising data

Packet as seen by hcidump Ruuvi MfgID 99 at end of line and
next line begins with 04.
hcidump --raw |grep --after-context=2 ' 99 $'
> 04 3E 2B 02 01 00 01 DC 06 65 6D FD D0 1F 02 01 04 1B FF 99
  04 05 0F ED 30 77 C5 5D FC F0 02 98 FF D8 A5 B6 BE E3 41 D0
  FD 6D 65 06 DC 
hcidump --raw |grep -B2 '23 0E'   # MAC address begins as the last byte of 2nd line of hcidump's output
> 04 3E 2B 02 01 00 01 0E 23 6C 9C 8B D4 1F 02 01 06 1B FF 99 
  04 05 11 D9 7C 5C C0 14 FF E4 FF C8 03 E4 25 D6 11 00 28 D4 
  8B 9C 6C 23 0E A4 
bdaddress: lowest 2 bytes 
--
> 04 3E 2B 02 01 00 01 0E 23 6C 9C 8B D4 1F 02 01 06 1B FF 99 
  04 05 11 E9 7C 92 C0 14 FF E4 FF C0 03 E0 25 D6 11 00 2C D4 
  8B 9C 6C 23 0E A0 

Scan Request

Scan Response

ruuvi.drivers.c/src/tasks/ruuvi_task_advertisement.c:133

High Res formats :

   05 B3
Aka raw and RawV2

Used by:
See Tomi Tuhkanen's ruuvitag_sensor or Henrik Heikkil's ruuvi Collector .
or your own custom reader/interpreter and additional hardware for receiving .

The data is decoded from "Manufacturer Specific Data" field, undirected, non-connectable bluetooth advertisement. More details are at Argenox .

Version 2.x sensor readings transmitted at 1 second intervals.
The tag will indicate highres (raw) mode by faintly blinking the red LED

There are Bluetooth Generic Attributes (GATT) services specifications for

names are those used in Influx database as stored by RuuviCollector.


from ruuvi.endpoints.c/src/ruuvi_endpoint_5.h & _8.h
Offset
intrepreted values Description
0 05 , 08 Format type code (08 encrypted)
1 – 2 -40.000 — 84.995 Temperature (16bit signed in .005 centigrade units ie 200ths. )
Examples:
0x1388 = 5000, 5000*.005=25°C
0xFF67 = 0x10000-FF67= i.e. -153 , -153*.005 = -0.765°C
0x8E90 = 0x10000-8E90=716F(i=-29040 , -29040 *.005 = -145.20°C
0x7FFF =  32767 *.005 = 206.695 ! 0x8001 = -32767 *.005 = -206.695
-32767 aka 0x8000 Invalid / not available

Operating range -40°C(-40°F; 0xE0C0 200ths) – 85°C(185°F;0x4268 200ths)
BME280 accuracy ±1°C in the range of 0°C(32°F) – 60°C(140°F)

3 – 4 0 — 100 humidity: 16bit unsigned; in .0025%, divide by 400 to get percent.
Example 0x9470 = 38000/400 = 95%. 0x9C40 = 100% .
Invalid results from the sensor are reported as 163.83% (packet value 0xFFFF ) or 0xBB80 (i.e. 120).

Sensirion SHTC3 accuracy ±2% in the range for 20%-80%,

download BME280 datasheet( local copy) description. accuracy ±3% in the range for 20%-80%,

5 – 6 900 — 1,100 atmospheric pressure ( 16bit unsigned, offset by 50000) 65535 (0xFFFF) indicates invalid or unavailable
Example:0xC340 = 49984, 49984+50000=99984 aka 999.84hPa(aka 29.52 inHg)

DPS310 ±0.06 hPa (±0.5 m)

Considering that the weather related airpressure changes very slowly, a change of xxxx within a few seconds or even minutes can be used to determine change in height of the RuuviTag over a short time period. See barometric pressure.
Lowest non-tornadic atmospheric pressure ever measured was 870 hPa (0.858 atm; 25.69 inHg)
highest was 1083.8mb = hPa (32.00 inHg) at Agata, Siberia, Russia (alt. 262m , 862ft) corresponds to being at 600 m (2,000 ft) below sea level!

7 – 8 -10,000 — 10,000 accelerationX ( 16bit signed Most Significant Byte first)
9 – 10 -10,000 — 10,000 accelerationY STMicroelectronics LIS2DH12
11 – 12 -10,000 — 10,000 accelerationZ
Examples:03E8 = 1.000
If the tag is not changing speed, for example on a flat surface(example ship cabin shelf) or rotating pole, Z acceleration can be used to determine the orientation of the Ruuvi Tag. For example if it is flat on a table the Z component will report a value near 1.000, if inverted -1, on edge 0.
If it is on a ship Z may report a value between -.1 and +.1 indicating the amount of roll being experienced (9 degrees is a lot of roll!
A value greater than 1 or less then -1 will indicated the tag is being dropped or lifted.
See ST AppNote 4509
See movement and orientation
( values over 16000 indicates error (implementation pending 10/04/17)
13 – 14.2
(13.14.)>>5
aka (13.14.)/32
1.600 — 3.646 batteryVoltage above 1.600V, in millivolts, 11 bits unsigned (0-2046 )
2047 (FFEx or FFFx) indicates an invalid reading.
Examples:D4B6=3.3v(new); AC9x=2.98v; 9C4x=2.85v; 960x=2.800v ; 8FCx=2.750
Evaluate using:    echo 'ibase=16; print 640+(   XXX0   /20)      ,"\n"' | /usr/bin/bc
The above calculation is in base16 (aka hexadecimal): 1000 aka 0x640 and >>5 aka /0x20
14.3 – 14.7
byte 14 & x'1F'
4
-40 — +4
TX power above -40dBm, in 2dBm steps. 5 bits unsigned.
As of version 3 always -4dBm (appears as 6 in hex dump)
Nordic nRF52832 only allows -40, -20, -16,-12, -8, -4, 0, +3 and +4 Value of x'1F' indicates invalid value.(?)
15 0 — 254 Movement counter ,8bit unsigned, incremented by motion detection interrupts from LIS2DH12 Accelerometer
Highest valid value is 254, with 255 is reserved for the "Not Available".

This seems too small a field since a single movement can cause many interrupts causing this to rollover too often.DGG
After additional experience it seems that several independent movements would be detectable.
If each event causes as many as 5 interrupts, arbitrarly choosing 4 events per second will result in 100 interrupts in a 5 second interval.
If the movement(actually more like a vibration) continued ofer several intervals values would be expected to be like: 80, 160,30, 150, 245, 105, 193, 20 …
If the interval is increased to 10 seconds this is still within 254 limit. This would be observed a values like 50, 250, 245, 240,

16 – 17 0 — 65,534 measurementSequenceNumber ,16bit unsigned. 65,535 indicates not available. Each time a measurement is taken, this is incremented by one.
Used for measurement de-duplication (depending on the transmit interval, multiple packets with the same measurements can be sent, and there may be measurements that never were sent).
Takes 20 hours to rollover at 1 measurment / second
18 – 23 C0:00:00:… –
FF:FF:FF:…
NRF_FICR->DEVICEADDR
MAC= NRF_FICR->DEVICEADDR | C0 00 00 00 00 00
Always leading Cx, Dx, Ex or Fx
 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
05 12 D4 9C 40 C3 40 00 38 00 E4 03 E4 90 76 41 AD EE F7 FA 74 4A 1E 1A            B8=RSSI
f  temp  humid atmp  xxxxx yyyyy zzzzz b   t  m  -seq- ---- MAC -------- 
m                                      a   X  o
t                                      t   p  v
                                           r  # 

from ruuvi.endpoints.c/src/ruuvi_endpoint_6.h

Offset
intrepreted values Description
0 06 Format type code
1 – 2 -40.000 — 84.995 Temperature (16bit signed in .005 centigrade units ie 200ths. )
    pm1p0_ppm    Particulate matter mass concentration PM1.0 in micrograms/m3.
    pm2p5_ppm 
    pm4p0_ppm 
    pm10p0_ppm 
    co2 
    humidity_rh 
    voc_index 
    nox_index 
    temperature_c     
    measurement_count 

MAC 2:12 ONLY!


SEQCTR_MSB (11U)                //!< Index of sequence counter MSB
SEQCTR_LSB (12U)                //!< Index of sequence counter LSB
#define RE_8_RESERVED_BYTES    (4U)                 //!< Reserved encrypted space
RESERVED   (13U)                //!< Index of start of reserved space
CRC8       (17U)                //!< Index of CRC8 byte
ADDR_MSB   (18U)                //!< Start of address


Vibration format AC

Vibrations

acceleration_bcast. Lower precision for Voltage (i.e. .125 volts), temperature (i.e. .1C)

Offset
intrepreted values Description
0 AC ACceration Format type code
1 02 Version
2 – 3 -32,767— 32,767 mG X Peak to Peak Actual valid range??
4 – 5 -32,767— 32,767 mG Y
6 – 7 -32,767— 32,767 mG Z
8 – 9 -32,767— 32,767 mG X RMS
10 – 11 -32,767— 32,767 mG X RMS
12 – 13 -32,767— 32,767 mG Z RMS
14 reserved
15 reserved
16 reserved
17 reserved
18 reserved (perhaps MAC[4] for IOS )
19 reserved (perhaps MAC[5]
20 1.600 — 3.300 millivolts in eights (biased from 1600)
(mV-1600) * 8 ) >> 8
Examples:
3.300-1.600 = 1700*8 = 0x3520 => 0x35
0x35 -> 0x3500 /8 = 13568 /8 = 3.296

1.900-1.600 =  300*8    2400 =>  0x0960 => 0x09
0x09 -> 0x0900 / 8 =  288 +1600 =  1.888
21 -40.000 — 84.995 Temperature in tenth degree C
22 – 23 0 — 65,535 Message Sequence Number

Complex Vibration Data format AF

Offset
intrepreted values Description
0 AF ACceration Format type code
1 01 Version
2 00 — 02 type 0:x;1:y ;2:Z
3 8.8 Fixed-point value
23 00 — 255 Sequence number

Offset
intrepreted
values
Description
0 03, FA

Deprecated

Format type code (FA encrypted)

1 0..100 Humidity: in 0.5%, example: 0x70 is 56%. Values > 0x64 indicate error
(accuracy tolerance ±3% in the range for 20%-80%)
2 -40..85 Temperature (MSB is sign, next 7 bits are value (akward?) centigrade.
3 0..99 Temperature (fraction, 1/100.)
Values over 99 indicates error (implementation pending 10/04/17)
cannot initalize, unreadable, excessive variation from previous reading, exceeds reasonable value (see Bosch selfTest
SHTC3 Sensirion.com
4-5 500..1,100 atmospheric pressure (Most Significant Byte first, value bias 50hPa)
Values over 1,100 indicates error (implementation pending 10/04/17)
cannot initalize, unreadable, excessive variation from previous reading, exceeds reasonable value
6-7 -16000..16000 Acceleration-X (Most Significant Byte first)
8-9 -16000..16000 Acceleration-Y STMicroelectronics
10-11 -16000..16000 Acceleration-Z Examples:03E8 = 1.000
When laying flat on a table the value is expected to be 1.00
When upside down -1.000 when on edge 0.000
When riseing or falling rapidly the value will be greater than 1.000

Analysis for static RuuviTag mounted nearly vertically, of 650 points over a 6 hour period clearly show that the for a Mean= 0.038, sensor variation due to noise is 0.032 - 0.044 with a stddev=0.0045.
This shows that thousands should be ignored.

Attempts to accelerate the tag manually as quickly as possible only resulted in a maximun of 2.000 Gs ( values over 16000 indicates error (implementation pending 10/04/17)

12-13 1700 .. 3300 Battery voltage (millivolts)
Sample:
99 04  03 C8     15 61      C4 4C        01 1D   FF 3D   03 9D    0B A1 00 00 00
mfgr  fmt hum    temp       atmo press     X       Y       Z      battery
          200    21                                                 2.977
          100%     .97


04 3E 25 02 01 03 01 D5 37 52 68 33 F2 19 02 01 04 15 FF 99 04 03 2C 1A 08 C9 79 00 0B FF F5 03 EB 0A ED 00 00 00 00 CD
                     |------MAC------|                   |CIC|fmt|hum|temp|press |  x | y   |  z  |batt              ||RSSI

See discussion.

Temperature: -127.99°C to +127.9 °C (well over boiling!) in .01°C increments.
Value:Measurement; x0000:0°C ; x8145:-1.°C; x0145:1 °C
Atmospheric Pressure
50,000 Pa to 115,536Value Measurement: Pa in 1 Pa increments. (1003-1026 range found by scrin https://graphs.2kgwf.fi/dashboard/db/ruuvi-demo)

Value:Measurement; 0-50000 Pa; 41325:101325 Pa (average sea-level pressure) ; 65534:115534 Pa ; 65535 error to be implemented 50,000 Pa to 115,536Value Measurement: Pa in 1 Pa increments. (1003-1026 range found by scrin https://graphs.2kgwf.fi/dashboard/db/ruuvi-demo)

Value:Measurement; 0-50000 Pa; 41325:101325 Pa (average sea-level pressure) ; 65534:115534 Pa ; 65535 error to be implemented

Acceleration -32000 to 32000 (mG), 16 G max (2 G in default configuration).
Values are 2-complement int16_t, 3 channels X,Y,X
Value:Measurement; 0xFC18:-1000 mG ; 0x03E8:1000 mG ; 65535 error to be implemented
Battery voltage 1800 mV to 3300 mV in 1 mV increments, accuracy? ; 1000 error to be implemented
ToDo: "special" values to indicate error.

future packet layouts


Hardware B7.1 Test Points

The System On a Chip used in the ruuvi nRF52832 ARM® Cortex® M4 @64 MHz with floating point, 512KB/64KB.

This document adapted from: github.com/ruuvi/ruuvi-sensor-protocols

https://github.com/google/eddystone/blob/master/eddystone-url/docs/config-service-spec.md

Additional links for information:
ruuvi.slack
ruuvi forum

Apps for IOS

From the AppStore For example: NordicSemi

Maximu BLE packet length was revised with version4.2 to be 251

download Bluetooth.org core specs (26MB)

Regarding humidity and dew point

And then there's NFC python lib used to interact with the ruuvi.

Nearby Notification policy

services including ESP Environmental Sensing Profile, which include Humidity but those are NOT used here.

Sample LG packet

04 3E 2A 02 01 02 01 25 19 A1 7E DE 48 1E 02 01 1A 0A FF C4
00 06 34 14 12 16 FD 80 02 0A D4 03 03 B9 FE 08 1B 00 CF 26
66 53 E8 24 AB
GATT: read the logs with RuuviWebBLE using Chrome and Web Bluetooth

Documentation for depreicated URL formatsversion 09/11/23 DGG



Format type codes

00 unused as of the date of this document
01 Historical deprecated
02 Eddystone-URL, URL-safe base64 -encoded, kickstarter edition (no battery voltage)
03 unused as of the date of this document ( not highres )
04 Eddystone-URL with tag ID. , URL-safe base64 -encoded,
05 raw hi-res
FA Encrypted raw hi-res

3 High res (aka raw) format
4 unused
5 05 raw v2
6-15 06-0Freserved ?
16-239 10-F0reserved bi directional?
240-255 F0-FFcustom appliations
alternate assignments
format
code
unallocated
possible additional data bits
8-11 08 URL V2
12 0C   possible use as one format
using B[0].67 as data
13 0D  
14 0E  
15 0F  
16-28 10-1C 0001 dddd b[0].4567  
32-59 20-3C 001d dddd b[0].34567 
64-123 40-7C 01dd dddd b[0].234567 
128-251 80-FC 1ddd dddd b[0].1234567 Allocating as many as 7 bits of FIRST byte for data
Errors are indicated by "special" values: initialization failure, value xxx exceeds limit

As there are a limited number of format types available without sacrificing bits for data, a change in format type is only necessary when the format is incompatible.
For example using previously unused bits will not be reason to change the format type code. This means that if a field has a range of 0-124, is right justified in a byte and is in a field documented to be 7 bits wide do not assume that the high order bit will be zero.