はじめに
2020年7月頃、Macの Swift Playgrounds で、10秒間、周辺の新型コロナウイルス接触確認アプリ(COCOA)がインストールされているスマホを数えるコードを書きました。
iOSアプリ版も作成したのですが、iOS13以上ではCOCOAが検知できなくなっています。
今回、同様なことを javascript で書くチャレンジです。
コロナ接触確認アプリの利用状況を調べるアプリを作ってみた pic.twitter.com/BZYXcFm9Mo
— Sam Akada@HomeKit (@sam_akada) July 12, 2020
Swiftコード
import UIKit
import CoreBluetooth
import PlaygroundSupport
class ViewController: UIViewController, CBCentralManagerDelegate {
var centralManager: CBCentralManager?
let scanTime: Double = 10 // seconds
let label = UILabel()
var count = 0
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
label.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height/4)
label.center = view.center
label.textAlignment = .left
label.font = label.font.withSize(100)
label.text = "-"
self.view.addSubview(label)
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func scanStart() {
if centralManager!.isScanning == false {
let service = CBUUID(string: "fd6f")
self.centralManager?.scanForPeripherals(withServices: [service], options: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + scanTime) {
self.centralManager?.stopScan()
self.label.text = "\(self.count)"
self.count = 0
self.scanStart()
}
}
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch (central.state) {
case .poweredOn:
scanStart()
case .unknown:
break
case .resetting:
break
case .unsupported:
break
case .unauthorized:
break
case .poweredOff:
break
@unknown default:
break
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral.identifier)
count += 1
}
}
PlaygroundPage.current.liveView = ViewController()
macOS Catalina, iPadOS 12のSwift Playgroundsでは、COCOAを検知できますが、macOS Monterey, iPadOS 13以上では、検知できなくなりました。
事前調査
- node.js v8の古いバージョンでは、nobleのモジュールを使った、BLEの事例があった。
- openSSLの脆弱性を考慮すると、新しいバージョンを使いたい。
- できるだけ新しいバージョンのnode.jsでBLEを使う時、アバンダンウェアプロジェクト (Abandonware) のnobleを使うらしい。
- node.jsの公式サイトには、ARMv6のバイナリがない。
環境
- Raspberry Pi Zero (CPU ARMv6)
- Raspberry Pi OS Lite 32bit January 28th 2022 (bullseye)
- node.js v17.7.2
nodejsのインストール
~/.profile に環境変数を追加します。
VERSION=v17.7.2
DISTRO=linux-armv6l
export PATH=/usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin:$PATH
※VERSIONを書き換えることで、違うバージョンのnodejsをインストールできます。
環境変数を反映します。
. ~/.profile
nodejs公式サイトには、ARMv6のバイナリビルドがないため、非公式ビルドサイトからダウンロードします。
curl -OL https://unofficial-builds.nodejs.org/download/release/$VERSION/node-$VERSION-$DISTRO.tar.gz
ファイルを展開します。
sudo mkdir -p /usr/local/lib/nodejs
sudo tar -zxvf node-v16.14.2-linux-armv6l.tar.gz -C /usr/local/lib/nodejs
シンボリンクリンクを作成します。
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/node /usr/bin/node
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/npm /usr/bin/npm
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/npx /usr/bin/npx
確認
$ node -v
v17.7.2
$ npm -v
8.5.2
$ npx -v
8.5.2
$ node -p process.versions
{
node: '17.7.2',
v8: '9.6.180.15-node.15',
uv: '1.43.0',
zlib: '1.2.11',
brotli: '1.0.9',
ares: '1.18.1',
modules: '102',
nghttp2: '1.47.0',
napi: '8',
llhttp: '6.0.4',
openssl: '3.0.2+quic',
cldr: '40.0',
icu: '70.1',
tz: '2021a3',
unicode: '14.0',
ngtcp2: '0.1.0-DEV',
nghttp3: '0.1.0-DEV'
}
nobleのインストール
npm i @abandonware/noble
サンプルコード
10秒間、周辺の新型コロナウイルス接触確認アプリ(COCOA)がインストールされている端末数を数えます。
// COCOA scan.js
'use strict';
const noble = require('@abandonware/noble');
const cocoaDevices = [];
//discovered BLE device
const discovered = (peripheral) => {
const device = {
uuid: peripheral.uuid,
rssi: peripheral.rssi
};
cocoaDevices.push(device);
console.log(`${cocoaDevices.length}:(${device.uuid}) RSSI${device.rssi}`);
}
//BLE scan start
const scanStart = () => {
//COCOA Service UUID
noble.startScanning(['fd6f'],false);
noble.on('discover', discovered);
}
if(noble.state === 'poweredOn'){
scanStart();
}else{
noble.on('stateChange', scanStart);
}
setTimeout(function(){
noble.stopScanning();
process.exit();
},10000);
実行結果
COCOAアプリ入れた、iPhoneを1台を置いた状態で、試したら、1回目、スマホが1台、2回目、スマホが2台でした。近くに、もう1台、スマホがあるみたい。