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:
- sending commands to the valve and receiving the respective notification within a short time frame
- 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
and0x0C
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 XXXX
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 XXXX
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
andYY=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
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:
- the weight in Kg
- 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 |