API da ponte JavaScript
Sensores de fitness BLE
Frequência cardíaca, velocidade, cadência, potência e bateria a partir de perfis padrão de Bluetooth Low Energy.
AppMint.beacons helper#
AppMint.beacons.startScan(options) / stopScan() / isScanning()
Exemplo
Encontra beacons Bluetooth próximos - iBeacon e Eddystone (UID, URL e TLM) - e informa a página sobre cada um cerca de uma vez por segundo por meio do evento appmint:beacon, com a intensidade do sinal e uma distância aproximada.
Retorna: startScan() → uma 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. Requer: nada a marcar - um build cujo código chama beacons.startScan declara as permissões de busca Bluetooth e de localização precisa (os resultados de beacons são dados de localização para o Android, então o usuário é perguntado por ambas, e o Play lista o app como usando localização).
Rastreie os beacons de um local:
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);
}Somente Eddystone, com telemetria de bateria:
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');
});Pare quando a tela for deixada:
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});Campos do evento: todo beacon tem type, rssi, address, timestamp; o iBeacon adiciona uuid, major, minor, txPower, distance; o Eddystone UID adiciona namespace, instance, txPower, distance; o URL adiciona url; o TLM adiciona batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtra UUIDs de iBeacon e namespaces Eddystone (hex em minúsculas).
Observações: A distância vem da intensidade do sinal e só serve para perto / longe - paredes e corpos a alteram em metros. A busca continua até stopScan() ou até o app fechar.
beaconIsScanning ponte#
window.WebToApk.beaconIsScanning(): Boolean
Se uma busca de beacons está em andamento.
Exemplo
Documentado junto com AppMint.beacons - o exemplo de lá mostra este também.
Encontra beacons Bluetooth próximos - iBeacon e Eddystone (UID, URL e TLM) - e informa a página sobre cada um cerca de uma vez por segundo por meio do evento appmint:beacon, com a intensidade do sinal e uma distância aproximada.
Retorna: startScan() → uma 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. Requer: nada a marcar - um build cujo código chama beacons.startScan declara as permissões de busca Bluetooth e de localização precisa (os resultados de beacons são dados de localização para o Android, então o usuário é perguntado por ambas, e o Play lista o app como usando localização).
Rastreie os beacons de um local:
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);
}Somente Eddystone, com telemetria de bateria:
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');
});Pare quando a tela for deixada:
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});Campos do evento: todo beacon tem type, rssi, address, timestamp; o iBeacon adiciona uuid, major, minor, txPower, distance; o Eddystone UID adiciona namespace, instance, txPower, distance; o URL adiciona url; o TLM adiciona batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtra UUIDs de iBeacon e namespaces Eddystone (hex em minúsculas).
Observações: A distância vem da intensidade do sinal e só serve para perto / longe - paredes e corpos a alteram em metros. A busca continua até stopScan() ou até o app fechar.
beaconStartScan ponte#
window.WebToApk.beaconStartScan(optionsJson: String, callbackId: String)
Inicia o rastreamento de beacons com [optionsJson] `{uuids?, ibeacon?, eddystone?}`; resolve [callbackId] com `{ok}` ou `{ok:false, code}`.
Exemplo
Documentado junto com AppMint.beacons - o exemplo de lá mostra este também.
Encontra beacons Bluetooth próximos - iBeacon e Eddystone (UID, URL e TLM) - e informa a página sobre cada um cerca de uma vez por segundo por meio do evento appmint:beacon, com a intensidade do sinal e uma distância aproximada.
Retorna: startScan() → uma 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. Requer: nada a marcar - um build cujo código chama beacons.startScan declara as permissões de busca Bluetooth e de localização precisa (os resultados de beacons são dados de localização para o Android, então o usuário é perguntado por ambas, e o Play lista o app como usando localização).
Rastreie os beacons de um local:
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);
}Somente Eddystone, com telemetria de bateria:
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');
});Pare quando a tela for deixada:
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});Campos do evento: todo beacon tem type, rssi, address, timestamp; o iBeacon adiciona uuid, major, minor, txPower, distance; o Eddystone UID adiciona namespace, instance, txPower, distance; o URL adiciona url; o TLM adiciona batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtra UUIDs de iBeacon e namespaces Eddystone (hex em minúsculas).
Observações: A distância vem da intensidade do sinal e só serve para perto / longe - paredes e corpos a alteram em metros. A busca continua até stopScan() ou até o app fechar.
beaconStopScan ponte#
window.WebToApk.beaconStopScan(callbackId: String)
Para o rastreamento de beacons; resolve [callbackId] com `{ok:true}`.
Exemplo
Documentado junto com AppMint.beacons - o exemplo de lá mostra este também.
Encontra beacons Bluetooth próximos - iBeacon e Eddystone (UID, URL e TLM) - e informa a página sobre cada um cerca de uma vez por segundo por meio do evento appmint:beacon, com a intensidade do sinal e uma distância aproximada.
Retorna: startScan() → uma 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. Requer: nada a marcar - um build cujo código chama beacons.startScan declara as permissões de busca Bluetooth e de localização precisa (os resultados de beacons são dados de localização para o Android, então o usuário é perguntado por ambas, e o Play lista o app como usando localização).
Rastreie os beacons de um local:
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);
}Somente Eddystone, com telemetria de bateria:
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');
});Pare quando a tela for deixada:
document.addEventListener('visibilitychange', async function () {
if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});Campos do evento: todo beacon tem type, rssi, address, timestamp; o iBeacon adiciona uuid, major, minor, txPower, distance; o Eddystone UID adiciona namespace, instance, txPower, distance; o URL adiciona url; o TLM adiciona batteryMilliVolts, temperatureC, advertCount, uptimeSeconds. uuids filtra UUIDs de iBeacon e namespaces Eddystone (hex em minúsculas).
Observações: A distância vem da intensidade do sinal e só serve para perto / longe - paredes e corpos a alteram em metros. A busca continua até stopScan() ou até o app fechar.
bleConnect ponte#
window.WebToApk.bleConnect(address: String)
Runtime para permBluetooth. Nenhuma opção do assistente o ativa: o build o arma quando o próprio código da página chama estes métodos (ou o Web Bluetooth). Antes deste runtime as permissões eram declaradas sem que nada no runtime tocasse um sensor, exatamente o padrão declarado-mas-morto que o SmsBridge documenta. Os resultados chegam como eventos `appmint:ble` / window.onAppMintBle({kind, ...}).
Descrito pelo seu grupo, Sensores de fitness BLE (frequência cardíaca / velocidade / cadência / potência / bateria), e não por conta própria.
Exemplo
Conecta a um sensor de fitness encontrado por bleStartScan() e começa a transmitir suas leituras.
Retorna: nada. O progresso e os dados chegam como eventos appmint:ble (e window.onAppMintBle): {kind:'state', state:'connecting', address}, {kind:'state', state:'connected', address}, {kind:'state', state:'ready', services:[...]}, depois {kind:'data', type, data} para cada leitura. Requer: Bluetooth (ativado por um build de ZIP ou HTML quando seu código usa a ponte de sensores) e a permissão de Dispositivos próximos, pedida no primeiro uso.
Passe o address de um evento device, a partir do toque do usuário:
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);
}
};Lembre o sensor que conectou e reconecte a ele da próxima vez sem uma busca:
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
});Acompanhe uma sessão de frequência cardíaca (média, máxima, contato da cinta) a partir das leituras:
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);
});Observações: Um sensor por vez: conectar para qualquer busca e derruba antes o sensor anterior (você recebe o disconnected dele). ready.services lista os UUIDs completos dos serviços suportados que este sensor tem. O primeiro pacote de velocidade/cadência após conectar não envia nada - velocidade e cadência precisam de dois pacotes para serem calculadas. heart_rate também traz rrIntervalsMs (intervalos batimento a batimento em ms, quando a cinta os envia), energyKj e contact quando a cinta os informa; power traz cadenceRpm a partir do segundo pacote quando o medidor envia dados de pedivela. Erros: not_enabled, permission_denied, bluetooth_unavailable, invalid_address. Se o sensor sair do alcance você recebe {kind:'state', state:'disconnected', address}.
bleDisconnect ponte#
window.WebToApk.bleDisconnect()
Runtime para permBluetooth. Nenhuma opção do assistente o ativa: o build o arma quando o próprio código da página chama estes métodos (ou o Web Bluetooth). Antes deste runtime as permissões eram declaradas sem que nada no runtime tocasse um sensor, exatamente o padrão declarado-mas-morto que o SmsBridge documenta. Os resultados chegam como eventos `appmint:ble` / window.onAppMintBle({kind, ...}).
Descrito pelo seu grupo, Sensores de fitness BLE (frequência cardíaca / velocidade / cadência / potência / bateria), e não por conta própria.
Exemplo
Desconecta o sensor de fitness conectado com bleConnect().
Retorna: nada. Se um sensor estava conectado, um evento appmint:ble {kind:'state', state:'disconnected'} se segue. Requer: Bluetooth (ativado por um build de ZIP ou HTML quando seu código usa a ponte de sensores); sem ele a chamada não faz nada.
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');
}
});Reconecte sozinho quando o sensor cair, mas não quando o usuário encerrou o treino:
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();
}
}Desconecte e esqueça o sensor salvo a partir de uma tela de configurações:
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.');
});Observações: O evento disconnected que você mesmo causa não tem address; um causado pelo sensor (fora de alcance, desligado) o tem. O app também desconecta quando fecha.
bleSetWheelCircumference ponte#
window.WebToApk.bleSetWheelCircumference(mm: Int)
Runtime para permBluetooth. Nenhuma opção do assistente o ativa: o build o arma quando o próprio código da página chama estes métodos (ou o Web Bluetooth). Antes deste runtime as permissões eram declaradas sem que nada no runtime tocasse um sensor, exatamente o padrão declarado-mas-morto que o SmsBridge documenta. Os resultados chegam como eventos `appmint:ble` / window.onAppMintBle({kind, ...}).
Descrito pelo seu grupo, Sensores de fitness BLE (frequência cardíaca / velocidade / cadência / potência / bateria), e não por conta própria.
Exemplo
Define o tamanho da roda da bicicleta (circunferência em milímetros) usado para converter as voltas da roda de um sensor de velocidade em km/h.
Retorna: nada. Requer: nada para chamá-lo; as próprias leituras de velocidade precisam de um sensor de velocidade de ciclismo conectado (veja 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));
});Aplique o tamanho de roda salvo do ciclista toda vez que conectar, já que a configuração não sobrevive a uma reinicialização:
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);
}Calibre a partir de um rolamento medido (uma volta completa da roda, em cm) e verifique a faixa você mesmo, porque um valor fora da faixa é ignorado sem erro:
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');
});Observações: Valores fora de 500-4000 mm são ignorados silenciosamente (o valor antigo permanece). A configuração dura até o app fechar, então defina-a de novo a cada inicialização, por exemplo logo antes de bleConnect(). Ela altera speedKmh nos dados speed_cadence de appmint:ble; a cadência não é afetada.
bleStartScan ponte#
window.WebToApk.bleStartScan()
Runtime para permBluetooth. Nenhuma opção do assistente o ativa: o build o arma quando o próprio código da página chama estes métodos (ou o Web Bluetooth). Antes deste runtime as permissões eram declaradas sem que nada no runtime tocasse um sensor, exatamente o padrão declarado-mas-morto que o SmsBridge documenta. Os resultados chegam como eventos `appmint:ble` / window.onAppMintBle({kind, ...}).
Descrito pelo seu grupo, Sensores de fitness BLE (frequência cardíaca / velocidade / cadência / potência / bateria), e não por conta própria.
Exemplo
Busca sensores de fitness Bluetooth próximos (frequência cardíaca, velocidade/cadência de ciclismo, potência, footpods de corrida) por 15 segundos.
Retorna: nada. Os resultados chegam como eventos appmint:ble (e window.onAppMintBle(detail)): um {kind:'device', address, name, sensors, rssi} por sensor encontrado, mais {kind:'state', state:'scanning'} no início e {kind:'state', state:'scan_stopped'} no fim. Requer: Bluetooth. Não há opção para isso: quando você compila a partir de um ZIP ou de uma página HTML, o build ativa o Bluetooth sozinho se seu código chama bleStartScan / bleConnect ou usa navigator.bluetooth. Um build de site (URL) não pode ativá-lo. A primeira busca pede ao usuário a permissão de Dispositivos próximos (Localização no Android 11 e anteriores).
Escute primeiro, depois faça a busca a partir do toque em um botão:
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.');
}
});Pareie automaticamente a cinta de frequência cardíaca mais forte quando a busca terminar:
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();
});Transforme cada erro de busca em uma mensagem que o usuário possa seguir:
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;
});Observações: Códigos de erro em {kind:'error', error}: not_enabled (o build não tem Bluetooth), permission_denied, bluetooth_unavailable (sem adaptador), bluetooth_off, scan_failed (pode trazer o code do Android). A busca só reporta dispositivos que anunciam um dos quatro serviços de fitness, e cada dispositivo apenas uma vez por busca. Iniciar uma nova busca para a antiga. Use o listener appmint:ble ou window.onAppMintBle, não os dois - ambos são chamados para cada mensagem.
bleStopScan ponte#
window.WebToApk.bleStopScan()
Runtime para permBluetooth. Nenhuma opção do assistente o ativa: o build o arma quando o próprio código da página chama estes métodos (ou o Web Bluetooth). Antes deste runtime as permissões eram declaradas sem que nada no runtime tocasse um sensor, exatamente o padrão declarado-mas-morto que o SmsBridge documenta. Os resultados chegam como eventos `appmint:ble` / window.onAppMintBle({kind, ...}).
Descrito pelo seu grupo, Sensores de fitness BLE (frequência cardíaca / velocidade / cadência / potência / bateria), e não por conta própria.
Exemplo
Para uma busca de sensores iniciada com bleStartScan() antes de seus 15 segundos acabarem.
Retorna: nada. Se uma busca estava em andamento, um evento appmint:ble {kind:'state', state:'scan_stopped'} se segue. Requer: Bluetooth (ativado por um build de ZIP ou HTML quando seu código usa a ponte de sensores); sem ele a chamada não faz nada.
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();
}
});Pare mais cedo assim que o tipo de sensor de que você precisa aparecer:
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');
}
});Pare a busca quando o usuário fechar a folha de pareamento ou sair do app:
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();
});Observações: Você raramente precisa disto: a busca para sozinha após 15 segundos, e bleConnect() também a para. Chamar quando nenhuma busca está em andamento é seguro e não envia evento.