ساخت APK رایگان

API پل جاوااسکریپت

سنسورهای ورزشی BLE

ضربان قلب، سرعت، ریتم پدال‌زنی، توان و باتری از پروفایل‌های استاندارد Bluetooth Low Energy.

AppMint.beacons کمک‌کننده#

AppMint.beacons.startScan(options) / stopScan() / isScanning()

نمونه

beaconهای Bluetooth اطراف - iBeacon و Eddystone (UID، URL و TLM) - را پیدا می‌کند و تقریباً هر ثانیه یک‌بار دربارهٔ هرکدام از طریق رویداد appmint:beacon به صفحه می‌گوید، با قدرت سیگنال و یک فاصلهٔ تقریبی.

مقدار بازگشتی: startScan() ← یک Promise از {ok: true} یا {ok: false, code} (not_enabled، permission_denied، bluetooth_off، bluetooth_unavailable، scan_failed، blocked). stopScan() ← {ok: true}. isScanning() ← true/false. نیازها: چیزی برای تیک زدن نیست - ساختی که کدش beacons.startScan را فراخوانی کند مجوزهای اسکن Bluetooth و مکان دقیق را اعلام می‌کند (نتایج beacon برای Android دادهٔ مکان‌اند، پس از کاربر هر دو خواسته می‌شود و Play اپلیکیشن را به‌عنوان استفاده‌کنندهٔ مکان فهرست می‌کند).

beaconهای یک مکان را برد‌یابی کنید:

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، با تله‌متری باتری:

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');
});

وقتی از صفحه خارج می‌شوید متوقف کنید:

document.addEventListener('visibilitychange', async function () {
  if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});

فیلدهای رویداد: هر beacon دارای type، rssi، address، timestamp است؛ iBeacon uuid، major، minor، txPower، distance را اضافه می‌کند؛ Eddystone UID namespace، instance، txPower، distance را؛ URL url را؛ TLM batteryMilliVolts، temperatureC، advertCount، uptimeSeconds را. uuids UUIDهای iBeacon و فضای نام‌های Eddystone را فیلتر می‌کند (hex با حروف کوچک).

نکته‌ها: فاصله از قدرت سیگنال به دست می‌آید و فقط برای نزدیک / دور خوب است - دیوارها و بدن‌ها آن را چند متر تغییر می‌دهند. اسکن تا stopScan() یا بسته شدن اپلیکیشن ادامه می‌یابد.

beaconIsScanning پل#

window.WebToApk.beaconIsScanning(): Boolean

آیا اسکن beacon در جریان است.

نمونه

همراه با AppMint.beacons مستند شده - نمونهٔ آنجا این یکی را هم نشان می‌دهد.

beaconهای Bluetooth اطراف - iBeacon و Eddystone (UID، URL و TLM) - را پیدا می‌کند و تقریباً هر ثانیه یک‌بار دربارهٔ هرکدام از طریق رویداد appmint:beacon به صفحه می‌گوید، با قدرت سیگنال و یک فاصلهٔ تقریبی.

مقدار بازگشتی: startScan() ← یک Promise از {ok: true} یا {ok: false, code} (not_enabled، permission_denied، bluetooth_off، bluetooth_unavailable، scan_failed، blocked). stopScan() ← {ok: true}. isScanning() ← true/false. نیازها: چیزی برای تیک زدن نیست - ساختی که کدش beacons.startScan را فراخوانی کند مجوزهای اسکن Bluetooth و مکان دقیق را اعلام می‌کند (نتایج beacon برای Android دادهٔ مکان‌اند، پس از کاربر هر دو خواسته می‌شود و Play اپلیکیشن را به‌عنوان استفاده‌کنندهٔ مکان فهرست می‌کند).

beaconهای یک مکان را برد‌یابی کنید:

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، با تله‌متری باتری:

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');
});

وقتی از صفحه خارج می‌شوید متوقف کنید:

document.addEventListener('visibilitychange', async function () {
  if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});

فیلدهای رویداد: هر beacon دارای type، rssi، address، timestamp است؛ iBeacon uuid، major، minor، txPower، distance را اضافه می‌کند؛ Eddystone UID namespace، instance، txPower، distance را؛ URL url را؛ TLM batteryMilliVolts، temperatureC، advertCount، uptimeSeconds را. uuids UUIDهای iBeacon و فضای نام‌های Eddystone را فیلتر می‌کند (hex با حروف کوچک).

نکته‌ها: فاصله از قدرت سیگنال به دست می‌آید و فقط برای نزدیک / دور خوب است - دیوارها و بدن‌ها آن را چند متر تغییر می‌دهند. اسکن تا stopScan() یا بسته شدن اپلیکیشن ادامه می‌یابد.

beaconStartScan پل#

window.WebToApk.beaconStartScan(optionsJson: String, callbackId: String)

برد‌یابی beacon را با [optionsJson] `{uuids?, ibeacon?, eddystone?}` شروع می‌کند؛ [callbackId] را با `{ok}` یا `{ok:false, code}` تکمیل می‌کند.

نمونه

همراه با AppMint.beacons مستند شده - نمونهٔ آنجا این یکی را هم نشان می‌دهد.

beaconهای Bluetooth اطراف - iBeacon و Eddystone (UID، URL و TLM) - را پیدا می‌کند و تقریباً هر ثانیه یک‌بار دربارهٔ هرکدام از طریق رویداد appmint:beacon به صفحه می‌گوید، با قدرت سیگنال و یک فاصلهٔ تقریبی.

مقدار بازگشتی: startScan() ← یک Promise از {ok: true} یا {ok: false, code} (not_enabled، permission_denied، bluetooth_off، bluetooth_unavailable، scan_failed، blocked). stopScan() ← {ok: true}. isScanning() ← true/false. نیازها: چیزی برای تیک زدن نیست - ساختی که کدش beacons.startScan را فراخوانی کند مجوزهای اسکن Bluetooth و مکان دقیق را اعلام می‌کند (نتایج beacon برای Android دادهٔ مکان‌اند، پس از کاربر هر دو خواسته می‌شود و Play اپلیکیشن را به‌عنوان استفاده‌کنندهٔ مکان فهرست می‌کند).

beaconهای یک مکان را برد‌یابی کنید:

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، با تله‌متری باتری:

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');
});

وقتی از صفحه خارج می‌شوید متوقف کنید:

document.addEventListener('visibilitychange', async function () {
  if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});

فیلدهای رویداد: هر beacon دارای type، rssi، address، timestamp است؛ iBeacon uuid، major، minor، txPower، distance را اضافه می‌کند؛ Eddystone UID namespace، instance، txPower، distance را؛ URL url را؛ TLM batteryMilliVolts، temperatureC، advertCount، uptimeSeconds را. uuids UUIDهای iBeacon و فضای نام‌های Eddystone را فیلتر می‌کند (hex با حروف کوچک).

نکته‌ها: فاصله از قدرت سیگنال به دست می‌آید و فقط برای نزدیک / دور خوب است - دیوارها و بدن‌ها آن را چند متر تغییر می‌دهند. اسکن تا stopScan() یا بسته شدن اپلیکیشن ادامه می‌یابد.

beaconStopScan پل#

window.WebToApk.beaconStopScan(callbackId: String)

برد‌یابی beacon را متوقف می‌کند؛ [callbackId] را با `{ok:true}` تکمیل می‌کند.

نمونه

همراه با AppMint.beacons مستند شده - نمونهٔ آنجا این یکی را هم نشان می‌دهد.

beaconهای Bluetooth اطراف - iBeacon و Eddystone (UID، URL و TLM) - را پیدا می‌کند و تقریباً هر ثانیه یک‌بار دربارهٔ هرکدام از طریق رویداد appmint:beacon به صفحه می‌گوید، با قدرت سیگنال و یک فاصلهٔ تقریبی.

مقدار بازگشتی: startScan() ← یک Promise از {ok: true} یا {ok: false, code} (not_enabled، permission_denied، bluetooth_off، bluetooth_unavailable، scan_failed، blocked). stopScan() ← {ok: true}. isScanning() ← true/false. نیازها: چیزی برای تیک زدن نیست - ساختی که کدش beacons.startScan را فراخوانی کند مجوزهای اسکن Bluetooth و مکان دقیق را اعلام می‌کند (نتایج beacon برای Android دادهٔ مکان‌اند، پس از کاربر هر دو خواسته می‌شود و Play اپلیکیشن را به‌عنوان استفاده‌کنندهٔ مکان فهرست می‌کند).

beaconهای یک مکان را برد‌یابی کنید:

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، با تله‌متری باتری:

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');
});

وقتی از صفحه خارج می‌شوید متوقف کنید:

document.addEventListener('visibilitychange', async function () {
  if (document.visibilityState === 'hidden' && await AppMint.beacons.isScanning()) AppMint.beacons.stopScan();
});

فیلدهای رویداد: هر beacon دارای type، rssi، address، timestamp است؛ iBeacon uuid، major، minor، txPower، distance را اضافه می‌کند؛ Eddystone UID namespace، instance، txPower، distance را؛ URL url را؛ TLM batteryMilliVolts، temperatureC، advertCount، uptimeSeconds را. uuids UUIDهای iBeacon و فضای نام‌های Eddystone را فیلتر می‌کند (hex با حروف کوچک).

نکته‌ها: فاصله از قدرت سیگنال به دست می‌آید و فقط برای نزدیک / دور خوب است - دیوارها و بدن‌ها آن را چند متر تغییر می‌دهند. اسکن تا stopScan() یا بسته شدن اپلیکیشن ادامه می‌یابد.

bleConnect پل#

window.WebToApk.bleConnect(address: String)

زمان اجرا برای permBluetooth. هیچ کلید جادوگری آن را تنظیم نمی‌کند: ساخت وقتی کد خود صفحه این متدها (یا Web Bluetooth) را فراخوانی کند آن را فعال می‌کند. پیش از این زمان اجرا، مجوزها اعلام می‌شدند در حالی که هیچ چیز در زمان اجرا به سنسور دست نمی‌زد، همان الگوی اعلام‌شده‌اما‌مرده‌ای که SmsBridge مستند می‌کند. نتایج به‌صورت رویدادهای `appmint:ble` / window.onAppMintBle({kind, ...}) جریان می‌یابند.

به‌جای خودش، با گروهش توضیح داده شده است، سنسورهای ورزشی BLE (ضربان قلب / سرعت / ریتم / توان / باتری).

نمونه

به یک سنسور ورزشی که bleStartScan() پیدا کرده وصل می‌شود و پخش قرائت‌هایش را شروع می‌کند.

مقدار بازگشتی: هیچ. پیشرفت و داده به‌صورت رویدادهای appmint:ble (و window.onAppMintBle) می‌رسند: {kind:'state', state:'connecting', address}، {kind:'state', state:'connected', address}، {kind:'state', state:'ready', services:[...]}، سپس {kind:'data', type, data} برای هر قرائت. نیازها: Bluetooth (وقتی کدتان از پل سنسور استفاده کند، ساخت ZIP یا HTML آن را روشن می‌کند) و مجوز دستگاه‌های اطراف که در اولین استفاده خواسته می‌شود.

address را از یک رویداد device بدهید، از لمس کاربر:

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);
  }
};

سنسوری را که وصل شد به خاطر بسپارید و دفعهٔ بعد بدون اسکن دوباره به آن وصل شوید:

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
});

یک جلسهٔ ضربان قلب (میانگین، حداکثر، تماس نوار) را از قرائت‌ها دنبال کنید:

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);
});

نکته‌ها: هر بار یک سنسور: اتصال هر اسکن را متوقف می‌کند و ابتدا سنسور قبلی را قطع می‌کند (disconnected آن را می‌گیرید). ready.services UUIDهای کامل سرویس‌های پشتیبانی‌شدهٔ این سنسور را فهرست می‌کند. اولین بستهٔ سرعت/ریتم پس از اتصال چیزی نمی‌فرستد - سرعت و ریتم برای محاسبه به دو بسته نیاز دارند. heart_rate هم rrIntervalsMs (فاصله‌های ضربه به ضربه به ms، وقتی نوار می‌فرستد)، energyKj و contact را وقتی نوار گزارش می‌کند حمل می‌کند؛ power از بستهٔ دوم به بعد cadenceRpm را وقتی سنج داده‌های میل‌لنگ بفرستد حمل می‌کند. خطاها: not_enabled، permission_denied، bluetooth_unavailable، invalid_address. اگر سنسور از برد خارج شود می‌گیرید {kind:'state', state:'disconnected', address}.

bleDisconnect پل#

window.WebToApk.bleDisconnect()

زمان اجرا برای permBluetooth. هیچ کلید جادوگری آن را تنظیم نمی‌کند: ساخت وقتی کد خود صفحه این متدها (یا Web Bluetooth) را فراخوانی کند آن را فعال می‌کند. پیش از این زمان اجرا، مجوزها اعلام می‌شدند در حالی که هیچ چیز در زمان اجرا به سنسور دست نمی‌زد، همان الگوی اعلام‌شده‌اما‌مرده‌ای که SmsBridge مستند می‌کند. نتایج به‌صورت رویدادهای `appmint:ble` / window.onAppMintBle({kind, ...}) جریان می‌یابند.

به‌جای خودش، با گروهش توضیح داده شده است، سنسورهای ورزشی BLE (ضربان قلب / سرعت / ریتم / توان / باتری).

نمونه

سنسور ورزشی‌ای را که با bleConnect().

مقدار بازگشتی: هیچ. اگر سنسوری متصل بود، رویداد appmint:ble {kind:'state', state:'disconnected'} می‌آید. نیازها: Bluetooth (وقتی کدتان از پل سنسور استفاده کند، ساخت ZIP یا HTML آن را روشن می‌کند)؛ بدون آن فراخوانی کاری نمی‌کند.

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');
  }
});

وقتی سنسور قطع شد خودکار دوباره وصل شوید، اما نه وقتی کاربر تمرین را تمام کرده است:

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();
  }
}

سنسور ذخیره‌شده را از یک صفحهٔ تنظیمات قطع کنید و فراموش کنید:

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.');
});

نکته‌ها: رویداد disconnected که خودتان ایجاد می‌کنید address ندارد؛ رویدادی که سنسور ایجاد کرده (خارج از برد، خاموش شده) دارد. اپلیکیشن وقتی بسته می‌شود هم قطع می‌کند.

bleSetWheelCircumference پل#

window.WebToApk.bleSetWheelCircumference(mm: Int)

زمان اجرا برای permBluetooth. هیچ کلید جادوگری آن را تنظیم نمی‌کند: ساخت وقتی کد خود صفحه این متدها (یا Web Bluetooth) را فراخوانی کند آن را فعال می‌کند. پیش از این زمان اجرا، مجوزها اعلام می‌شدند در حالی که هیچ چیز در زمان اجرا به سنسور دست نمی‌زد، همان الگوی اعلام‌شده‌اما‌مرده‌ای که SmsBridge مستند می‌کند. نتایج به‌صورت رویدادهای `appmint:ble` / window.onAppMintBle({kind, ...}) جریان می‌یابند.

به‌جای خودش، با گروهش توضیح داده شده است، سنسورهای ورزشی BLE (ضربان قلب / سرعت / ریتم / توان / باتری).

نمونه

اندازهٔ چرخ دوچرخه (محیط به میلی‌متر) را که برای تبدیل چرخش‌های چرخ سنسور سرعت به km/h استفاده می‌شود تنظیم می‌کند.

مقدار بازگشتی: هیچ. نیازها: برای فراخوانی هیچ؛ خود قرائت‌های سرعت یک سنسور سرعت دوچرخهٔ متصل می‌خواهند (ببینید 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));
});

اندازهٔ چرخ ذخیره‌شدهٔ دوچرخه‌سوار را در هر اتصال اعمال کنید، چون تنظیم پس از راه‌اندازی مجدد نمی‌ماند:

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);
}

از یک غلتش اندازه‌گیری‌شده (یک دور کامل چرخ، به cm) کالیبره کنید و بازه را خودتان بررسی کنید، چون مقدار خارج از بازه بدون خطا نادیده گرفته می‌شود:

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');
});

نکته‌ها: مقدارهای بیرون از ۵۰۰ تا ۴۰۰۰ میلی‌متر بی‌صدا نادیده گرفته می‌شوند (مقدار قبلی می‌ماند). تنظیم تا بسته شدن اپلیکیشن می‌ماند، پس پس از هر راه‌اندازی دوباره تنظیمش کنید، مثلاً درست پیش از bleConnect(). speedKmh را در دادهٔ speed_cadence مربوط به appmint:ble تغییر می‌دهد؛ ریتم پدال‌زنی تحت تأثیر نیست.

bleStartScan پل#

window.WebToApk.bleStartScan()

زمان اجرا برای permBluetooth. هیچ کلید جادوگری آن را تنظیم نمی‌کند: ساخت وقتی کد خود صفحه این متدها (یا Web Bluetooth) را فراخوانی کند آن را فعال می‌کند. پیش از این زمان اجرا، مجوزها اعلام می‌شدند در حالی که هیچ چیز در زمان اجرا به سنسور دست نمی‌زد، همان الگوی اعلام‌شده‌اما‌مرده‌ای که SmsBridge مستند می‌کند. نتایج به‌صورت رویدادهای `appmint:ble` / window.onAppMintBle({kind, ...}) جریان می‌یابند.

به‌جای خودش، با گروهش توضیح داده شده است، سنسورهای ورزشی BLE (ضربان قلب / سرعت / ریتم / توان / باتری).

نمونه

سنسورهای ورزشی Bluetooth اطراف (ضربان قلب، سرعت/ریتم دوچرخه، توان، footpodهای دویدن) را به مدت ۱۵ ثانیه اسکن می‌کند.

مقدار بازگشتی: هیچ. نتایج به‌صورت رویدادهای appmint:ble (و window.onAppMintBle(detail)) می‌رسند: یک {kind:'device', address, name, sensors, rssi} برای هر سنسور یافت‌شده، به‌علاوهٔ {kind:'state', state:'scanning'} در شروع و {kind:'state', state:'scan_stopped'} در پایان. نیازها: Bluetooth. برای آن کلیدی نیست: وقتی از ZIP یا صفحهٔ HTML می‌سازید، اگر کدتان bleStartScan / bleConnect را فراخوانی کند یا از navigator.bluetooth استفاده کند، ساخت خودش Bluetooth را روشن می‌کند. ساخت وب‌سایت (URL) نمی‌تواند آن را روشن کند. اولین اسکن از کاربر مجوز دستگاه‌های اطراف را می‌خواهد (در Android 11 و قدیمی‌تر مکان).

اول گوش بدهید، سپس از لمس یک دکمه اسکن کنید:

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.');
  }
});

وقتی اسکن تمام می‌شود، قوی‌ترین نوار ضربان قلب را خودکار جفت کنید:

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();
});

هر خطای اسکن را به پیامی تبدیل کنید که کاربر بتواند به آن عمل کند:

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;
});

نکته‌ها: کدهای خطا در {kind:'error', error}: not_enabled (ساخت Bluetooth ندارد)، permission_denied، bluetooth_unavailable (بدون آداپتور)، bluetooth_off، scan_failed (ممکن است code Android را داشته باشد). اسکن فقط دستگاه‌هایی را گزارش می‌کند که یکی از چهار سرویس ورزشی را تبلیغ می‌کنند، و هر دستگاه فقط یک‌بار در هر اسکن. شروع اسکن جدید قبلی را متوقف می‌کند. یا شنوندهٔ appmint:ble یا window.onAppMintBle را استفاده کنید، نه هر دو - هر دو برای هر پیام فراخوانی می‌شوند.

bleStopScan پل#

window.WebToApk.bleStopScan()

زمان اجرا برای permBluetooth. هیچ کلید جادوگری آن را تنظیم نمی‌کند: ساخت وقتی کد خود صفحه این متدها (یا Web Bluetooth) را فراخوانی کند آن را فعال می‌کند. پیش از این زمان اجرا، مجوزها اعلام می‌شدند در حالی که هیچ چیز در زمان اجرا به سنسور دست نمی‌زد، همان الگوی اعلام‌شده‌اما‌مرده‌ای که SmsBridge مستند می‌کند. نتایج به‌صورت رویدادهای `appmint:ble` / window.onAppMintBle({kind, ...}) جریان می‌یابند.

به‌جای خودش، با گروهش توضیح داده شده است، سنسورهای ورزشی BLE (ضربان قلب / سرعت / ریتم / توان / باتری).

نمونه

اسکن سنسوری را که با bleStartScan() شروع شده پیش از تمام شدن ۱۵ ثانیه‌اش متوقف می‌کند.

مقدار بازگشتی: هیچ. اگر اسکنی در جریان بود، رویداد appmint:ble {kind:'state', state:'scan_stopped'} می‌آید. نیازها: Bluetooth (وقتی کدتان از پل سنسور استفاده کند، ساخت ZIP یا HTML آن را روشن می‌کند)؛ بدون آن فراخوانی کاری نمی‌کند.

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();
  }
});

به‌محض اینکه نوع سنسور مورد نیازتان ظاهر شد، زودتر متوقف کنید:

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');
  }
});

وقتی کاربر برگهٔ جفت‌سازی را می‌بندد یا از اپلیکیشن خارج می‌شود، اسکن را متوقف کنید:

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();
});

نکته‌ها: به ندرت به این نیاز دارید: اسکن پس از ۱۵ ثانیه خودش متوقف می‌شود و bleConnect() هم آن را متوقف می‌کند. فراخوانی آن وقتی اسکنی در جریان نیست بی‌خطر است و رویدادی نمی‌فرستد.