API du pont JavaScript
Capteurs de fitness BLE
Fréquence cardiaque, vitesse, cadence, puissance et batterie à partir des profils Bluetooth Low Energy standard.
AppMint.beacons assistant#
AppMint.beacons.startScan(options) / stopScan() / isScanning()
Exemple
Trouve les balises Bluetooth à proximité (iBeacon et Eddystone : UID, URL et TLM) et informe la page de chacune environ une fois par seconde via l'événement appmint:beacon, avec la puissance du signal et une distance approximative.
Retourne : startScan() → une Promise de {ok: true} ou {ok: false, code} (not_enabled, permission_denied, bluetooth_off, bluetooth_unavailable, scan_failed, blocked). stopScan() → {ok: true}. isScanning() → true/false. Nécessite : rien à cocher : une compilation dont le code appelle beacons.startScan déclare les autorisations d'analyse Bluetooth et de localisation précise (les résultats de balises sont des données de localisation pour Android, donc l'utilisateur doit accepter les deux, et Play classe l'application comme utilisant la localisation).
Détectez les balises d'un même lieu :
window.addEventListener('appmint:beacon', function (e) {
var b = e.detail;
if (b.type === 'ibeacon') {
showNearest(b.uuid, b.major, b.minor, b.distance); // metres, a rough estimate
} else if (b.type === 'eddystone-url') {
offerLink(b.url);
} else if (b.type === 'state') {
console.log('beacon scan ' + b.state); // 'scanning' | 'stopped'
} else if (b.type === 'error') {
console.warn('beacon scan error', b.error);
}
});
async function startRanging() {
if (!(window.AppMint && AppMint.beacons)) return;
var r = await AppMint.beacons.startScan({ uuids: ['e2c56db5-dffb-48d2-b060-d0f5a71096e0'] });
if (!r.ok) alert(r.code === 'bluetooth_off' ? 'Turn on Bluetooth' : 'Cannot scan: ' + r.code);
}Eddystone uniquement, avec la télémétrie de la batterie :
AppMint.beacons.startScan({ ibeacon: false });
window.addEventListener('appmint:beacon', function (e) {
var b = e.detail;
if (b.type === 'eddystone-uid') console.log(b.namespace, b.instance, b.rssi, b.distance);
if (b.type === 'eddystone-tlm') console.log(b.address, b.batteryMilliVolts + ' mV', b.temperatureC + ' °C');
});Arrêtez en quittant l'écran :
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});Champs de l'événement : chaque balise a type, rssi, address, timestamp ; iBeacon ajoute uuid, major, minor, txPower, distance ; Eddystone UID ajoute namespace, instance, txPower, distance ; URL ajoute url ; TLM ajoute batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtre les UUID iBeacon et les espaces de noms Eddystone (hexadécimal en minuscules).
Remarques : La distance est déduite de la puissance du signal et n'est fiable que pour proche / loin : les murs et les corps la modifient de plusieurs mètres. L'analyse dure jusqu'à stopScan() ou la fermeture de l'application.
beaconIsScanning pont#
window.WebToApk.beaconIsScanning(): Boolean
Indique si une analyse de balises est en cours.
Exemple
Documenté avec AppMint.beacons : l'exemple qui s'y trouve illustre aussi celui-ci.
Trouve les balises Bluetooth à proximité (iBeacon et Eddystone : UID, URL et TLM) et informe la page de chacune environ une fois par seconde via l'événement appmint:beacon, avec la puissance du signal et une distance approximative.
Retourne : startScan() → une Promise de {ok: true} ou {ok: false, code} (not_enabled, permission_denied, bluetooth_off, bluetooth_unavailable, scan_failed, blocked). stopScan() → {ok: true}. isScanning() → true/false. Nécessite : rien à cocher : une compilation dont le code appelle beacons.startScan déclare les autorisations d'analyse Bluetooth et de localisation précise (les résultats de balises sont des données de localisation pour Android, donc l'utilisateur doit accepter les deux, et Play classe l'application comme utilisant la localisation).
Détectez les balises d'un même lieu :
window.addEventListener('appmint:beacon', function (e) {
var b = e.detail;
if (b.type === 'ibeacon') {
showNearest(b.uuid, b.major, b.minor, b.distance); // metres, a rough estimate
} else if (b.type === 'eddystone-url') {
offerLink(b.url);
} else if (b.type === 'state') {
console.log('beacon scan ' + b.state); // 'scanning' | 'stopped'
} else if (b.type === 'error') {
console.warn('beacon scan error', b.error);
}
});
async function startRanging() {
if (!(window.AppMint && AppMint.beacons)) return;
var r = await AppMint.beacons.startScan({ uuids: ['e2c56db5-dffb-48d2-b060-d0f5a71096e0'] });
if (!r.ok) alert(r.code === 'bluetooth_off' ? 'Turn on Bluetooth' : 'Cannot scan: ' + r.code);
}Eddystone uniquement, avec la télémétrie de la batterie :
AppMint.beacons.startScan({ ibeacon: false });
window.addEventListener('appmint:beacon', function (e) {
var b = e.detail;
if (b.type === 'eddystone-uid') console.log(b.namespace, b.instance, b.rssi, b.distance);
if (b.type === 'eddystone-tlm') console.log(b.address, b.batteryMilliVolts + ' mV', b.temperatureC + ' °C');
});Arrêtez en quittant l'écran :
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});Champs de l'événement : chaque balise a type, rssi, address, timestamp ; iBeacon ajoute uuid, major, minor, txPower, distance ; Eddystone UID ajoute namespace, instance, txPower, distance ; URL ajoute url ; TLM ajoute batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtre les UUID iBeacon et les espaces de noms Eddystone (hexadécimal en minuscules).
Remarques : La distance est déduite de la puissance du signal et n'est fiable que pour proche / loin : les murs et les corps la modifient de plusieurs mètres. L'analyse dure jusqu'à stopScan() ou la fermeture de l'application.
beaconStartScan pont#
window.WebToApk.beaconStartScan(optionsJson: String, callbackId: String)
Démarre la détection de balises avec [optionsJson] `{uuids?, ibeacon?, eddystone?}` ; résout [callbackId] avec `{ok}` ou `{ok:false, code}`.
Exemple
Documenté avec AppMint.beacons : l'exemple qui s'y trouve illustre aussi celui-ci.
Trouve les balises Bluetooth à proximité (iBeacon et Eddystone : UID, URL et TLM) et informe la page de chacune environ une fois par seconde via l'événement appmint:beacon, avec la puissance du signal et une distance approximative.
Retourne : startScan() → une Promise de {ok: true} ou {ok: false, code} (not_enabled, permission_denied, bluetooth_off, bluetooth_unavailable, scan_failed, blocked). stopScan() → {ok: true}. isScanning() → true/false. Nécessite : rien à cocher : une compilation dont le code appelle beacons.startScan déclare les autorisations d'analyse Bluetooth et de localisation précise (les résultats de balises sont des données de localisation pour Android, donc l'utilisateur doit accepter les deux, et Play classe l'application comme utilisant la localisation).
Détectez les balises d'un même lieu :
window.addEventListener('appmint:beacon', function (e) {
var b = e.detail;
if (b.type === 'ibeacon') {
showNearest(b.uuid, b.major, b.minor, b.distance); // metres, a rough estimate
} else if (b.type === 'eddystone-url') {
offerLink(b.url);
} else if (b.type === 'state') {
console.log('beacon scan ' + b.state); // 'scanning' | 'stopped'
} else if (b.type === 'error') {
console.warn('beacon scan error', b.error);
}
});
async function startRanging() {
if (!(window.AppMint && AppMint.beacons)) return;
var r = await AppMint.beacons.startScan({ uuids: ['e2c56db5-dffb-48d2-b060-d0f5a71096e0'] });
if (!r.ok) alert(r.code === 'bluetooth_off' ? 'Turn on Bluetooth' : 'Cannot scan: ' + r.code);
}Eddystone uniquement, avec la télémétrie de la batterie :
AppMint.beacons.startScan({ ibeacon: false });
window.addEventListener('appmint:beacon', function (e) {
var b = e.detail;
if (b.type === 'eddystone-uid') console.log(b.namespace, b.instance, b.rssi, b.distance);
if (b.type === 'eddystone-tlm') console.log(b.address, b.batteryMilliVolts + ' mV', b.temperatureC + ' °C');
});Arrêtez en quittant l'écran :
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});Champs de l'événement : chaque balise a type, rssi, address, timestamp ; iBeacon ajoute uuid, major, minor, txPower, distance ; Eddystone UID ajoute namespace, instance, txPower, distance ; URL ajoute url ; TLM ajoute batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtre les UUID iBeacon et les espaces de noms Eddystone (hexadécimal en minuscules).
Remarques : La distance est déduite de la puissance du signal et n'est fiable que pour proche / loin : les murs et les corps la modifient de plusieurs mètres. L'analyse dure jusqu'à stopScan() ou la fermeture de l'application.
beaconStopScan pont#
window.WebToApk.beaconStopScan(callbackId: String)
Arrête la détection des balises ; résout [callbackId] avec `{ok:true}`.
Exemple
Documenté avec AppMint.beacons : l'exemple qui s'y trouve illustre aussi celui-ci.
Trouve les balises Bluetooth à proximité (iBeacon et Eddystone : UID, URL et TLM) et informe la page de chacune environ une fois par seconde via l'événement appmint:beacon, avec la puissance du signal et une distance approximative.
Retourne : startScan() → une Promise de {ok: true} ou {ok: false, code} (not_enabled, permission_denied, bluetooth_off, bluetooth_unavailable, scan_failed, blocked). stopScan() → {ok: true}. isScanning() → true/false. Nécessite : rien à cocher : une compilation dont le code appelle beacons.startScan déclare les autorisations d'analyse Bluetooth et de localisation précise (les résultats de balises sont des données de localisation pour Android, donc l'utilisateur doit accepter les deux, et Play classe l'application comme utilisant la localisation).
Détectez les balises d'un même lieu :
window.addEventListener('appmint:beacon', function (e) {
var b = e.detail;
if (b.type === 'ibeacon') {
showNearest(b.uuid, b.major, b.minor, b.distance); // metres, a rough estimate
} else if (b.type === 'eddystone-url') {
offerLink(b.url);
} else if (b.type === 'state') {
console.log('beacon scan ' + b.state); // 'scanning' | 'stopped'
} else if (b.type === 'error') {
console.warn('beacon scan error', b.error);
}
});
async function startRanging() {
if (!(window.AppMint && AppMint.beacons)) return;
var r = await AppMint.beacons.startScan({ uuids: ['e2c56db5-dffb-48d2-b060-d0f5a71096e0'] });
if (!r.ok) alert(r.code === 'bluetooth_off' ? 'Turn on Bluetooth' : 'Cannot scan: ' + r.code);
}Eddystone uniquement, avec la télémétrie de la batterie :
AppMint.beacons.startScan({ ibeacon: false });
window.addEventListener('appmint:beacon', function (e) {
var b = e.detail;
if (b.type === 'eddystone-uid') console.log(b.namespace, b.instance, b.rssi, b.distance);
if (b.type === 'eddystone-tlm') console.log(b.address, b.batteryMilliVolts + ' mV', b.temperatureC + ' °C');
});Arrêtez en quittant l'écran :
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});Champs de l'événement : chaque balise a type, rssi, address, timestamp ; iBeacon ajoute uuid, major, minor, txPower, distance ; Eddystone UID ajoute namespace, instance, txPower, distance ; URL ajoute url ; TLM ajoute batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtre les UUID iBeacon et les espaces de noms Eddystone (hexadécimal en minuscules).
Remarques : La distance est déduite de la puissance du signal et n'est fiable que pour proche / loin : les murs et les corps la modifient de plusieurs mètres. L'analyse dure jusqu'à stopScan() ou la fermeture de l'application.
bleConnect pont#
window.WebToApk.bleConnect(address: String)
Environnement d'exécution pour permBluetooth. Aucune option de l'assistant ne l'active : la compilation l'arme quand le code de la page appelle ces méthodes (ou Web Bluetooth). Avant cet environnement, les autorisations étaient déclarées sans que rien ne touche un capteur, exactement le schéma « déclaré mais inutilisé » que documente SmsBridge. Les résultats arrivent sous forme d'événements `appmint:ble` / window.onAppMintBle({kind, ...}).
Décrit avec son groupe, Capteurs de fitness BLE (fréquence cardiaque / vitesse / cadence / puissance / batterie), plutôt que séparément.
Exemple
Se connecte à un capteur de fitness trouvé par bleStartScan() et commence à diffuser ses mesures.
Retourne : rien. La progression et les données arrivent sous forme d'événements appmint:ble (et window.onAppMintBle) : {kind:'state', state:'connecting', address}, {kind:'state', state:'connected', address}, {kind:'state', state:'ready', services:[...]}, puis {kind:'data', type, data} pour chaque mesure. Nécessite : Bluetooth (activé par une compilation ZIP ou HTML lorsque votre code utilise le pont de capteurs) et l'autorisation Appareils à proximité, demandée à la première utilisation.
Passez l'address d'un événement device, depuis l'appui de l'utilisateur :
function connectSensor(address) {
if (!window.WebToApk || typeof window.WebToApk.bleConnect !== 'function') return;
window.WebToApk.bleConnect(address);
}
window.onAppMintBle = function (d) {
if (d.kind === 'state') {
// 'connecting' | 'connected' | 'ready' | 'disconnected' (also 'scanning' / 'scan_stopped')
showStatus(d.state);
} else if (d.kind === 'data') {
if (d.type === 'heart_rate') show('bpm', d.data.bpm);
if (d.type === 'speed_cadence') { // either key can be missing in one packet
if (d.data.speedKmh !== undefined) show('speed', d.data.speedKmh.toFixed(1) + ' km/h');
if (d.data.cadenceRpm !== undefined) show('cadence', Math.round(d.data.cadenceRpm) + ' rpm');
}
if (d.type === 'power') show('power', d.data.watts + ' W');
if (d.type === 'running') show('pace', d.data.speedKmh.toFixed(1) + ' km/h, ' + d.data.cadenceSpm + ' spm');
if (d.type === 'battery') show('battery', d.data.percent + '%');
} else if (d.kind === 'error') {
showStatus('Could not connect: ' + d.error);
}
};Mémorisez le capteur qui s'est connecté et reconnectez-vous-y la fois suivante sans analyse :
var SAVED_KEY = 'hrStrapAddress';
window.addEventListener('appmint:ble', function (e) {
var d = e.detail;
if (d.kind === 'state' && d.state === 'connected') localStorage.setItem(SAVED_KEY, d.address);
if (d.kind === 'error' && d.error === 'invalid_address') localStorage.removeItem(SAVED_KEY);
});
document.getElementById('start-workout').addEventListener('click', function () {
if (!window.WebToApk || typeof window.WebToApk.bleConnect !== 'function') return;
var address = localStorage.getItem(SAVED_KEY);
if (address) window.WebToApk.bleConnect(address);
else window.WebToApk.bleStartScan(); // first time: let the user pick a sensor
});Suivez une séance de fréquence cardiaque (moyenne, maximum, contact de la ceinture) à partir des mesures :
var beats = 0, sum = 0, max = 0;
window.addEventListener('appmint:ble', function (e) {
var d = e.detail;
if (d.kind === 'state' && d.state === 'ready' && d.services.length === 0) {
showStatus('This sensor has no heart rate, speed, power or battery service.');
}
if (d.kind !== 'data' || d.type !== 'heart_rate') return;
if (d.data.contact === false) { // only sent by straps that report skin contact
showStatus('Wet the strap: no skin contact');
return;
}
beats++; sum += d.data.bpm; max = Math.max(max, d.data.bpm);
show('bpm', d.data.bpm);
show('avg', Math.round(sum / beats));
show('max', max);
});Remarques : Un capteur à la fois : se connecter arrête toute analyse et déconnecte d'abord le capteur précédent (vous recevez son disconnected). ready.services liste les UUID complets des services pris en charge que ce capteur possède. Le premier paquet vitesse/cadence après la connexion n'envoie rien : la vitesse et la cadence nécessitent deux paquets pour être calculées. heart_rate contient aussi rrIntervalsMs (intervalles entre battements en ms, quand la ceinture les envoie), energyKj et contact lorsque la ceinture les indique ; power contient cadenceRpm à partir de son deuxième paquet quand le capteur envoie des données de manivelle. Erreurs : not_enabled, permission_denied, bluetooth_unavailable, invalid_address. Si le capteur sort de la portée, vous recevez {kind:'state', state:'disconnected', address}.
bleDisconnect pont#
window.WebToApk.bleDisconnect()
Environnement d'exécution pour permBluetooth. Aucune option de l'assistant ne l'active : la compilation l'arme quand le code de la page appelle ces méthodes (ou Web Bluetooth). Avant cet environnement, les autorisations étaient déclarées sans que rien ne touche un capteur, exactement le schéma « déclaré mais inutilisé » que documente SmsBridge. Les résultats arrivent sous forme d'événements `appmint:ble` / window.onAppMintBle({kind, ...}).
Décrit avec son groupe, Capteurs de fitness BLE (fréquence cardiaque / vitesse / cadence / puissance / batterie), plutôt que séparément.
Exemple
Déconnecte le capteur de fitness connecté avec bleConnect().
Retourne : rien. Si un capteur était connecté, un événement appmint:ble {kind:'state', state:'disconnected'} suit. Nécessite : Bluetooth (activé par une compilation ZIP ou HTML lorsque votre code utilise le pont de capteurs) ; sans lui, l'appel ne fait rien.
document.getElementById('end-workout').addEventListener('click', function () {
if (window.WebToApk && typeof window.WebToApk.bleDisconnect === 'function') {
window.WebToApk.bleDisconnect();
}
});
window.addEventListener('appmint:ble', function (e) {
if (e.detail.kind === 'state' && e.detail.state === 'disconnected') {
showStatus('Sensor disconnected');
}
});Reconnectez-vous automatiquement quand le capteur décroche, mais pas quand l'utilisateur a terminé l'entraînement :
var lastAddress = null, userEnded = false, retries = 0;
window.addEventListener('appmint:ble', function (e) {
var d = e.detail;
if (d.kind !== 'state') return;
if (d.state === 'connected') { lastAddress = d.address; userEnded = false; retries = 0; }
// Only a drop caused by the sensor carries an address.
if (d.state === 'disconnected' && d.address && !userEnded && lastAddress && retries < 3) {
retries++;
showStatus('Sensor lost, reconnecting (' + retries + '/3)...');
setTimeout(function () { window.WebToApk.bleConnect(lastAddress); }, 3000);
}
});
function endWorkout() {
userEnded = true;
if (window.WebToApk && typeof window.WebToApk.bleDisconnect === 'function') {
window.WebToApk.bleDisconnect();
}
}Déconnectez et oubliez le capteur enregistré depuis un écran de paramètres :
document.getElementById('forget-sensor').addEventListener('click', function () {
localStorage.removeItem('hrStrapAddress'); // wherever your app saved the address
if (window.WebToApk && typeof window.WebToApk.bleDisconnect === 'function') {
window.WebToApk.bleDisconnect();
}
showStatus('Sensor forgotten. Tap Scan to pair a new one.');
});Remarques : L'événement disconnected que vous provoquez vous-même n'a pas d'address ; celui provoqué par le capteur (hors de portée, éteint) en a une. L'application se déconnecte aussi quand elle se ferme.
bleSetWheelCircumference pont#
window.WebToApk.bleSetWheelCircumference(mm: Int)
Environnement d'exécution pour permBluetooth. Aucune option de l'assistant ne l'active : la compilation l'arme quand le code de la page appelle ces méthodes (ou Web Bluetooth). Avant cet environnement, les autorisations étaient déclarées sans que rien ne touche un capteur, exactement le schéma « déclaré mais inutilisé » que documente SmsBridge. Les résultats arrivent sous forme d'événements `appmint:ble` / window.onAppMintBle({kind, ...}).
Décrit avec son groupe, Capteurs de fitness BLE (fréquence cardiaque / vitesse / cadence / puissance / batterie), plutôt que séparément.
Exemple
Définit la taille de roue du vélo (circonférence en millimètres) utilisée pour convertir les tours de roue d'un capteur de vitesse en km/h.
Retourne : rien. Nécessite : rien pour l'appeler ; les mesures de vitesse elles-mêmes nécessitent un capteur de vitesse de vélo connecté (voir bleConnect).
// 2096 mm = 700x23c (the default). 2105 = 700x25c, 2136 = 700x28c, 2070 = 26x2.0 MTB.
function setWheel(mm) {
if (window.WebToApk && typeof window.WebToApk.bleSetWheelCircumference === 'function') {
window.WebToApk.bleSetWheelCircumference(mm);
}
}
document.getElementById('wheel').addEventListener('change', function (e) {
setWheel(parseInt(e.target.value, 10));
});Appliquez la taille de roue enregistrée du cycliste à chaque connexion, puisque le réglage ne survit pas à un redémarrage :
function connectBike(address) {
if (!window.WebToApk || typeof window.WebToApk.bleConnect !== 'function') return;
var mm = parseInt(localStorage.getItem('wheelMm'), 10) || 2096;
window.WebToApk.bleSetWheelCircumference(mm);
window.WebToApk.bleConnect(address);
}Étalonnez à partir d'un déroulé mesuré (un tour de roue complet, en cm) et vérifiez vous-même la plage, car une valeur hors plage est ignorée sans erreur :
document.getElementById('save-rollout').addEventListener('click', function () {
var mm = Math.round(parseFloat(document.getElementById('rollout-cm').value) * 10);
if (!(mm >= 500 && mm <= 4000)) {
showStatus('Enter a roll-out between 50 and 400 cm.');
return;
}
localStorage.setItem('wheelMm', String(mm));
if (window.WebToApk && typeof window.WebToApk.bleSetWheelCircumference === 'function') {
window.WebToApk.bleSetWheelCircumference(mm); // applies to the next speed reading
}
showStatus('Wheel set to ' + mm + ' mm');
});Remarques : Les valeurs hors de 500-4000 mm sont ignorées en silence (l'ancienne valeur reste). Le réglage dure jusqu'à la fermeture de l'application ; redéfinissez-le donc après chaque lancement, par exemple juste avant bleConnect(). Il modifie speedKmh dans les données speed_cadence de appmint:ble ; la cadence n'est pas affectée.
bleStartScan pont#
window.WebToApk.bleStartScan()
Environnement d'exécution pour permBluetooth. Aucune option de l'assistant ne l'active : la compilation l'arme quand le code de la page appelle ces méthodes (ou Web Bluetooth). Avant cet environnement, les autorisations étaient déclarées sans que rien ne touche un capteur, exactement le schéma « déclaré mais inutilisé » que documente SmsBridge. Les résultats arrivent sous forme d'événements `appmint:ble` / window.onAppMintBle({kind, ...}).
Décrit avec son groupe, Capteurs de fitness BLE (fréquence cardiaque / vitesse / cadence / puissance / batterie), plutôt que séparément.
Exemple
Recherche pendant 15 secondes les capteurs de fitness Bluetooth à proximité (fréquence cardiaque, vitesse/cadence de vélo, puissance, capteurs de course).
Retourne : rien. Les résultats arrivent sous forme d'événements appmint:ble (et window.onAppMintBle(detail)) : un {kind:'device', address, name, sensors, rssi} par capteur trouvé, plus {kind:'state', state:'scanning'} au début et {kind:'state', state:'scan_stopped'} à la fin. Nécessite : Bluetooth. Il n'y a pas d'option pour cela : quand vous compilez à partir d'un ZIP ou d'une page HTML, la compilation active Bluetooth d'elle-même si votre code appelle bleStartScan / bleConnect ou utilise navigator.bluetooth. Une compilation de site web (URL) ne peut pas l'activer. La première analyse demande à l'utilisateur l'autorisation Appareils à proximité (Localisation sur Android 11 et versions antérieures).
Écoutez d'abord, puis lancez l'analyse depuis un appui sur un bouton :
var found = {};
window.addEventListener('appmint:ble', function (e) {
var d = e.detail;
if (d.kind === 'device') {
found[d.address] = d;
// d.sensors: any of 'heart_rate', 'speed_cadence', 'power', 'running'
addRow(d.address, (d.name || 'Unnamed sensor') + ' ' + d.sensors.join(', ') + ' (' + d.rssi + ' dBm)');
} else if (d.kind === 'state' && d.state === 'scanning') {
showStatus('Looking for sensors...');
} else if (d.kind === 'state' && d.state === 'scan_stopped') {
showStatus(Object.keys(found).length ? 'Pick a sensor' : 'No sensors found. Wake the sensor and try again.');
} else if (d.kind === 'error') {
showStatus('Bluetooth error: ' + d.error);
}
});
document.getElementById('scan').addEventListener('click', function () {
if (window.WebToApk && typeof window.WebToApk.bleStartScan === 'function') {
found = {};
window.WebToApk.bleStartScan();
} else {
showStatus('Sensors work in the installed app only.');
}
});Appairez automatiquement la ceinture cardiaque au signal le plus fort à la fin de l'analyse :
var best = null, pairing = false;
window.addEventListener('appmint:ble', function (e) {
var d = e.detail;
if (!pairing) return;
if (d.kind === 'device' && d.sensors.indexOf('heart_rate') !== -1) {
if (!best || d.rssi > best.rssi) best = d; // closer strap = higher (less negative) rssi
} else if (d.kind === 'state' && d.state === 'scan_stopped') {
pairing = false;
if (best) window.WebToApk.bleConnect(best.address);
else showStatus('No heart-rate strap found. Put it on and try again.');
}
});
document.getElementById('pair-hr').addEventListener('click', function () {
if (!window.WebToApk || typeof window.WebToApk.bleStartScan !== 'function') return;
best = null;
pairing = true;
window.WebToApk.bleStartScan();
});Transformez chaque erreur d'analyse en un message sur lequel l'utilisateur peut agir :
var SCAN_HELP = {
not_enabled: 'This app was built without Bluetooth.',
permission_denied: 'Allow Nearby devices for this app in Settings to find sensors.',
bluetooth_unavailable: 'This phone has no Bluetooth.',
bluetooth_off: 'Turn Bluetooth on, then tap Scan again.',
scan_failed: 'The scan could not start. Wait a moment and try again.'
};
window.addEventListener('appmint:ble', function (e) {
var d = e.detail;
if (d.kind !== 'error') return;
var text = SCAN_HELP[d.error] || ('Bluetooth error: ' + d.error);
if (d.code !== undefined) text += ' (code ' + d.code + ')';
showStatus(text);
document.getElementById('scan').disabled = false;
});Remarques : Codes d'erreur dans {kind:'error', error} : not_enabled (la compilation n'a pas Bluetooth), permission_denied, bluetooth_unavailable (pas d'adaptateur), bluetooth_off, scan_failed (peut contenir le code Android). L'analyse ne signale que les appareils qui annoncent l'un des quatre services de fitness, et chaque appareil une seule fois par analyse. Lancer une nouvelle analyse arrête l'ancienne. Utilisez soit l'écouteur appmint:ble, soit window.onAppMintBle, pas les deux : les deux sont appelés pour chaque message.
bleStopScan pont#
window.WebToApk.bleStopScan()
Environnement d'exécution pour permBluetooth. Aucune option de l'assistant ne l'active : la compilation l'arme quand le code de la page appelle ces méthodes (ou Web Bluetooth). Avant cet environnement, les autorisations étaient déclarées sans que rien ne touche un capteur, exactement le schéma « déclaré mais inutilisé » que documente SmsBridge. Les résultats arrivent sous forme d'événements `appmint:ble` / window.onAppMintBle({kind, ...}).
Décrit avec son groupe, Capteurs de fitness BLE (fréquence cardiaque / vitesse / cadence / puissance / batterie), plutôt que séparément.
Exemple
Arrête une analyse de capteurs démarrée avec bleStartScan() avant la fin de ses 15 secondes.
Retourne : rien. Si une analyse était en cours, un événement appmint:ble {kind:'state', state:'scan_stopped'} suit. Nécessite : Bluetooth (activé par une compilation ZIP ou HTML lorsque votre code utilise le pont de capteurs) ; sans lui, l'appel ne fait rien.
window.addEventListener('appmint:ble', function (e) {
if (e.detail.kind === 'state' && e.detail.state === 'scan_stopped') {
document.getElementById('scan').disabled = false;
}
});
document.getElementById('stop-scan').addEventListener('click', function () {
if (window.WebToApk && typeof window.WebToApk.bleStopScan === 'function') {
window.WebToApk.bleStopScan();
}
});Arrêtez plus tôt dès que le type de capteur dont vous avez besoin apparaît :
window.addEventListener('appmint:ble', function (e) {
var d = e.detail;
if (d.kind === 'device' && d.sensors.indexOf('power') !== -1) {
if (window.WebToApk && typeof window.WebToApk.bleStopScan === 'function') {
window.WebToApk.bleStopScan(); // no need to wait the full 15 seconds
}
showPowerMeter(d.address, d.name || 'Power meter');
}
});Arrêtez l'analyse quand l'utilisateur ferme la feuille d'appairage ou quitte l'application :
function stopLooking() {
if (window.WebToApk && typeof window.WebToApk.bleStopScan === 'function') {
window.WebToApk.bleStopScan(); // safe even if the scan already ended
}
}
document.getElementById('close-pairing').addEventListener('click', function () {
stopLooking();
document.getElementById('pairing-sheet').hidden = true;
});
document.addEventListener('visibilitychange', function () {
if (document.hidden) stopLooking();
});Remarques : Vous en avez rarement besoin : l'analyse s'arrête toute seule après 15 secondes, et bleConnect() l'arrête aussi. L'appeler quand aucune analyse n'est en cours est sans danger et n'envoie aucun événement.