1
+ < html >
2
+ < head >
3
+ < title > Demo FTMS Treadmill Web Console</ title >
4
+ </ head >
5
+
6
+ < body >
7
+ < h1 > Web Bluetooth / FTMS BLE Treadmill</ h1 >
8
+
9
+ < h2 > Connection</ h2 >
10
+ < button id ="bleConnectionButton "> Connect FTMS BLE Treadmill</ button >
11
+ < br />
12
+ < span > Open the Web brower console to see the result.</ span >
13
+ </ body >
14
+
15
+ < script >
16
+ const serviceFTMS = 0x1826 ;
17
+ const treadmillData = 0x2acd ;
18
+
19
+ document . querySelector ( '#bleConnectionButton' ) . addEventListener ( 'click' , function ( ) {
20
+ if ( isWebBluetoothEnabled ( ) ) {
21
+ connect ( ) ;
22
+ }
23
+ } ) ;
24
+
25
+
26
+
27
+ function isWebBluetoothEnabled ( ) {
28
+ if ( navigator . bluetooth ) {
29
+ return true ;
30
+ } else {
31
+ ChromeSamples . setStatus ( 'Web Bluetooth API is not available.\n' +
32
+ 'Please make sure the "Experimental Web Platform features" flag is enabled.' ) ;
33
+ return false ;
34
+ }
35
+ }
36
+
37
+
38
+
39
+ function connect ( ) {
40
+ console . log ( 'Requesting FTMS Bluetooth Device...' ) ;
41
+ navigator . bluetooth . requestDevice ( {
42
+ filters :[ {
43
+ services : [ serviceFTMS ] ,
44
+ } ] } )
45
+ . then ( device => {
46
+ console . log ( 'Connecting to GATT Server...' ) ;
47
+ return device . gatt . connect ( ) ;
48
+ } )
49
+ . then ( server => {
50
+ console . log ( 'Getting Service...' ) ;
51
+ return server . getPrimaryService ( serviceFTMS ) ;
52
+ } )
53
+ . then ( service => {
54
+ console . log ( 'Getting Characteristic...' ) ;
55
+ return service . getCharacteristic ( treadmillData ) ;
56
+ } )
57
+ . then ( characteristic => {
58
+ var treadmillDataCharacteristic = characteristic ;
59
+ return treadmillDataCharacteristic . startNotifications ( ) . then ( _ => {
60
+ console . log ( '> Notifications started' ) ;
61
+ treadmillDataCharacteristic . addEventListener ( 'characteristicvaluechanged' , handleNotifications ) ;
62
+ } ) ;
63
+ } )
64
+ . catch ( error => {
65
+ console . log ( 'Argh! ' + error ) ;
66
+ } ) ;
67
+ }
68
+
69
+
70
+
71
+
72
+ function handleNotifications ( event ) {
73
+ let value = event . target . value ;
74
+ let a = [ ] ;
75
+ // Convert raw data bytes to hex values in order to console log each notification.
76
+ for ( let i = 0 ; i < value . byteLength ; i ++ )
77
+ {
78
+ a . push ( '0x' + ( '00' + value . getUint8 ( i ) . toString ( 16 ) ) . slice ( - 2 ) ) ;
79
+ }
80
+ console . log ( '> ' + a . join ( ' ' ) ) ;
81
+
82
+ var flags = value . getUint16 ( 0 , /*littleEndian=*/ true ) ;
83
+ // 2octets for flags, 2octets for instant speed, nextPosition is incremented following the number of octets for each value
84
+ var nextPosition = 4 ;
85
+
86
+
87
+ if ( ( flags & ( 1 << 1 ) ) != 0 ) { posAvgSpeed = nextPosition ; nextPosition += 2 ; }
88
+ if ( ( flags & ( 1 << 2 ) ) != 0 ) { posTotDistance = nextPosition ; nextPosition += 3 ; } //4
89
+ if ( ( flags & ( 1 << 3 ) ) != 0 ) { posInclination = nextPosition ; nextPosition += 4 ; } //8
90
+ if ( ( flags & ( 1 << 4 ) ) != 0 ) { posElevGain = nextPosition ; nextPosition += 4 ; }
91
+ if ( ( flags & ( 1 << 5 ) ) != 0 ) { posInsPace = nextPosition ; nextPosition += 1 ; }
92
+ if ( ( flags & ( 1 << 6 ) ) != 0 ) { posAvgPace = nextPosition ; nextPosition += 1 ; }
93
+ if ( ( flags & ( 1 << 7 ) ) != 0 ) { posKcal = nextPosition ; nextPosition += 5 ; }
94
+ if ( ( flags & ( 1 << 8 ) ) != 0 ) { posHR = nextPosition ; nextPosition += 1 ; }
95
+ if ( ( flags & ( 1 << 9 ) ) != 0 ) { posMET = nextPosition ; nextPosition += 1 ; }
96
+ if ( ( flags & ( 1 << 10 ) ) != 0 ) { posElaspedTime = nextPosition ; nextPosition += 2 ; }
97
+ if ( ( flags & ( 1 << 11 ) ) != 0 ) { posRemainTime = nextPosition ; nextPosition += 2 ; }
98
+ if ( ( flags & ( 1 << 12 ) ) != 0 ) { posForceBelt = nextPosition ; nextPosition += 4 ; }
99
+
100
+ // instantaneous speed
101
+ speed = value . getUint16 ( 2 , /*littleEndian=*/ true ) / 100 ;
102
+ console . log ( '> Speed ' + speed ) ;
103
+
104
+ //distance
105
+ distance = value . getUint16 ( posTotDistance , /*littleEndian=*/ true ) ;
106
+ distance_complement = value . getUint8 ( posTotDistance + 2 , /*littleEndian=*/ true ) ;
107
+ distance_complement = distance_complement << 16 ;
108
+ distance = distance + distance_complement ;
109
+ console . log ( '> Distance ' + distance ) ;
110
+
111
+ if ( typeof posInclination != "undefined" )
112
+ {
113
+ inclination = ( value . getInt16 ( posInclination , /*littleEndian=*/ true ) / 10 ) ;
114
+ console . log ( '> Inclinaison % ' + inclination ) ;
115
+ }
116
+
117
+ if ( typeof posKcal != "undefined" )
118
+ {
119
+ kcal = ( value . getUint16 ( posKcal , /*littleEndian=*/ true ) ) ;
120
+ console . log ( '> Kcal ' + kcal ) ;
121
+ }
122
+
123
+ if ( typeof posHR != "undefined" )
124
+ {
125
+ console . log ( '> HR ' + ( value . getUint8 ( posHR , /*littleEndian=*/ true ) ) ) ;
126
+ }
127
+
128
+ if ( typeof posElaspedTime != "undefined" )
129
+ {
130
+ console . log ( '> Elapsed time ' + ( value . getUint16 ( posElaspedTime , /*littleEndian=*/ true ) ) ) ;
131
+ }
132
+ }
133
+
134
+
135
+
136
+ </ script >
137
+ </ html >
0 commit comments