This commit is contained in:
Gilles Boccon-Gibod
2023-10-01 14:15:17 -07:00
parent 99bc92d53d
commit ad13b11464
11 changed files with 37 additions and 40 deletions

View File

@@ -67,16 +67,14 @@ nav:
- Zephyr: platforms/zephyr.md
- Examples:
- Overview: examples/index.md
<<<<<<< HEAD
- Extras:
- Overview: extras/index.md
- Android Remote HCI: extras/android_remote_hci.md
=======
- Hive:
- Overview: hive/index.md
- Speaker: hive/web/speaker/speaker.html
- Scanner: hive/web/scanner/scanner.html
>>>>>>> 2e9fb96 (wip (+5 squashed commits))
- Heart Rate Monitor: hive/web/heart_rate_monitor/heart_rate_monitor.html
copyright: Copyright 2021-2023 Google LLC

View File

@@ -26,4 +26,5 @@ Virtual Devices
---------------
* [Speaker](web/speaker/speaker.html) - Virtual speaker that plays audio in a browser page.
* [Heart Rate Monitor](web/heart_rate_monitor/heart_rate_monitor.html) - Virtual heart rate monitor.

View File

@@ -13,3 +13,9 @@ name = "scanner"
description = "Simple Scanner Application"
type = "Application"
url = "scanner/scanner.html"
[[index]]
name = "heart-rate-monitor"
description = "Virtual Heart Rate Monitor"
type = "Device"
url = "heart_rate_monitor/heart_rate_monitor.html"

View File

@@ -57,10 +57,10 @@ export class Bumble extends EventTarget {
}
// Load the Bumble module
this.log('Installing micropip');
await this.pyodide.loadPackage('micropip');
bumblePackage ||= 'bumble';
console.log('Installing micropip');
this.log(`Installing ${bumblePackage}`)
await this.pyodide.loadPackage('micropip');
await this.pyodide.runPythonAsync(`
import micropip
await micropip.install('${bumblePackage}')
@@ -76,7 +76,7 @@ export class Bumble extends EventTarget {
// Sync previously persisted filesystem data into memory
await new Promise(resolve => {
this.pyodide.FS.syncfs(true, () => {
this.log('FS synced in');
console.log('FS synced in');
resolve();
});
})
@@ -128,7 +128,7 @@ export class Bumble extends EventTarget {
}
async loadApp(appUrl) {
this.log('Loading script');
this.log('Loading app');
const script = await (await fetch(appUrl)).text();
await this.pyodide.runPythonAsync(script);
const pythonMain = this.pyodide.globals.get('main');
@@ -136,14 +136,14 @@ export class Bumble extends EventTarget {
if (app.on) {
app.on('key_store_update', this.onKeystoreUpdate.bind(this));
}
this.log('App is ready!');
return app;
}
onKeystoreUpdate() {
// Sync the FS
this.pyodide.FS.syncfs(() => {
this.log('FS synced out');
console.log('FS synced out');
});
}
}

View File

@@ -1,10 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css">
<script src="https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js"></script>
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
<script src="https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js"></script>
<script type="module" src="../ui.js"></script>
<script type="module" src="heart_rate_monitor.js"></script>
<style>
@@ -15,13 +14,16 @@
</style>
</head>
<body>
<bumble-controls id="bumble-controls"></bumble-controls><hr>
<textarea id="log-output" style="width: 100%;" rows="10" disabled></textarea><hr>
<span class="material-symbols-outlined">
cardiology
</span>
<span id="hr-value">60</span>
<br>
<button id="hr-up-button">+</button>
<button id="hr-down-button">-</button>
</body>
<button id="hr-up-button" class="mdc-icon-button material-icons"><div class="mdc-icon-button__ripple"></div>arrow_upward</button>
<button id="hr-down-button" class="mdc-icon-button material-icons"><div class="mdc-icon-button__ripple"></div>arrow_downward</button>
<hr>
<textarea id="log-output" style="width: 100%;" rows="10" disabled></textarea><hr>
</body>
</html>

View File

@@ -26,4 +26,5 @@ document.querySelector('#hr-down-button').addEventListener('click', () => {
// Setup the app
const app = await setupSimpleApp('heart_rate_monitor.py', bumbleControls, logToOutput);
logToOutput('Click the Bluetooth button to start');

View File

@@ -1,15 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="scanner.css">
<script src="https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js"></script>
<script src="https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js"></script>
<script type="module" src="../ui.js"></script>
<script type="module" src="scanner.js"></script>
</style>
</style>
</head>
<body>
<script type="module">
import {LitElement, html} from 'https://cdn.jsdelivr.net/gh/lit/dist@2/core/lit-core.min.js';
@@ -18,4 +17,5 @@
<bumble-controls id="bumble-controls"></bumble-controls><hr>
<textarea id="log-output" style="width: 100%;" rows="10" disabled></textarea><hr>
<scan-list id="scan-list"></scan-list>
</body>
</body>
</html>

View File

@@ -65,3 +65,4 @@ const bumbleControls = document.querySelector('#bumble-controls');
// Setup the app
const app = await setupSimpleApp('scanner.py', bumbleControls, logToOutput);
app.on('update', onUpdate);
logToOutput('Click the Bluetooth button to start');

View File

@@ -2,9 +2,8 @@
<html>
<head>
<title>Bumble Speaker</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="speaker.css">
<script src="https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js"></script>
<script src="https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js"></script>
<script type="module" src="speaker.js"></script>
<script type="module" src="../ui.js"></script>
</head>

View File

@@ -96,12 +96,11 @@ class Speaker:
STARTED = 2
SUSPENDED = 3
def __init__(self, hci_source, hci_sink, codec, discover):
def __init__(self, hci_source, hci_sink, codec):
self.hci_source = hci_source
self.hci_sink = hci_sink
self.js_listeners = {}
self.codec = codec
self.discover = discover
self.device = None
self.connection = None
self.avdtp_listener = None
@@ -180,7 +179,6 @@ class Speaker:
def on_bluetooth_disconnection(self, reason):
print(f'Disconnection ({reason})')
self.connection = None
AsyncRunner.spawn(self.advertise())
self.emit('disconnection', None)
def on_avdtp_connection(self, protocol):
@@ -199,10 +197,6 @@ class Speaker:
# Listen for close events
protocol.on('close', self.on_avdtp_close)
# Discoverall endpoints on the remote device is requested
if self.discover:
AsyncRunner.spawn(self.discover_remote_endpoints(protocol))
def on_avdtp_close(self):
print("Audio Stream Closed")
@@ -237,10 +231,6 @@ class Speaker:
self.bytes_received += len(packet.payload)
self.emit("audio", self.audio_extractor.extract_audio(packet))
async def advertise(self):
await self.device.set_discoverable(True)
await self.device.set_connectable(True)
async def connect(self, address):
# Connect to the source
print(f'=== Connecting to {address}...')
@@ -317,8 +307,7 @@ class Speaker:
print("Connection timed out")
return
else:
# Start being discoverable and connectable
await self.advertise()
# We'll wait for a connection
print("Waiting for connection...")
async def start(self):
@@ -333,4 +322,4 @@ class Speaker:
# -----------------------------------------------------------------------------
def main(hci_source, hci_sink):
return Speaker(hci_source, hci_sink, "aac", False)
return Speaker(hci_source, hci_sink, "aac")

View File

@@ -10,7 +10,7 @@ class BumbleControls extends LitElement {
render() {
return html`
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<dialog id="settings-dialog" @close=${this.onSettingsDialogClose}>
<dialog id="settings-dialog" @close=${this.onSettingsDialogClose} style="font-family:sans-serif">
<p>WebSocket URL for HCI transport</p>
<form>
<input id="settings-hci-url-input" type="text" size="50"></input>