-
• #27
yes, we do not want to connect, just to scan for broadcasted ads with a time in data. May be in future there should be a certificate or at least a shared public key for security. So some hacker do not set all Bangles around to a wrong time. :)
-
• #28
Thanks @diego - I think I might end up using this, I think connecting will result in a much more accurate time than relying on the right advertisement being picked up at the right time.
I had a look at Bleak recently (it is in the Espruino tutorials somewhere), your example will be useful to me for another project I think.
-
• #29
1 ms accuracy is not possible
I think it is but not with such simple code. Great quick example. Few random ideas -
you can use setScan with right filter, this needs to be combined with some unique data in advertisement - e.g. manufacturer or serviceData. I think for serviceData id you could use id of specific characteristics in ble current time service or any other defined to contain time and then the data could match the format. It is not exactly to the standard but is close enough to not conflict with anything. see also https://devzone.nordicsemi.com/f/nordic-q-a/4048/what-service-data-can-be-added-to-the-advertising-packagemanufacturer is ok too but if you have more espruino devices you'll get more matches, with serviceData it would be unique
https://www.bluetooth.com/specifications/assigned-numbers/
https://www.bluetooth.com/specifications/specs/current-time-service-1-1/the 16bit assigned numbers for different entities are unique and not overlapping between types so that's why I think you can put it safely to serviceData even if it is not id for service
as for accuracy - ntp prococol can do it quite well over internet, bluetoth timing is strict, advertising packets are timed/spaced in deterministic way. the bash+hci command is probably the worst part here. I tried latest espruino with esp32 yesterday, looks like it can do ntp over wifi and can do Bluetooth advertising. I hope we could possibly generate advertising packet (or scan response packet) on the fly there. But anyway even second accuracy is good enough too.
EDIT: for esp32 to be usable for that we'd probably need something like this https://github.com/gmag11/ESPNtpClient to have the time in esp32 accurate to 1ms
-
• #30
I think connecting will result in a much more accurate time than relying on the right advertisement being picked up at the right time.
I guess both ways could work. The callback in setScan gives you the packet as it is received, not sure whether with connection you can get it faster. Connection/GATT stuff is another layer on top received packets that may slow things down or make it less deterministic. Advertisement packets are much simpler/lower level. Try with nrfconnect on android, there is history of advertisement packets received - click 'MORE' on device list to see how they arrived to the phone - it is not random at all.
-
• #31
I think connecting will result in a much more accurate time than relying on the right advertisement being picked up at the right time.
I thought so too but in my tests that connection takes several seconds while advertisement-solution can be improved down to e.g. 50ms delay between updating advertisement, so using connection is a lot worse for some reason.
bluetoth timing is strict, advertising packets are timed/spaced in deterministic way
No it's not deterministic - Bluetooth protocol has builtin random delay for timing which is around 10 ms or so, so accuracy better than that is not possible using normal API. (But yeah it's good enough.)
-
• #32
No it's not deterministic - Bluetooth protocol has builtin random delay for timing which is around 10 ms or so
Oh, you are right for the advertising, there is delay indeed. Decribed e.g. here https://www.argenox.com/library/bluetooth-low-energy/ble-advertising-primer/ didn't know this. Makes sense. However it is not like that for the rest, the rest has strict timing so receiver device can wake at the precise moment sender is supposed to send the packet, that is part of the 'low energy'.
But anyway even with advertising the timing for scan response packet may be better. This is with active scanning, it is second packet for advertising data.
EDIT:
Scan response is more deterministic, see https://devzone.nordicsemi.com/f/nordic-q-a/29719/beacon-scan-response-request-and-packet-timing -
• #33
Scan response timing seems deterministic only in relation to preceding advertising packet. For that to be useful I'd need to
a) know the exact time when preceding advertising packet was sent
b) set response packet content after preceding advertising packet has been sent, so it's uptodateI don't think either of those are possible with normal APIs since advertising isn't meant to be used for sending time-sensitive data like this. (Sure both would be possible in theory with custom Bluetooth protocol stack.)
-
• #34
@diego
Unfortunately I don't know what the recent responses mean. I'm not a programmer. (Someone else built my clock.) Is it possible to insert one of the scripts above (yours?) and get good time? What do they do? Where do they get the time from? (Where's the BLE source?) How often? Is the connection "automatic"?Thanks.
-
• #35
For that to be useful I'd need to
set response packet content after preceding advertising packet has been sent, so it's uptodateYes. This may actually work with nordic softdevice 6.1.x , see https://github.com/espruino/Espruino/issues/2000 since 6.1.0 you need to supply static buffer that needs to be allocated for whole advertising time. So most likely current data will be sent as is from that buffer, so updating timestamp in it periodically or when some event happens (like when someone asks for scan response) may work. Documentation says it should not be modified but if one does not change the structure and just update timestamp in specific location it may work.
Anyway, opening connection and getting time from characteristics (possibly few times) may be easier after all if millisecond accuracy is preferred.
-
• #36
This is one approach: it connect to bangle then sends the computer time (hopefully a good time)
within the command to update bangle. Then you have only the delay of the communication with the device, which can be measured and adjusted.On my device, this is the average for 100 samples: 0.05636221885681152s, so I could adjust to add 50ms on the time sent to the device to compensate.
-
• #37
Sorry, @Numerist, I think I was still a bit programmy on my response.
In more broad terms, the script above when executed on a computer with bluetooth sets the clock on the bangle to the time of the computer.As the communication of the command between pc and bangle is kind of fast, there's little need for compensating (50ms in my tests, but you can antecipate and correct for that if you wanted)
-
• #38
Also, I've just made a pex (executable) file from the sample script I've sent earlier, it's attached, if you want to try it out.
The pex is just a glorified zip file, so you can open it and check out inside, but you can execute with:
./send_time.pex 'aa:bb:cc:dd:ee:ff'
The usage:
usage: send_time.py [-h] [--correction CORRECTION] address
Bangle send time
positional arguments:
address bluetooth address to connect
optional arguments:
-h, --help show this help message and exit
--correction CORRECTION
milliseconds to add to time to compensate for connection time
1 Attachment
-
• #39
@diego
No problem; I'm the odd one here with no programming knowledge. I don't know how to run scripts like yours on my computer but may be able to find out…but what I really want is something to put on the watch that will get the time from my phone, preferably automatically at a specified interval (e.g. once or twice a day). Or if that's not possible, from my computer.Even better would be something like what worked for Bangle.js 1: set the GPS time once, and it controls the watch indefinitely. I still don't know if that's possible with Bangle.js 2. People say the GPS setup on the new watch is different, but what does that mean for this question?
-
• #40
My BLE time advertising is starting to work quite well. (I switched to Rust for broadcast code instead of bash as I know Rust quite well.) Current version doesn't actually change watch time, just applies the delta to displayed time.
-
• #41
Oh nice :-)
BTW one possibility for Service Data is to advertise "Date Time" 0x2A08 as per https://forum.micropython.org/viewtopic.php?t=9577&p=53698
it is 7 bytes format0 1 2 3 4 5 6
Description Year Month Day Hour Minute Second
Minimum 1582 1 1 0 0 0
Maximum 9999 12 31 23 59 59
Then one could pass options
{filters: [{serviceData:{"2a08":{}}}]}
and it should work. I tried it with ESP32 running espruino and it worked for me
On ESP32 I've runNRF.setAdvertising({
0x2a08 : [0xe6,0x07,1,22,17,19,30]
})
and then on another device this worked
>packets=2
=2
>NRF.setScan(function(d) {
: packets--;
: if (packets<=0)
: NRF.setScan(); // stop scanning
: else
: console.log(d); // print packet info
:},{filters: [{serviceData:{"2a08":{}}}]});
=undefined
BluetoothDevice: {
"id": "b4:e6:2d:89:01:27 public",
"rssi": -51,
"data": new Uint8Array([2, 1, 6, 10, 22, 8, 42, 230, 7, 1, 22, 17, 19, 30, 14, 9, 69, 83, 80, 51, 50, 46, 106, 115, 32, 48, 49, 50, 53, 0, 0]).buffer,
"name": "ESP32.js 0125",
"serviceData": {
"2a08": new Uint8Array([230, 7, 1, 22, 17, 19, 30]).buffer
}
}
>
-
• #42
I'm now including milliseconds also for more precision. Bangle.js 2 doesn't support setting time at millisecond precision, but this works quite nicely (wait until next exact second and then set time):
let delta = 1000 - (received_time % 1000);
setTimeout(function() {
setTime((received_time + delta) / 1000);
}, delta);
-
• #43
0x2A2B
"Current Time" seems better. It has those same fields and then 3 more single-byte fields, most importantlyfractions256
for 4 ms accuracy.dayOfWeek
: 1=Monday, 2=Tuesday, ..., 7=Sundayfractions256
: 0-255 ; 1/256th:s of a secondadjustReason
: 0 for this application
-
• #44
or just the 0x2a0c "Exact Time 256" which is without adjustReason
They are nested structures, see
https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v15.3.0%2Fstructexact__time__256__t.html or https://community.silabs.com/s/question/0D51M00007xeHRw/implementation-of-folded-ble-characteristics-in-gatt?language=en_USmy current ESP32 code is
// enable NTP
require("Wifi").setSNTP("pool.ntp.org","+01")
// advertise time
setInterval(function(){
var d=Date(),y=d.getFullYear(),day=d.getDay();
NRF.setAdvertising({
// 0x2a08 : [y&255,y)>>8,d.getMonth()+1,d.getDate(),d.getHours(),d.getMinutes(),d.getSeconds()]
0x2a0c : [y&255,y>>8,d.getMonth()+1,d.getDate(),d.getHours(),d.getMinutes(),d.getSeconds(),day?day:7,d.getMilliseconds()>>2]
});
},250);
-
• #45
It seems that the 0-10ms random delay is not added to first advertisement, only to subsequent advertisements.
I'm currently testing code like this which seems to give quite steady rate of one advertisement every second (I hope to publish full code soon, maybe tomorrow):
- start advertising
- wait 100 ms
- stop advertising
- wait 900 ms
- loop from beginning
For example here are differences in milliseconds of Bangle.js 2 time and my computer time for 5 minutes, one update every 10 seconds:
63 64 71 65 65 69
66 69 70 70 70 69
71 73 75 73 73 72
76 77 77 77 79 78
80 82 81 84 88 81
You can even see the clock drift here. With 1.73s/day you'd expect clock to drift 6ms in 5 minutes - at least for this short test it's clearly more than that.
- start advertising
-
• #46
The 10ms jitter is a deliberate collision avoidance mechanism in BLE. Do you really need sub-10ms accuracy on a watch?
-
• #47
No not really, I would've been happy with 200ms accuracy, but it's fun to see how accurate I can get.
I could add my own 10ms jitter to the 900ms sleep. The main thing is that there is no random delay between getting time from computer and sending advertising with that time.
-
• #48
additionally a delay can be figured out if there are 2 BLE devices on a computer.
One Advertiser, another Scanner. The Scanner, when it receives time can compare it with the computer time.
I may be try it with laptop internal BLE and USB dongle. -
• #49
Advertiser+Scanner could be used to advertise really accurate times:
- Advertiser sends time advertisement with ID
- Scanner receives that advertisement, compares included time with actual time, reports error to Advertiser
- Advertiser sends next time advertisement with next ID and error of previous advertisement
- ...
Then Bangle.js would need to receive two subsequent time advertisements to know exact time first advertisement was sent.
ps. I've now added my initial code to GitHub.
- Advertiser sends time advertisement with ID
-
• #50
I have also modified your bash example a bit, it runs on raspberry pi and uses the 0x2a0c "Exact Time 256"
advpad="00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
ble_advertise_datetime(){
values="$(( $1&255 )) $(( $2/256 )) $3 $4 $5 $6 $7 $8 $(( $9/4000000 ))"
sudo hcitool -i hci0 cmd 0x08 0x0008 10 02 01 06 0c 16 0c 2a $(printf '%02X %02X %02X %02X %02X %02X %02X %02X %02X' $values) $advpad
}
sudo hciconfig hci0 leadv 3
i=60
while [ $i -gt 0 ] ; do
echo $i
ble_advertise_datetime $(date "+%-Y %-Y %-m %-d %-H %-M %-S %-u %-N")
sleep 0.5
i=$((i-1))
done
sudo hciconfig hci0 noleadv
Yes, I don't use the gadgetbridge, so it works for me.