RadonEye BLE Interface

I ran your expect script on my RD200, changing the MAC address to match my device. Here’s the result:

$ ./temp_expect.sh 
Time 2022-07-04T14:51:48
50 0a 38 00 3c 00 00 00 05 00 0a 00 

This works for me. The current value for my RD200 was 1.51 pCi/L, and this data matches that. The 3rd and 4th bytes (38 00), little-endian, contain the current value in Bq/m^3:
x0038 = 56 Bq/m^3 = 1.51 pCi/L.

Notice the change I made to radon_reader.py for getting the RadonValue from sending 0x50:

RadonValue = struct.unpack('<H',RadonValue[2:4])[0]

The response is apparently different from what the old RD200 used to send, since the was the old code:

RadonValue = struct.unpack('<f',RadonValue[2:6])[0]

They are now sending as short int (2-bytes) with Bq/m^3 instead of pCi/L as a 4-byte float.

Thanks for the post, same result for me unfortunately. I just get all 0x0’s back from the write/read.

I modified the script to work with Python3 and added a bunch of debugs and uploaded it to github:

Here is my debug output:

pi@hassio:~/radonreader $ python3 radon_reader2.py -a 94:3c:c6:dd:42:ce -v
2022-07-05 00:34:25,168 - root - DEBUG - Service <uuid=Generic Attribute handleStart=1 handleEnd=5>
2022-07-05 00:34:25,169 - root - DEBUG - Service <uuid=Generic Access handleStart=20 handleEnd=28>
2022-07-05 00:34:25,170 - root - DEBUG - Service <uuid=1523 handleStart=40 handleEnd=65535>
2022-07-05 00:34:25,170 - root - DEBUG - Reading: 00001523-0000-1000-8000-00805f9b34fb
2022-07-05 00:34:25,171 - root - DEBUG - RadonEyeService from UUID: Service <uuid=1523 handleStart=40 handleEnd=65535>
2022-07-05 00:34:25,171 - root - DEBUG - Writing UUID: 00001524-0000-1000-8000-00805f9b34fb
2022-07-05 00:34:25,509 - root - DEBUG - Service Characteristics: Characteristic <1524>
2022-07-05 00:34:25,509 - root - DEBUG - Writing Bytes: b'P'
2022-07-05 00:34:26,665 - root - DEBUG - Reading: 00001525-0000-1000-8000-00805f9b34fb
2022-07-05 00:34:26,714 - root - DEBUG - Radon Value: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
2022-07-05 [00:34:26] - 94:3C:C6:DD:42:CE - Radon Value: 0.00 pCi/L

Update: I copied the methodology of using the handler reference in the ./temp_expect.sh script instead of using UUIDs and it actually works fine now. I will update the original radeon_reader.py with this code now…

pi@hassio:~/radonreader $ python3 radon_reader_by_handle.py
2022-07-05 01:51:27,215 - root - DEBUG - Radon Value Raw: b’P\n\x02\x00\x05\x00\x00\x00\x00\x00\x00\x00’
2022-07-05 01:51:27,215 - root - DEBUG - Radon Value Bq/m^3: 2
2022-07-05 01:51:27,215 - root - DEBUG - Radon Value pCi/L: 0.05405405405405406

Update #2
I updated radon_reader.py to:

-work with the new RD200
-auto scan for devices, so you don’t have to provide a MAC address
-automatically figure out the RD200 version based on the device name

Note:
– I tested the python app with my own RD200 v2, but do not have an RD200 v1 to test backwards comparability with.
– If you specify an address you now have to specify a device type -t (either 0 for the original RD200 or 1 for the new RD200)

1 Like

I was looking at gatttool, it can be run in non-interactive mode.
And one can request in which way UUIDs are connected to handles.

The old version of RD200:

gatttool -i hci0 -t random -b D5:04:05:65:AB:EF -I
[D5:04:05:65:AB:EF][LE]> connect
Attempting to connect to D5:04:05:65:AB:EF
Connection successful
[D5:04:05:65:AB:EF][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0009, end grp handle: 0x0011 uuid: 00001523-1212-efde-1523-785feabcd123
attr handle: 0x0012, end grp handle: 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb
[D5:04:05:65:AB:EF][LE]> char-desc
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x0008, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0009, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000a, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000b, uuid: 00001524-1212-efde-1523-785feabcd123
handle: 0x000c, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000d, uuid: 00001525-1212-efde-1523-785feabcd123
handle: 0x000e, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x000f, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0010, uuid: 00001526-1212-efde-1523-785feabcd123
handle: 0x0011, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0012, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0013, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0014, uuid: 00002a29-0000-1000-8000-00805f9b34fb

gatttool -i hci0 -t random -b D5:04:05:65:AB:EF --char-write-req --handle=0x000b --value=0x50 --char-read --handle=0x000d
Characteristic value/descriptor: 50 10 00 00 00 00 5c 8f c2 3e c3 f5 a8 3e 00 00 01 00 00 00

The new version of RD200:

gatttool -b 1C:9D:C2:51:7F:5A -I
[1C:9D:C2:51:7F:5A][LE]> connect
Attempting to connect to 1C:9D:C2:51:7F:5A
Connection successful
[1C:9D:C2:51:7F:5A][LE]> primary
attr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0028, end grp handle: 0xffff uuid: 00001523-0000-1000-8000-00805f9b34fb
[1C:9D:C2:51:7F:5A][LE]> char-desc
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb
handle: 0x0004, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb
handle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002a, uuid: 00001524-0000-1000-8000-00805f9b34fb
handle: 0x002b, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002c, uuid: 00001525-0000-1000-8000-00805f9b34fb
handle: 0x002d, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x002e, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002f, uuid: 00001526-0000-1000-8000-00805f9b34fb
handle: 0x0030, uuid: 00002902-0000-1000-8000-00805f9b34fb

gatttool -i hci0 -b 1C:9D:C2:51:7F:5A --mtu=507 --char-write-req --handle=0x002a --value=0x50 --char-read --handle=0x002c
Characteristic value/descriptor: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

The expect script is a “hack” which works. But certainly there is a problem with gattlib.

Seems a little strange. I think 0x002a resets to all 0’s after responding, and the read just gets the current, reset value.

Also:

$ gatttool -i hci0 -b 94:3C:C6:DE:31:7A --mtu=507 --char-write-req --handle=0x002a --value=0x50 --listen
Characteristic value was written successfully
^C
$ gatttool -i hci0 -b 94:3C:C6:DE:31:7A --mtu=507 --char-write-req --handle=0x002a --value=50 --listen
Characteristic value was written successfully
Notification handle = 0x002c value: 50 0a 30 00 3f 00 00 00 04 00 08 00 
^C

Seems like writing 0x50 doesn’t work, but writing 50 does, as long as --listen is used

The other problem is that non-interactive gatttool does not set MTU:

$ gatttool -i hci0 -b 94:3C:C6:DE:31:7A --mtu=507 --char-write-req --handle=0x002a --value=41 --listen
Characteristic value was written successfully
Notification handle = 0x002f value: 41 04 01 fa 19 00 30 00 30 00 26 00 2e 00 2e 00 2d 00 23 00 
Notification handle = 0x002f value: 41 04 02 fa 26 00 26 00 10 00 1a 00 13 00 20 00 2b 00 31 00 
Notification handle = 0x002f value: 41 04 03 fa 31 00 3b 00 38 00 3e 00 30 00 44 00 31 00 2b 00 
Notification handle = 0x002f value: 41 04 04 79 27 00 2b 00 38 00 3b 00 41 00 48 00 44 00 35 00 
^C

The first three responses are each supposed to be 507 bytes total transmission (last one = 249), and this only returns 23 bytes (the default, minimum value).

For example, interactive:

$ gatttool -i hci0 -b 94:3C:C6:DE:31:7A -I
[94:3C:C6:DE:31:7A][LE]> connect
Attempting to connect to 94:3C:C6:DE:31:7A
Connection successful
[94:3C:C6:DE:31:7A][LE]> mtu 507
MTU was exchanged successfully: 507
[94:3C:C6:DE:31:7A][LE]> char-write-req 0x002a 41
Characteristic value was written successfully
Notification handle = 0x002f value: 41 04 01 fa 19 00 30 00 30 00 26 00 2e 00 2e 00 2d 00 23 00 20 00 1d 00 2a 00 17 00 17 00 12 00 1d 00 1d 00 2b 00 34 00 2e 00 37 00 27 00 21 00 30 00 37 00 3a 00 2d 00 2b 00 1a 00 30 00 16 00 10 00 13 00 12 00 0f 00 17 00 16 00 24 00 19 00 16 00 26 00 1c 00 20 00 34 00 3f 00 26 00 35 00 3f 00 30 00 31 00 38 00 3f 00 44 00 38 00 26 00 19 00 24 00 2a 00 2e 00 21 00 20 00 1c 00 24 00 1c 00 26 00 38 00 2e 00 48 00 34 00 35 00 37 00 38 00 44 00 44 00 31 00 41 00 44 00 3b 00 27 00 2b 00 27 00 1d 00 17 00 2d 00 2b 00 27 00 26 00 2e 00 3b 00 44 00 44 00 3e 00 45 00 4e 00 37 00 34 00 44 00 2e 00 24 00 30 00 24 00 2b 00 2d 00 2a 00 30 00 1c 00 30 00 23 00 23 00 1c 00 23 00 31 00 20 00 3a 00 3e 00 3f 00 38 00 45 00 55 00 45 00 3a 00 42 00 2a 00 37 00 42 00 35 00 2e 00 38 00 2a 00 35 00 21 00 21 00 2a 00 26 00 24 00 3b 00 31 00 30 00 3e 00 30 00 3a 00 24 00 37 00 3b 00 37 00 26 00 41 00 30 00 1c 00 34 00 21 00 23 00 34 00 26 00 19 00 23 00 24 00 1d 00 19 00 16 00 2a 00 2e 00 34 00 3e 00 41 00 38 00 30 00 21 00 3a 00 2d 00 2a 00 2b 00 21 00 24 00 24 00 30 00 24 00 19 00 1c 00 16 00 1a 00 1a 00 21 00 27 00 2b 00 23 00 2b 00 27 00 2b 00 2a 00 3b 00 2d 00 2a 00 12 00 17 00 27 00 26 00 24 00 1d 00 27 00 20 00 1a 00 1d 00 20 00 23 00 24 00 31 00 20 00 2a 00 2a 00 31 00 34 00 3a 00 2d 00 42 00 34 00 35 00 34 00 3b 00 30 00 37 00 2e 00 27 00 26 00 17 00 2a 00 2b 00 20 00 19 00 26 00 2d 00 21 00 27 00 2e 00 38 00 37 00 38 00 30 00 27 00 21 00 31 00 24 00 26 00 19 00 2a 00 24 00 1a 00 1c 00 20 00 13 00 2a 00 
Notification handle = 0x002f value: 41 04 02 fa 26 00 26 00 10 00 1a 00 13 00 20 00 2b 00 31 00 3e 00 34 00 19 00 35 00 35 00 2e 00 30 00 37 00 24 00 2a 00 30 00 21 00 26 00 23 00 1c 00 19 00 1d 00 17 00 21 00 20 00 1d 00 2a 00 3b 00 24 00 20 00 26 00 24 00 30 00 2e 00 26 00 38 00 30 00 31 00 2a 00 2d 00 2b 00 2b 00 2b 00 26 00 2a 00 1d 00 24 00 1a 00 23 00 2e 00 30 00 45 00 41 00 2e 00 2b 00 34 00 38 00 3e 00 45 00 2d 00 42 00 35 00 2d 00 2a 00 26 00 1d 00 34 00 2e 00 20 00 26 00 2e 00 21 00 21 00 1c 00 2d 00 4e 00 41 00 45 00 38 00 31 00 3f 00 3a 00 38 00 35 00 23 00 26 00 27 00 24 00 16 00 2d 00 30 00 1c 00 2a 00 10 00 27 00 20 00 20 00 1d 00 26 00 2d 00 31 00 37 00 3e 00 31 00 2e 00 3a 00 2d 00 49 00 4b 00 41 00 37 00 2d 00 3f 00 3b 00 30 00 26 00 31 00 27 00 41 00 30 00 3b 00 41 00 5c 00 5a 00 45 00 44 00 4b 00 49 00 4c 00 45 00 30 00 48 00 45 00 41 00 38 00 2b 00 3a 00 31 00 37 00 24 00 27 00 26 00 17 00 31 00 34 00 23 00 2b 00 45 00 34 00 31 00 35 00 31 00 35 00 30 00 3e 00 42 00 2e 00 3a 00 2e 00 20 00 2a 00 23 00 1d 00 13 00 2e 00 16 00 1d 00 26 00 2a 00 27 00 31 00 37 00 37 00 3f 00 31 00 50 00 37 00 37 00 34 00 26 00 41 00 20 00 2b 00 23 00 2d 00 27 00 2d 00 34 00 2a 00 2b 00 35 00 2a 00 3b 00 42 00 49 00 45 00 50 00 50 00 3e 00 42 00 3a 00 4c 00 52 00 3f 00 41 00 42 00 3a 00 37 00 48 00 31 00 3e 00 30 00 3e 00 3e 00 3f 00 3a 00 38 00 2e 00 45 00 60 00 45 00 63 00 45 00 59 00 4c 00 38 00 52 00 42 00 3b 00 3a 00 35 00 3e 00 2a 00 30 00 26 00 24 00 2e 00 26 00 16 00 20 00 20 00 16 00 24 00 2d 00 35 00 34 00 23 00 
Notification handle = 0x002f value: 41 04 03 fa 31 00 3b 00 38 00 3e 00 30 00 44 00 31 00 2b 00 2a 00 37 00 1c 00 31 00 20 00 1d 00 30 00 2a 00 27 00 3a 00 2a 00 30 00 48 00 48 00 44 00 37 00 2d 00 2e 00 35 00 4b 00 3b 00 31 00 35 00 3e 00 1d 00 27 00 2e 00 2d 00 2d 00 2a 00 30 00 20 00 20 00 37 00 35 00 49 00 56 00 4c 00 3a 00 2b 00 3e 00 3a 00 3e 00 4c 00 37 00 30 00 38 00 2a 00 30 00 2d 00 2e 00 1d 00 2b 00 3a 00 3b 00 27 00 49 00 50 00 3b 00 41 00 42 00 5d 00 4c 00 3b 00 3a 00 23 00 30 00 31 00 3a 00 49 00 26 00 2a 00 26 00 2d 00 20 00 20 00 20 00 26 00 1d 00 24 00 1a 00 0f 00 2d 00 23 00 24 00 23 00 26 00 1d 00 34 00 35 00 31 00 34 00 23 00 2a 00 2a 00 26 00 27 00 1d 00 26 00 35 00 30 00 2e 00 13 00 35 00 34 00 24 00 2a 00 26 00 3a 00 34 00 3e 00 3b 00 2d 00 3e 00 44 00 3a 00 2b 00 3b 00 31 00 23 00 35 00 2e 00 30 00 2d 00 30 00 26 00 45 00 3e 00 3f 00 38 00 38 00 37 00 30 00 24 00 2b 00 42 00 41 00 3f 00 3f 00 3b 00 30 00 30 00 3f 00 30 00 35 00 13 00 1a 00 20 00 27 00 3b 00 2d 00 35 00 38 00 41 00 38 00 42 00 3f 00 31 00 3e 00 2e 00 30 00 4e 00 3b 00 38 00 31 00 3a 00 31 00 38 00 2e 00 2b 00 23 00 37 00 2a 00 19 00 2b 00 31 00 2a 00 31 00 52 00 66 00 52 00 5c 00 49 00 4c 00 42 00 52 00 45 00 37 00 37 00 3f 00 4b 00 23 00 3b 00 30 00 27 00 2a 00 2a 00 2d 00 37 00 2a 00 20 00 2a 00 31 00 3b 00 31 00 30 00 31 00 4c 00 3f 00 5f 00 41 00 3b 00 31 00 42 00 3e 00 3a 00 2d 00 24 00 34 00 2d 00 2e 00 21 00 31 00 2e 00 26 00 2d 00 26 00 56 00 3e 00 41 00 3b 00 4b 00 56 00 45 00 4c 00 3f 00 34 00 45 00 3e 00 42 00 42 00 30 00 
Notification handle = 0x002f value: 41 04 04 79 27 00 2b 00 38 00 3b 00 41 00 48 00 44 00 35 00 38 00 4e 00 3b 00 3e 00 3e 00 4b 00 71 00 42 00 56 00 52 00 4c 00 37 00 31 00 34 00 30 00 20 00 19 00 24 00 1d 00 2a 00 19 00 24 00 2d 00 1a 00 31 00 2b 00 37 00 34 00 3a 00 41 00 4c 00 38 00 3f 00 3b 00 2d 00 37 00 3f 00 35 00 27 00 2a 00 23 00 2a 00 23 00 2a 00 37 00 3f 00 38 00 4e 00 3e 00 44 00 48 00 49 00 38 00 41 00 38 00 45 00 50 00 41 00 38 00 34 00 3a 00 3f 00 30 00 44 00 21 00 37 00 2d 00 21 00 19 00 3b 00 30 00 2d 00 4e 00 4b 00 59 00 55 00 44 00 3a 00 52 00 50 00 66 00 5d 00 31 00 4c 00 42 00 42 00 2e 00 30 00 2d 00 21 00 24 00 31 00 2a 00 24 00 37 00 24 00 2e 00 42 00 49 00 5c 00 64 00 5a 00 50 00 42 00 48 00 48 00 38 00 41 00 41 00 31 00 52 00 2d 00 31 00 
[94:3C:C6:DE:31:7A][LE]> disconnect

(gatttool:2066): GLib-WARNING **: 16:04:05.144: Invalid file descriptor.

[94:3C:C6:DE:31:7A][LE]> exit

Definitely not getting all of the bytes using non-inteactive. Also, trying to read that value (0x002f) instad of --listen with non-interactive also fails:

$ gatttool -i hci0 -b 94:3C:C6:DE:31:7A --mtu=507 --char-write-req --handle=0x002a --value=41 --char-read --handle 0x002f
Characteristic value/descriptor: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

I am using a pretty hacked together python3 script that uses pygatt, with a gatttool backend. It works fine, other than its ugliness and lack of error trapping:

#! /usr/bin/env python3

import pygatt
import time
from struct import unpack
import csv
from datetime import timedelta
from datetime import datetime
import os
from influxdb import InfluxDBClient

## This changes directory to the location of the script when called by crontab (on external storage device):
abspath = os.path.abspath(__file__)
dirname = os.path.dirname(abspath)
os.chdir(dirname)

## Change this to RD200 MAC:
radon_mac = 'XX:XX:XX:XX:XX:XX'

## influx configuration - edit these:
ifuser = "username"
ifpass = "password"
ifdb   = "dbname"
ifhost = "127.0.0.1"
ifport = 8086
measurement_name = "Radon"

## Use GATTTool backend on RPi:
adapter = pygatt.GATTToolBackend()

complete = False
history = []
## Get current time:
now = datetime.now()

## Round to the nearest 5 minutes (not required):
now = now - timedelta(minutes=now.minute % 5,
                      seconds=now.second,
                      microseconds=now.microsecond)

## This manages history data and writes to CSV
## Eventually I want to clear/recreate InfluxDB table with new info
## handle_data gets the history values using 0x41:
def handle_data(handle, value):
#    print("Received data: %s" % value.hex())
    
    ## Using global lets me tell main program that this is finished
    global complete
    global history
    req_no = value.pop(0)
    tot_resps = value.pop(0)
    this_resp = value.pop(0)
    num_values = value.pop(0)
    ## After removing the first 4 bytes, the rest contain history in Bq/m^3:
    Bq_m3 = unpack('<'+'H'*(len(value)//2),value)
#    print(len(Bq_m3))
    Bq_m3 = list(Bq_m3)
    pCi_L = [x/37 for x in Bq_m3]
    resp_len = len(Bq_m3)
    if num_values != resp_len:
        print("Number of values didn't match!")

#    print(f"Requested {req_no}, got {tot_resps} replies, this is reply {this_resp} containing {num_values} values.")
#    print(f"Values: {value.hex()}")
#    print(f"First 4 values out of {resp_len} total in this response: {Bq_m3[0:4]} Bq/m^3")
#    print(f"First 4 values out of {resp_len} total in this response: {pCi_L[0:4]} pCi/L")

    ## This adds the latest values to history:
    history.extend(pCi_L)

    ## If this response is the last response, set complete to True:
    if this_resp == tot_resps:
        #print("Completed")
        complete = True


## handle_current gets the current data using 0x40:
def handle_current(handle, value):
    currentTime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    ## take a timestamp for this measurement
    time = datetime.utcnow()

    #print("Received data: %s" % value.hex())
    
    ## global complete lets the main program know this is finished:
    global complete
    req_no = value.pop(0) # first byte is 0x40 from write
    extra_no = value.pop() # don't know what last byte is for... removed it
    
    Bq_m3 = unpack('<'+'H'*(len(value)//2),value)
#    print(len(Bq_m3))
    resp_len = len(Bq_m3)
#    print(f"Values: {value.hex()}")
#    print(Bq_m3)
    latest = Bq_m3[16]/37 # the latest value is stored at 16
    peak = Bq_m3[25]/37 # the peak value is stored at 25
#    print(currentTime)
    print(f"Latest value = {latest:.2f} pCi/L at {currentTime}")
    print(f"Peak value = {peak:.2f} pCi/L")
    
    ## Append to CSV file using rounded time (now):
    with open("RadonCurrentValues.csv", "a") as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow([now,latest,peak])

    ## format the data as a single measurement for influx
    body = [
        {
        "measurement": measurement_name,
        "time": time,
        "fields": {
            "radon": latest,
            "peak": peak
            }
        }
    ]
    ## connect to influx
    ifclient = InfluxDBClient(ifhost,ifport,ifuser,ifpass,ifdb)
    ## write the measurement
    ifclient.write_points(body)

    complete = True

try:
    adapter.start()

    try:
        device = adapter.connect(radon_mac,timeout=20)
    except:
        print("Couldn't connect, retrying...")
        device = adapter.connect(radon_mac,timeout=20)

    ## Set mtu to get the full history responses:
    try:
        device.exchange_mtu(507)
    except:
        print("Couldn't set MTU, retrying...")
        device.exchange_mtu(507)

    
    print("Subscribing to history response...")
    
    ## For some reason there is no subscribe_handle, even though char_write_handle exists... weird.
    #device.subscribe_handle(0x002f,
    #                 callback=handle_data,
    #                 indication=False,
    #                 wait_for_response=False)

    ## Subscribe to UUID:
    device.subscribe("00001526-0000-1000-8000-00805f9b34fb",
                     callback=handle_data,
                     indication=False,
                     wait_for_response=False)

    ## Request history data by sending 0x41:
    print("Requesting data...")
    device.char_write_handle(0x002a,
                      bytearray([0x41]),
                      wait_for_response=False)

    ## Could also subscribe to UUID instead of handle:
    #device.char_write("00001524-0000-1000-8000-00805f9b34fb",
    #                  bytearray([0x41]),
    #                  wait_for_response=False)

    while not (complete) :
        time.sleep(1) # wait one second until handle_data sets complete to True
#        print(f"Complete = {complete}")

    device.unsubscribe("00001526-0000-1000-8000-00805f9b34fb")

    ## This doesn't store dates for history, just one per hour
    ## Cound history and subtract 1 hour each (assuming device was kept running continuously):
    historyCount = len(history)
    difference = timedelta(hours=1)
    times = [now - x*difference for x in list(range(historyCount-1, -1, -1))]
    
    ## Write history values to CSV file or DB here (new file each time):
    with open("RadonHistory.csv", "w") as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(["Timestamp","Radon (pCi/L)"])
        for value in range(len(history)):
            writer.writerow([times[value], history[value]])


    ## Now, set complete to False again to get current values:
    complete = False

    ## Make sure file exists, otherwise write header:
    if not os.path.isfile("RadonCurrentValues.csv"):
        with open("RadonCurrentValues.csv", "w") as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow(["Timestamp","Radon (pCi/L)","Peak value (pCi/L)"])


    print("Subscribing to current response...")
    
    ## Subscribe to 1525 for current data:
    device.subscribe("00001525-0000-1000-8000-00805f9b34fb",
                     callback=handle_current,
                     indication=False,
                     wait_for_response=False)
    
    print("Requesting data...")

    ## Request current data by sending 0x40:
    device.char_write_handle(0x002a,
                      bytearray([0x40]),
                      wait_for_response=False)

    while not (complete) :
        time.sleep(1) # wait one second until handle_data sets complete to True
#        print(f"Complete = {complete}")

    #device.unsubscribe("00001525-0000-1000-8000-00805f9b34fb")
    ## Why is it not subscribed? Leave it out...
    ## For some reason that caused an error

finally:
    adapter.stop()
#    print(f"Historical data (Bq/m^3): {history}")
    print(f"Total hours returned for history: {len(history)}")

Pygatt required me to subscribe to the response to get the correct data. I don’t know how that relates to using non-interactive gatttool, but just reading from the handle would return 0’s unless it was a response to the request.

Hey, thanks for the handle for the old device. I updated the file in the repo to do either 0x002a for the new device and 0x000b for the old device.

Could someone test the radon_reader.py in my github with an old RD200 device? It is 100% working with the my new RD200 now.

I also added instructions in the README on how to integrate the MQTT messages into Home Assistant.

Maybe that was a typo:

Old device:
handle: 0x000d, uuid: 00001525-1212-efde-1523-785feabcd123

The handles are:

New device:
send 0x002a → notification receive on: 0x002c

Old device:
send 0x000b → notification receive on: 0x000d

I updated the ./temp_expect.sh expect script that was posted earlier to account for both device types. It is also working on my new RD200.

Strange. With the old devices only the non-interactive command works:

gatttool -i hci0 -t random -b D5:04:05:65:AB:EF --char-write-req --handle=0x000b --value=50 --char-read --handle=0x000d
Characteristic value/descriptor: 50 10 ec 51 b8 3d 85 eb d1 3e c3 f5 a8 3e 00 00 01 00 00 00

Here is a one liner that works for the new device:

echo $(timeout 5 gatttool -i hci0 -t public -b 94:3c:c6:dd:42:ce --char-write-req --handle=0x002a --value=50 --mtu=507 --listen)

Great !

But why does gatttool provide only zero data in case -t public and --listen are not included ?
And most of the time gatttool complains with:

connect error: Function not implemented (38)

until it ends with success.
But at least this behavior is similar to the interactive mode.

Why not just use the updated python script I posted? It works better and posts stuff to MQTT.

Also I think that this is not a bug in gatttool. It seems that the process for getting current readings from the RD200 has changed. The new device expects you to subscribe to notifications and receive the data that way versus reading it directly from the handle.

1 Like

@lunaHome I spent way too much time trying to make the RadonEye I purchased this year work with ESPHome but with no luck. But your script works beautifully on my Rapsberry Pi Zero W.

2 Likes

So happy to see this script. I have installed on a pi 2 and I am getting the following errors on run. Any ideas would be great!

pi@phoscon:~/Downloads/radonreader-master $ python3 radon_reader.py -v -ms localhost -mu radonuser -mw radon123  -ma -m -t 1 -a 94:3C:C6:DD:20:02
2022-07-12 08:33:08,030 - root - DEBUG - Re-trying connections attempts: 1'
2022-07-12 08:33:09,070 - root - DEBUG - Re-trying connections attempts: 2'
2022-07-12 08:33:10,107 - root - DEBUG - Re-trying connections attempts: 3'
2022-07-12 08:33:11,140 - root - DEBUG - Re-trying connections attempts: 4'
2022-07-12 08:33:12,143 - root - DEBUG - Sending payload (byte): b'P' To handle (int): 42
Helper not started (did you call connect()?)
~~~

I got it working! Just realized pi 2 does not have BT. Setup a pi 3 and it works!
Thanks for this!!

Hey I don’t think that the RPi2 has Bluetooth. I think they added that with the RPi3

Good deal!

The python script with a raspberry pi zero w works great! I would love to get ESPHome working it’s a bit lighter than a full OS for this measurement, but for now at least I’m gathering data!

This may not be the right place for this question / issue but I’m running the phython script on a pi4 with phython 3.9. I’m getting a message “Helper not started (did you call connect()?)”. Any idea what I’m doing wrong? I had it working last night, I rebooted and now I get this message.

Thank you.