BLE GATT Interface¶

Context¶

In A naĂŻve attempt at decoding the pHin BLE GAP Interface, we saw that the pHin uses two types of advertisements:

  1. During an initial period of 90s, it announces itself as “connectable”

  2. After the 90s period, it shifts to “scannable” (i.e. not connectable)

With the unit I was working with, the pHin with the black probe and soft potting, it was not possible to connect. I didn’t take the time to understand the reason for this, assuming that the developers had protected the connection and also because I was confident that all the read-only data I wanted to extract from the probe would be contained in the advertisements.

I’m re-opening this topic now (2 weeks later), because I read that the newly-released pHinished app was capable of setting the pHin monitor in winter mode, and back to normal mode. This implies a transmission of information from the application to the pHin monitor, which can only be achieved by entering the connected mode. This idea is reinforced by the fact that the wintering operation requires the user to use the magnet: it must be connection-related, since trigerring a hardware reset of the microcontroller is the only way to make it return to the 90s connectable period. Since the whole point of this reverse-engineering was to allow people to continue using their pHin monitors as long as possible and since the power consumption is probably much lower in winter mode, I can’t say the reverse is complete until I document how to set the device in winter mode.

Now that I have found a good excuse to re-open this project, here is the current situation:

  • I’m unable to connect to my pHin monitor for whatever reason

  • The pHinished app presumably uses a BLE connection to put the device in winter mode. I’m assuming that the pHinished application was developed without any proprietary information from Hayward, so it should be possible to establish a connection to a pHin without any secret information (or, secret information that is reasonably easy to reverse-engineer)

  • I installed the pHinished application and it turns out that it’s unable to interact with my pHin monitor. Could I be in possession of an older version of pHin which doesn’t support connections? Or did I somehow break something while reverse-engineering the other parts? Is there a specific requirement on the RF part that is specific to the BLE Connected mode which I might have damaged?

  • Remembering that I still have a second pHin monitor as backup, I decided to start by verifying if connections are possible on that one.

Establishing a BLE Connection on the “blue probe” pHin¶

Replacing the battery on this second pHin was a lot more difficult as the potting material is extremely hard. I managed to hook up a power supply on the battery contacts, but I will definately not attempt to access any other parts of the PCB:

Powering this over a 3V regulated power supply brings up the device immediately in a BLE Scanner, and I was relieved to see that with this one, it’s possible to connect over BLE.

In CySmart, while establishing a BLE Connection, I get the following trace:

[11:34:09:220] : 'Resolve and Set Peer Device BD Address' request sent
[11:34:09:220] :    BD Address Type: RANDOM_ADDRESS
[11:34:09:220] :    BD Address: E7:B8:BE:71:B0:C7:00:00
[11:34:09:222] : 'Command Status' event received
[11:34:09:222] :    Status: BLE_STATUS_OK
[11:34:09:222] : 'Resolve and Set Peer Device BD Address Response' event received
[11:34:09:222] :    Status: 0x01
[11:34:09:223] : 'Command Complete' event received
[11:34:09:223] :    Status: BLE_STATUS_OK
[11:34:09:227] : 'Establish Connection' request sent
[11:34:09:227] :    BD Address Type: RANDOM_ADDRESS
[11:34:09:227] :    BD Address: E7:B8:BE:71:B0:C7:00:00
[11:34:09:230] : 'Command Status' event received
[11:34:09:230] :    Status: BLE_STATUS_OK
[11:34:09:250] : 'Establish Connection Response' event received
[11:34:09:864] : 'Enhanced connection complete' event received
[11:34:09:864] :    Status: 0x00
[11:34:09:864] :    Role: 0x00
[11:34:09:864] :    BD Address Type: RANDOM_ADDRESS
[11:34:09:864] :    BD Address: E7:B8:BE:71:B0:C7:00:00
[11:34:09:864] :    Local resolvable address: 00:00:00:00:00:00:00:00
[11:34:09:864] :    Peer resolvable address: 00:00:00:00:00:00:00:00
[11:34:09:864] :    Connection Interval: 8.75 ms
[11:34:09:864] :    Slave Latency: 0
[11:34:09:864] :    Supervision Timeout: 100 ms
[11:34:09:868] : 'Command Complete' event received
[11:34:09:868] :    Status: BLE_STATUS_OK

The trace continues below, but I’m stopping here to note that up until this point, the trace is identical to what I had with the other pHin. At this point, the connection attempt to the other pHin model is terminated (and yet there are still common parts with the trace that follows):

  // Trace from the other pHin model, which fails to connect
  [13:24:24:794] : 'Connection Terminated Notification' event received
  [13:24:24:794] :  Reason: CONNECTION_FAILED_TO_BE_ESTABLISHED

I might come back to the previous model and attempt to understand what causes this disconnection, but for now I will continue working on the pHin that I can connect to without issues. Here is the remainder of the trace of the working pHin monitor::

  [11:34:09:868] : 'Get local device security keys' request sent
  [11:34:09:872] : 'Data length changed notification' event received
  [11:34:09:872] :    Connection maximum Tx octet: 27
  [11:34:09:872] :    Connection maximum Tx time: 328 µs
  [11:34:09:872] :    Connection maximum Rx octet: 27
  [11:34:09:872] :    Connection maximum Rx time: 328 µs
  [11:34:09:885] : 'Command Status' event received
  [11:34:09:885] :    Status: BLE_STATUS_OK

Here are some keys generated at the establishment of the connection. It seems that the connection uses “Just Works”, without authentification, since we didn’t need to provide any keys:

[11:34:09:885] : 'Get local device security keys response' event received
[11:34:09:885] :    Key flags: INITIATOR_ENCRYPTION_INFORMATION, INITIATOR_IDENTITY_INFORMATION, INITIATOR_SIGNATURE_KEY, RESPONDER_ENCRYPTION_INFORMATION, RESPONDER_IDENTITY_INFORMATION, RESPONDER_SIGNATURE_KEY
[11:34:09:885] :    Long Term Key (LTK): [D6:93:E8:A4:23:55:48:99:1D:77:61:E6:63:2B:10:8E]
[11:34:09:885] :    Encrypted Diversifier (EDIV) and Random Number: [99:1F:26:1E:F6:09:97:2E:AD:7E]
[11:34:09:885] :    Identity Resolving Key (IRK): [0A:2D:F4:65:E3:BD:7B:49:1E:B4:C0:95:95:13:46:73]
[11:34:09:885] :    Identification Address: [0x00A050504320, PUBLIC_ADDRESS]
[11:34:09:885] :    Connection Signature Resolving Key (CSRK): [90:D5:06:95:92:ED:91:D7:A8:9E:2C:DC:4A:93:5B:F9]
[11:34:09:886] : 'Command Complete' event received
[11:34:09:886] :    Status: BLE_STATUS_OK
[11:34:09:892] : 'Set OOB data' request sent
[11:34:09:892] :    OOB flag: Disable
[11:34:09:892] :    OOB Key: [00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00]
[11:34:09:892] :    OOB Data: [00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00]
[11:34:09:895] : 'Command Status' event received
[11:34:09:895] :    Status: BLE_STATUS_OK
[11:34:09:896] : 'Command Complete' event received
[11:34:09:896] :    Status: BLE_STATUS_OK

Here, MTU is requested and the default value of 0x17 (23) is returned:

[11:34:09:906] : 'Exchange GATT MTU Size' request sent
[11:34:09:906] :    MTU: 0x0200
[11:34:09:910] : 'Command Status' event received
[11:34:09:910] :    Status: BLE_STATUS_OK
[11:34:09:920] : 'Exchange GATT MTU Size Response' event received
[11:34:09:920] :    MTU: 0x0017
[11:34:09:920] : 'Command Complete' event received
[11:34:09:920] :    Status: BLE_STATUS_OK

Finally, the BLE Central reads characteristic UUID 0x2A00, which is the standard 16-bit UUID for the “Device Name”. The value returned is the hex representation of the ASCII characters “pHin71BE”, our pHin’s device name:

[11:34:09:933] : 'Read using Characteristic UUID' request sent
[11:34:09:933] :    Start Handle: 0x0001
[11:34:09:933] :    End Handle: 0xFFFF
[11:34:09:933] :    UUID: 0x2A00
[11:34:09:938] : 'Command Status' event received
[11:34:09:938] :    Status: BLE_STATUS_OK
[11:34:09:969] : 'Read using Characteristic UUID Response' event received
[11:34:09:969] :    Characteristic value 1:
[11:34:09:969] :    --------------------------------
[11:34:09:969] :    Attribute Handle: 0x0003
[11:34:09:969] :    Value: [70:48:69:6E:37:31:42:45]
[11:34:09:972] : 'Command Complete' event received
[11:34:09:972] :    Status: BLE_STATUS_OK

Exactly 2 minutes after the connection is established, the pHin monitor terminates the connection:

[11:36:08:655] : 'Connection Terminated Notification' event received
[11:36:08:655] :    Reason: REMOTE_USER_TERMINATED_CONNECTION

Making the peripheral force a disconnection after a certain delay is good practice:

  • It saves energy, as maintaining this BLE Connection could be more energy demanding than sending periodic Advertisements (this depends on the GATT connection parameters, which we will be able to analyse a bit later).

  • It ensures that the device is freed from the connection, allowing it to send periodic BLE Advertisements. This prevents any BLE Central (malicious or not) to monopolize the pHin monitor.

BLE Connection Parameters¶

Now that we are able to establish a connection, let’s look at the connection parameters. With CySmart, we notice the following connection parameters are established:

Parameter

Value

Connection Interval

8.75 ms

Connection Latency

0

Supervision Timeout

100 ms

This is the first time I actually use CySmart to look at the connection parameters. I assume that by “Connection Latency”, they mean “Slave Latency”. If these settings are the actual settings used, we can see that there has not been any attempt to save power during the BLE connection. Also, I note that we attempting to connect to the pHin monitor, I didn’t receive any request from the pHin to update the connection parameters. The pHin did not attempt to request parameters which are different from the default ones and which could result in a huge power saving. This might have been seen as unnecessary by the developers, since the connection is closed after 120 seconds, and a connection is very rarely used during the life of the product.

Let’s use our sniffer connected wireshark to confirm this. Here is a capture starting from the last BLE Advertisement sent by the pHin just before the connection, up until the connection is established and a few connection PDUs are exchanged:

We can see that the pairs of Master –> Slave and Slave –> Master packets are exchanged at roughly 8-10ms intervals.

To confirm that these are indeed connection parameters selected by the initiator, we modified the default connection parameters in the CySmart settings and estblished a new connection with the pHin monitor.

I selected:

  • Connection Interval Minimum value: 20ms (was 7.5ms)

  • Connection Interval Maximum value: 40ms (was 10ms)

  • Supervision Timeout: 500ms (was 100ms)

After establishing a connection, the actual parameters used followed the requested parameters:

Parameter

Value

Connection Interval

30 ms

Connection Latency

0

Supervision Timeout

500 ms

A wireshark capture confirms that the pHin monitor accepted these new parameters. We can see the exchanges are less frequent, at time intervals oscillating around 30ms:

../_images/wireshark-connection-settings-30ms.png

To conclude:

  • The pHin does not impose strict connection parameters

  • The pHin does not exploit any slave latency, which would allow it to omit a certain number of consecutive connection intervals, thus reducing power

There has been no effort at optimising power during the connection, but it makes sense: there is no need to optimize a mode which is seldom used.

BLE Services and Characteristics¶

Once connected, we discover the following services and characteristics. These are listed in the order in which they appear in the GATT Attribute Table.

To understand how an Attribute Table is constructed, it can be useful to read a simplified version of the BLE standard such as explained by certain manufacturers. NordicSemi’s documentation is a good starting point.

Generic Access Service (0x1800)¶

This is a standard BLE service, mandatory for all GATT servers. There are 2 mandatory characteristics in this profile:

  • Device Name = “pHin71BE”

  • Appearance = 0x0000 = “Unknown”

We see also a third, optional characteristic:

  • Peripheral Preferred Connection Parameters: 40:01:08:02:00:00:90:01.

So it looks like the device does have some preferred connection parameters. Let’s try to decode them according to the official BLE specifications. This is an 8-byte field formatted as follows:

  • Minimum connection interval (2 bytes, little-endian, multiple of 1.25ms): 0x0140 * 1.25ms = 320 * 1.25ms = 400ms.

  • Maximum connection interval (2 bytes, little-endian, multiple of 1.25ms): 0x0208 * 1.25ms = 520 * 1.25ms = 650ms.

  • Slave latency (2 bytes) = 0x0000

  • Connection Supervision Timeout (2 bytes, little-endian, multiple of 10ms): 0x0190 * 10ms = 400 * 10ms = 4s.

So it appears that the peripheral does have preferred connection parameters, but these are not used when we connect using CySmart.

Handle

UUID

UUID Description

Value

Properties

0x0001

0x2800

Primary Service Declaration

00:18

0x00

0x0002

0x2803

Characteristic Declaration

02:03:00:00:2A

0x00

0x0003

0x2A00

Device Name

“pHin71BE”

0x02

0x0004

0x2803

Characteristic Declaration

02:05:00:01:2A

0x00

0x0005

0x2A01

Appearance

00:00

0x02

0x0006

0x2803

Characteristic Declaration

02:07:00:04:2A

0x00

0x0007

0x2A04

Peripheral Preferred Connection Parameters

40:01:08:02:00:00:90:01

0x02

Generic Attribute Service (0x1801)¶

This service provides a characteristic which allows the GATT Server (the pHin) to announce when the attribute table has changed during a connection. I doubt that this is actually used by the pHin.

Handle

UUID

UUID Description

Value

Properties

0x0008

0x2800

Primary Service Declaration

01:18

0x00

0x0009

0x2803

Characteristic Declaration

20:0A:00:05:2A

0x00

0x000A

0x2A05

Service Changed

0x20

0x000B

0x2902

Client Characteristic Configuration

0x00

Connected Yard, Inc. Service (0xFE63)¶

This service uses a registered 16-bit UUID of 0xFE63 dedicated to Connected Yard, Inc. This is where the custom pHin characteristics lie, and this is where we need to look for the characteristic to send commands to the pHin.

There are several 128-bit UUID characteristics, all sharing a common format:

3206XXXX-76FD-4996-952B-2A1BE2CB9450

All characteristics share the same format except for the 16-bit XXXX section, which is different for each characteristic. In the table below, the characteristic UUIDs are given by their variable 16-bit part, but it is implicit that they are surrounded by the other fixed 112 bits.

Handle

UUID

UUID Description

Value

Properties

0x000C

0x2800

Primary Service Declaration

63:FE

0x00

0x000D

0x2803

Characteristic Declaration

0A:0E:…:27:15:06:32

0x00

0x000E

0x1527

0x0A

0x000F

0x2901

Characteristic User Description

0x00

0x0010

0x2803

Characteristic Declaration

08:11:…:2C:15:06:32

0x00

0x0011

0x152C

0x08

0x0012

0x2901

Characteristic User Description

0x00

0x0013

0x2803

Characteristic Declaration

08:14:…:2D:15:06:32

0x00

0x0014

0x152D

0x08

0x0015

0x2901

Characteristic User Description

0x00

0x0016

0x2803

Characteristic Declaration

12:17:…:2E:15:06:32

0x00

0x0017

0x152E

0x12

0x0018

0x2901

Characteristic User Description

0x00

0x0019

0x2902

Client Characteristic Configuration

0x00

0x001A

0x2803

Characteristic Declaration

02:1B:…:30:15:06:32

0x00

0x001B

0x1530

0x02

0x001C

0x2901

Characteristic User Description

0x00

0x001D

0x2803

Characteristic Declaration

02:1E:…:31:15:06:32

0x00

0x001E

0x1531

0x02

0x001F

0x2901

Characteristic User Description

0x00

0x0020

0x2803

Characteristic Declaration

02:21:…:32:15:06:32

0x00

0x0021

0x1532

0x02

0x0022

0x2901

Characteristic User Description

0x00

Let’s look at the characteristics in more detail in the following subsections.

Characteristic 0x1527¶

  • Access Modes: Read, Write

  • Initial Value: 00:00:00:00:00:00:00:00

Characteristic 0x152C¶

  • Access Modes: Write

Characteristic 0x152D¶

  • Access Modes: Write

Characteristic 0x152E¶

  • Access Modes: Read, Notify

  • Initial Value: FB:02:21:00:00:FB:FE:10

Activating notifications on this characteristic does not yield any unsollicited notifications. It’s possible that notifications are sent here as a response to another kind of interaction.

Characteristic 0x1530¶

  • Access Modes: Read

  • Initial Value: 04:00:00:00:42:00:00:00:02:00:00:00:00:00:00:00:00:00:00:00:00:00

Characteristic 0x1531¶

  • Access Modes: Read

  • Initial Value: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00

Characteristic 0x1532¶

  • Access Modes: Read

  • Initial Value: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00

Device Information Service (0x180A)¶

This contains read-only information about the device.

Handle

UUID

UUID Description

Value

Properties

0x0023

0x2800

Primary Service Declaration

0A:18

0x00

0x0024

0x2803

Characteristic Declaration

02:25:00:29:2A

0x00

0x0025

0x2A29

Manufacturer Name String

“Connected Yard Inc.”

0x02

0x0026

0x2803

Characteristic Declaration

02:27:00:24:2A

0x00

0x0027

0x2A24

Model Number String

“CY-PM1510-A1”

0x02

0x0028

0x2803

Characteristic Declaration

02:29:00:25:2A

0x00

0x0029

0x2A25

Serial Number String

“71BEB8E7CF9F87B0”

0x02

0x002A

0x2803

Characteristic Declaration

02:2B:00:27:2A

0x00

0x002B

0x2A27

Hardware Revision String

“3”

0x02

0x002C

0x2803

Characteristic Declaration

02:2D:00:26:2A

0x00

0x002D

0x2A26

Firmware Revision String

“1.7.15”

0x02

0x002E

0x2803

Characteristic Declaration

02:2F:00:28:2A

0x00

0x002F

0x2A28

Software Revision String

“1.7.15; Build 87; dKRs”

0x02

Brute-Forcing the Write Characteristics¶

Seeing that there are 2 characteristics which are write-only, it seems like good candidates for characteristics which accept user commands. A BLE characteristic can accept upto 20 bytes in this mode, because the MTU established in this connection is 23 bytes (this is default behavior for BLE). However, it is up to the GATT Server (pHin) to define how many actual byte can be written, and this can be any value upto 20 bytes.

I started by checking how many bytes can be sent on each of the write-only characteristics:

  • 0x152C accepts 1, 2, 3 and 4 bytes. Anything above 4 bytes results in an “Invalid Attribute Length”.

  • 0x152D accepts only 1 byte. Anything above 1 byte results in an “Invalid Attribute Length”.

This is good news: if we’re going to be brute-forcing values, we know that we have only 255 values to test on 0x152D. This is definately where I’m going to start.

To automate this, I use the following setup:

../_images/phin-brute-force-winter-mode.drawio.png

A short Python script on the test controller automates the interactions with the Power Supply and the BLE Dongle. The metholology is as follows:

  • Turn on the pHin power supply

  • Scan over BLE and connect

  • Write the next value to the 0x152D characteristic

  • Turn off and on the pHin power supply to trigger a reset

  • Wait 100 seconds for the initial 90-second connectable period to expire

  • Scan over BLE and see if the pHin is still advertising

  • Append the result to a log file

If the pHin is still advertising, it means it has not been put in winter mode. On the other hand, if the pHin is not advertising after those 100 seconds, it could very well have been passed in winter mode.

The test takes about 120 seconds, so it takes 8.5 hours to test all the 255 possible values of the 0x152D characteristic. This is already quite long, but worth a try. If it fails, it is worthwhile to do the same thing on the 0x152C characteristic (writing 1 byte only), but it would be impossible to test all the possible 2-byte, 3-byte and 4-byte combinations on 0x152C, since it accepts upto 4 bytes.

Brute Force Results: 0x152D¶

After testing the entire 255 possible values for the 0x152D, I was disappointed to see that none of the write operations resulted in a winter mode. Here is the full log file:

Brute Force Results: 0x152C¶

I set the brute-forcing script to the 0x152C characteristic, using the same methodology as for the previous charactersitic. I checked the first few values after starting the script, and I directly found something interesting. Here is the beginning of the log:

0:1
1:1
2:1
3:1
4:1
5:0
6:0
7:0
8:0
9:0
10:0

So it seems that after value 0x05, the advertisements are not active anymore. I stopped the script at this point and continued with manual tests. For some unknown reason, when I stopped the script I was unable to access the CY5677 BLE Dongle and had to revert to reprogramming the dongle and reboot my computer. Thinking I might have just had bad luck with the dongle, I re-ran the script again from the start, and saw the following initial results:

0:0
1:0
2:0
3:0
4:1
5:0
6:0

So it seems that there was something persistent after writing 0x05, which got reset when writing 0x04. I played around manually, repeating writing 0x04 and 0x05 manually and looking at the device’s behavior, and what I observe now seems to be the opposite of what the script outputs:

  • After writing 0x04 on 0x125C, the pHin monitor’s BLE Interface turns off after the initial 90s period

  • After writing 0x05 on 0x125C, the pHin monitor is back to normal advertising after the initial 90s period

I checked my scripts again to try to understand why I was getting the opposite, but I didn’t manage to spot any errors. I’m going to trust the manual tests…

Conclusion¶

Our brute-forcing of the 3206125C-76FD-4996-952B-2A1BE2CB9450 characteristic show that the values 0x04 and 0x05 are important. Manually testing these values brings me to the following conclusion:

  • Write 0x04 to 3206125C-76FD-4996-952B-2A1BE2CB9450 to set the pHin monitor in winter mode.

  • Write 0x05 to 3206125C-76FD-4996-952B-2A1BE2CB9450 to set the pHin monitor back to normal mode.