3. Protocol Description

3.1. Eq3 Eqiva Protocol

This section tries to describe in its entirety the application protocol used by the Eq3 Eqiva radiator valves discussed in the Introduction. It provides information on the BLE characteristics used, on the composition of commands and notifications, and shows the Extended BNF.

The protocol exploits two methods of communication:

  1. sending commands to the valve and receiving the respective notification within a short time frame
  2. receiving asynchronous notifications

All values exchanged contain the information necessary for their interpretation, therefore it can be considered a stateless protocol.

A detailed description will be provided below.

3.1.1. BLE Service And Characteristics

The protocol is based on two characteristics, one for the commands and one for the notifications. Both are part of the same service, identified by the UUID 3e135142-654f-9090-134a-a6ff5bb77046.

“Send command” characteristic

  • Property: read/write
  • UUID: 3fa4585a-ce4a-3bad-db4b-b8df8179ea09
  • Handle: 0x0411

“Notification” characteristic

  • Property: read/write/notify
  • UUID: d0e8434d-cd29-0996-af41-6c90f4e0eb2a
  • Handle: 0x0421

Client Characteristic Configuration Descriptor (CCID)

In general, the CCID, is an optional characteristic descriptor that defines how the characteristic may be configured by a specific client (recall: the client is the central device). Each client has its own instantiation of the Client Characteristic Configuration . Reads of the Client Characteristic Configuration only shows the configuration for that client and writes only affect the configuration of that client. The characteristic descriptor value is a bit field. When a bit is set, that action shall be enabled, otherwise it will not be used. [1]

In our case, the descriptor exists and has UUID 00002902-0000-1000-8000-00805f9b34fb. Even if it’s not used in this work, its role is fundamental in other contexts, including the development of applications for mobile devices. It allows to activate the reception of notifications by setting a bit value to 1 through a write operation.

Note

All the identification codes are made up of 128 bit. This shows that these are services and characteristics not provided by the Bluetooth LE specification but made by the manufacturer.

3.1.2. Extended Backus-Naur Form

The Backus-Naur Form is a formalism frequently used in the description of the syntax and grammar of protocols and languages. The “Extended”[2] version will be used below. It is designed for a clearer and more compact representation and is now universally recognized.

Remember that:

  • the symbol | indicates possible alternatives
  • the symbol * indicates the number of repetitions
  • [ ] identify optional symbols

Protocol Description

protocol = command | notification;

Command Description

command =
    set-date-time | set-temp | set-comfort | set-reduced | modify-comf-reduced
    | boost | auto | manual | holiday | lock | create-profile | read-profile
    | window-mode | set-offset;

set-date-time =03’, year, month, day, hour, minutes, seconds;

set-temp =41’, temperature;

set-comfort =43;

set-reduced =44;

modify-comf-reduced =11’, temperature, temperature;

boost =45’, (on | off);

auto =4000;

manual =4040;

holiday =40’, temperature-128, day, year, hour-and-minutes, month;

lock =80’, (on | off);

create-profile =10’, day-of-week, interval, 6*[interval];

read-profile =20’, day-of-week;

window-mode =14’, temperature, window-minutes;

set-offset =13’, offset-range;

Notification Description

notification = status-notification | profile-notification;

status-notification =02’, ’01’, valve-state, [holiday-parameters];

profile-notification = success-modify, profile-read;

valve-state = mode, byte, ’04’, temperature;

holiday-parameters = day, year, hour-and-minutes, month;

success-modify =0202’, day-of-week;

profile-read =21’, day-of-week, 7*interval;

Generic Types

on =01;

off =00;

year = (0’ | ’1’ | ’2’ | ’3’ | ’4’ | ’5’ | ’6), hexdigit;

month =0’, (0’ | ’1’ | ’2’ | ’3’ | ’4’ | ’5’ | ’6’ | ’7’ | ’8’ | ’9’ | ’A’ |
    ’B’ | ’C’);

day = (0’ | ’1), hexdigit;

hour = (0’ | ’1), hexdigit;

minutes = (0’ | ’1’ | ’2’ | ’3), hexdigit;

seconds = (0’ | ’1’ | ’2’ | ’3), hexdigit;

temperature-128 = (8’ | ’9’ | ’A’ | ’B’ | ’C’ | ’D’ | ’E’ | ’F’), hexdigit;

temperature = byte;

hour-and-minutes = byte;

day-of-week =0’, (0’ | ’1’ | ’2’ | ’3’ | ’4’ | ’5’ | ’6);

interval = temperature, byte;

window-minutes =0’, (0’ | ’1’ | ’2’ | ’3’ | ’4’ | ’5’ | ’6’ | ’7’ | ’8’ | ’9’ | ’A’ |
    ’B’ | ’C’);

mode = (0’ | ’2), (8’ | ’9’ | ’A’ | ’C’ | ’D’ | ’E’)

offset-range =0’, (0’ | ’1’ | ’2’ | ’3’ | ’4’ | ’5’ | ’6’ | ’7’ | ’8’ | ’9’ | ’A’ |
    ’B’ | ’C’ | ’D’ | ’E’)

byte = hexdigit, hexdigit

hexdigit =0’ | ’1’ | ’2’ | ’3’ | ’4’ | ’5’ | ’6’ | ’7’ | ’8’ | ’9’ | ’A’ | ’B’ |
    ’C’ | ’D’ | ’E’ | ’F’

3.1.3. Commands

Commands must be sent to the valve using the hexadecimal system, so the values shown below have already been converted. Alphabetic characters can be indifferently used in uppercase or lowercase.

Note that the valve, and consequently also the CalorBT application, is capable of handling only temperatures whose decimal part is rounded to .0 or .5.

3.1.3.1. Set Current Date And Time

Tells the valve the current date and time. In general it is used to synchronize with the device. The notification returned as a result of its execution makes it possible to obtain information about the state.

The command consists of 7 bytes:

byte 0: 03
byte 1: year % 100
byte 2: month
byte 3: day
byte 4: hour
byte 5: minutes
byte 6: seconds

Notes

  • the % symbol represents the modulo operation
  • months and days are calculated starting from 1. As a result, both the month of January and the first day of each month will be identified by the value 0x01

Example

The date and time 25/05/2016 11:27:28 become 03 10 05 19 0B 1B 1C. At the same way 29/08/2016 09:55:20 becomes 03 10 08 1D 09 37 14.

3.1.3.2. Select Temperature (manual)

Activates the selected temperature.

The command consists of 2 bytes:

byte 0: 41
byte 1: temperature * 2

Example

Setting the temperature to 18°C is done with command 4124. This is because 18*2 = 36 = 0x24. In the same way, to set the valve at 20.5°C it is necessary to send 4129.

3.1.3.3. Select Comfort Temperature

Activates the comfort temperature. To modify its default value use this command.

The command consists of 1 byte:

byte 0: 43

3.1.3.4. Select Reduced Temperature

Activates the reduced temperature. To modify its default value use this command.

The command consists of 1 byte:

byte 0: 44

3.1.3.5. Set Comfort And Reduced Temperature

Changes the default comfort and reduced temperature values within the valve settings.

The command consists of 3 byte:

byte 0: 11
byte 1: new_comfort_temperature * 2
byte 2: new_reduced_temperature * 2

Example

To set the default values for comfort and reduced temperatures to 23°C and 18.5°C respectively, the command 112E25 must be sent to the valve. This is because 23 * 2 = 46 = 0x2E while 18.5 * 2 = 37 = 0x25

3.1.3.6. Start/Stop Boost Mode

Starts or stops the boost mode on the valve.

The command consists of 2 byte:

byte 0: 45
byte 1: 01 on // 00 off

3.1.3.7. Select Auto Mode

Activates the automatic mode on the valve. The temperature will reflect the one selected through the weekly schedule.

The command consists of 2 byte:

byte 0: 40
byte 1: 00

3.1.3.8. Select Manual Mode

Activates the manual mode on the valve. The temperature must be selected using the command already shown.

The command consists of 2 byte:

byte 0: 40
byte 1: 40

3.1.3.9. Select Holiday Mode

Activates the holiday mode on the valve. To be activated, it requires: the temperature to be kept and the end date and time.

The command consists of 6 byte:

byte 0: 40
byte 1: (temperature * 2) + 128
byte 2: day
byte 3: year % 100
byte 4: (hour*2) + (minutes/30)
byte 5: month

Notes

  • the % symbol represents the modulo operation
  • months and days are calculated starting from 1. As a result, both the month of January and the first day of each month will be identified by the value 0x01
  • minutes can only be programmed in half-hour intervals (i.e. XX:00 or XX:30), so the value of minutes/30 will always be equivalent to 0 or 1.

Example

To maintain the temperature at 17.5°C up to 8.00pm on 10/09/2017 the command is 40 A3 0A 11 28 09. The byte 0xA3 is derived from the computation of (17.5 * 2) + 128 = 163 = 0xA3, while byte 0x28 was calculated through the selected time as (20 * 2) + (00/30) = 40 + 0 = 0x28.

3.1.3.10. Enable/Disable Command Block

It allows to lock the physical buttons on the valve. Note that it allows however to manage the valve through the application.

The command consists of 2 byte:

byte 0: 80
byte 1: 01 on // 00 off

3.1.3.11. Set Temperature Offset

Allows to set a temperature offset in a range between -3.5°C and +3.5°C.

The command consists of 2 byte:

byte 0: 13
byte 1: (temperature * 2) + 7

3.1.3.12. Change Window Mode Settings

Allows to set the duration and the temperature to keep when the window mode takes over. The window mode is activated automatically when the valve detects a significant temperature drop.

The command consists of 3 byte:

byte 0: 14
byte 1: (temperature * 2)
byte 2: (minutes / 5)

Notes

  • minutes can only assume values that are multiples of 5, so the final content of byte 2 will be between 0x00 and 0x0C

Example

To change the window mode settings to 12°C for the duration of 15 minutes it is necessary to send the command 14 18 03. Indeed 12*2 = 24 = 0x18 and 15/5 = 3 = 0x03.

3.1.3.13. Daily Profile Request

It requires data relating to the schedule of a given day. The information is received as a notification.

The command consists of 2 byte:

byte 0: 20
byte 1: day of the week

Notes

  • the days of the week are counted starting from Saturday (00 is Saturday, .., 06 is Friday)

3.1.3.14. Set Daily Profile

Set the schedule for a given day of the week. It is necessary to choose a base temperature and it is possible to modify it for at most three time intervals. If a profile is already present for the chosen day, it will be replaced.

The command consists of at most 16 byte:

byte 0: 10
byte 1: day of the week
[byte 2-15]: a sequence of at most seven pairs of bytes

In each pair (XX,YY):

  • YY is the time, coded as (minutes/10), up to which to maintain the temperature declared in XX
  • XX represents the temperature to be maintained until then, codified as (temperature*2)

Notes

  • the entire sequence of bytes [2-15] must allow to deduct the temperature to be maintained at any moment of the day
  • any unnecessary (because in excess) pairs of bytes can be kept at zero or omitted
  • the number of minutes in (minutes/10) is calculated from the beginning of the day (00:00)
  • the days of the week are counted starting from Saturday (00 is Saturday, .., 06 is Friday)

Example

We want to program the valve so that every Tuesday maintains a base temperature of 17°C and automatically sets itself at:

  • 20°C in the range 10:00-12:30
  • 19°C in the range 12:30-14:00
  • 20°C in the range 15:00-17:00

The command to be sent is 10 03 22 3C 28 4B 26 54 22 5A 28 66 22 90 00 00, built in the following way:

byte 0: 10 (default value)
byte 1: 03 (tuesday = 0x03)
byte (2,3): 22 3C (17°C base temperature up to 10:00)
byte (4,5): 28 4B (20°C up to 12:30)
byte (6,7): 26 54 (19°C up to 14:00)
byte (8,9): 22 5A (17°C up to 15:00)
byte (10,11): 28 66 (20°C up to 17:00)
byte (12,13): 22 90 (17°C base temperature up to 24:00)
byte (14,15): 00 00 (unnecessary, can be omitted)

3.1.4. Notifications

As already discussed, notifications are sent from the radiator valve to the central device in order to report to the user the status of the device or the outcome of an operation.

Also in this case the values are already converted into the hexadecimal numerical system.

3.1.4.1. Status Notif. (auto/manual mode)

They occur after the execution of any command if the valve is in automatic or manual mode. Note that another type of notification is received after the read profile or write profile command.

The notification consists of 6 byte:

byte 0: 02
byte 1: 01
byte 2: XY (see below)
byte 3: valve open state in % (from 0x00 to 0x64)
byte 4: undefined (battery level?)
byte 5: (temperature * 2)

In the second byte:

  • X indicates if the physical key block is active:

    X=0 keypad unlocked
    X=1 locked due to open window detection
    X=2 locked due to manual lock enabled
    X=3 locked due to open window detection && manual lock enabled
    
  • Y indicates the active mode on the valve:

    Y=8 auto mode
    Y=9 manual mode
    Y=A holiday mode
    Y=C boost mode. at the end it returns to automatic mode
    Y=D boost mode. at the end it returns to manual mode
    Y=E boost mode. at the end it returns to holiday mode
    

Example

If the valve is in automatic mode, set to 20°C without physical buttons locked, by executing the “Activate boost mode” command, the notification 02 01 0C XX XX 28 is received. The byte 0x0C supplies the information related to the unlock status and the mode in use, while the last byte 0x28 corresponds to twice the set temperature.

According to the same logic, by setting the valve in manual mode, with the physical buttons locked and setting the temperature to 21.5°C, the notification takes the value 02 01 29 XX XX 2B.

3.1.4.2. Status Notif. (holiday mode)

They occur after the execution of any command if:

  • the valve is in holiday mode
  • the valve is in boost mode and at its end it will return to holiday mode

Note that another type of notification is received after the read profile or write profile command.

The notification consists of 10 byte:

byte (0-5): same as in previous section (3.4.1)
byte 6: end_holiday_day
byte 7: end_holiday_year%100
byte 8: (end_hour*2) + (end_minutes/30)
byte 9: end_holiday_month

Notes

  • minutes can only be programmed in half-hour intervals (i.e. XX:00 or XX:30), so the value of end_minutes/30 will always be equivalent to 0 or 1.

Example

By activating the holiday mode with the physical buttons locked, temperature at 20°C and the end date set to 18:30 on 14/12/2016, the valve provides the following notification: 02 01 2A XX XX 24 0E 10 25 0C.

The first six bytes are consistent with what was stated in the previous section: 0x2A declares that the holiday mode is active. Of the remaining four bytes, 0x0E, 0x10 and 0x0C indicate the day, year, and month respectively. Finally, the 0x25 encodes the time “18:30” according to the method described: (18*2) + (30/30) = 36 + 1 = 37 = 0x25.

3.1.4.3. Profile Notif. (modify)

They appear after the Set Daily Profile command has been sent. They confirm the execution.

The notification consists of 3 byte:

byte 0: 02
byte 1: 02
byte 2: modified_day

Notes

  • the days of the week are counted starting from Saturday (00 is Saturday, .., 06 is Friday)

3.1.4.4. Profile Notif. (request)

They appear after the Daily Profile Request command has been sent. They provide all the information necessary to identify temperatures and time ranges for the selected day.

The notification consists of 16 byte:

byte 0: 21
byte 1: day_of_the_week
(byte 2-15): a sequence of seven pairs of bytes (see below)

In each pair (XX,YY):

  • YY is the time, coded as (minutes/10), up to which to maintain the temperature declared in XX
  • XX represents the temperature to be maintained until then, codified as (temperature*2)

Notes

  • the entire sequence of bytes (2-15) allows to deduct the temperature to be maintained at any moment of the day
  • any unnecessary (because in excess) pairs of bytes will have the value XX=base_temperature and YY=0x90
  • the days of the week are counted starting from Saturday (00 is Saturday, .., 06 is Friday)

Example

We program the valve so that every Monday maintains a base temperature of 17°C and automatically sets itself at:

  • 21°C in the range 06:00-06:00
  • 21°C in the range 17:00-23:00

We request the profile and we get the notification: 21 02 22 24 2A 36 22 66 2A 8A 22 90 22 90 22 90, built as follows:

byte 0: 21 (default value)
byte 1: 02 (Monday = 0x02)
byte (2,3): 22 24 (17°C up to 06:00)
byte (4,5): 2A 36 (21°C up to 09:00)
byte (6,7): 22 66 (17°C up to 17:00)
byte (8,9): 2A 8A (21°C up to 23:00)
byte (10,11): 22 90 (17°C up to 24:00)
byte (12,13): 22 90 (unused)
byte (14,15): 22 90 (unused)
[1]Bluetooth Core Specification 5.0, Volume 3, Part G, Section 3.3.3.3
[2]ISO/IEC. Extended Backus–Naur Form, 1996

3.2. Laica PS7200L Protocol

The PS7200L is a BLE scale produced by the italian company Laica. In addition to measuring weight, it allows the calculation of:

  • fat percentage
  • water percentage
  • skeletal muscle mass percentage
  • skeletal system weight
  • base metabolism
  • body mass index

Laica PS7200L

Laica PS7200L BLE Scale

To use all the features of the scale, the company provides an application, called laicabodytouch, for Android and iOS devices. The application receives the data from the scale, keeps track of it and shows it to the user through simple graphs.

It is interesting to observe the permissions required by the application to perform such a “simple” task. Some of them are quite ambiguous and are not essential to use Bluetooth [4]. For example, some required permissions are:

  • retrieve running apps
  • find/add/remove accounts on the device
  • read phone status and identity
  • view Wi-Fi connections

Note

At present, the PS7200L protocol has been reverse-engineered only in a small part. However, it has been included in this guide because it shows aspects that have not been dealt within other sections.

3.2.1. BLE Communication

After analyzing the log files using the methods described in the Logging Via Android section, it becomes clear that the application does not send commands to the scale.

The operation principle is based on the fact that when a person is on the scale, this starts broadcasting advertising packages. These packages contain all the information about the device and the person using it. For this reason, there is not even a pairing procedure between the central device and the BLE device.

Through the advertising packages, the scale provides the application two essential information:

  1. the weight in Kg
  2. a value used to derive all the other parameters (such as fat%, water%, etc..)

Note

To achieve the goal of point 2 (derive all the parameters), the application also uses three manually entered data: gender, age and height.

3.2.2. Advertising Packets Content

The structure of an advertising package is clearly described in the Bluetooth specifications [3]. In addition to a field that indicates the MAC address of the device who sent the package, there is an Advertising Data field that basically represents the payload.

Referring to the way Wireshark presents the packages (see Wireshark log of Advertisement packets), the data that compose the communication protocol between the two devices are the 12 Byte under Advertising Data > Manufacturer Specific > Data. Their meaning is as follows:

..
byte (2,3): weight*10 (in Kg)
byte (4,5): used to derive other parameters (fat%, water%, etc..)
..

At the moment it is not clear how the value of the bytes (4,5) can lead to the calculation of all the other data. Even decompiling the Android application the analysis is blocked by the fact that these two bytes are used as input to a function called getHealth() in the proprietary library libyohealth.so.

We decompiled the library using objdump (with an ARM toolchain) and the RetDec decompiler, which provides output in C language. However, for obvious reasons, the results are not easily readable. The outputs obtained from the decompilation process are available here.


[3]Bluetooth Core Specification 5.0, Volume 2, Part E, Page 1193
[4]Android Bluetooth Permissions