Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions src/bluetooth-extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
export namespace CommandIDs {
export const openDeviceRegistryDialog =
'bluetooth-manager:open-dialog-for-devices-registry';
export const disconnectDevice = 'bluetooth-manager:disconnect-device';
export const disconnect = 'bluetooth-manager:disconnect-device';
}

export function buildCompleteIdentifier(native: BluetoothDevice): string {
Expand Down Expand Up @@ -67,13 +67,13 @@ const BluetoothSidebarPlugin: JupyterFrontEndPlugin<void> = {
const openDeviceRegistryDialogLabel = trans.__('Add a Device');
let runningItemsList: Array<IRunningSessions.IRunningItem>;

app.commands.addCommand(CommandIDs.disconnectDevice, {
app.commands.addCommand(CommandIDs.disconnect, {
execute: args => {
const selectedDevice = bluetoothManager.deviceList.find(
device => device.native.id === (args.deviceID as string)
);
if (selectedDevice) {
bluetoothManager.disconnectDevice(selectedDevice);
bluetoothManager.disconnect(selectedDevice);
return selectedDevice;
} else {
throw new Error('No device provided or device is invalid');
Expand All @@ -87,20 +87,24 @@ const BluetoothSidebarPlugin: JupyterFrontEndPlugin<void> = {
execute: async () => {
showDialog({
title: 'Select device type',
body: new DropDownRegistry(bluetoothManager.registry),
body: new DropDownRegistry(bluetoothManager.deviceTypeRegistry),
buttons: [
Dialog.okButton({ label: 'Select' }),
Dialog.cancelButton({ label: 'Cancel' })
]
}).then(async result => {
if (result.button.accept) {
bluetoothManager.registry.itemsList.forEach(async item => {
if (item.deviceType === result.value) {
await bluetoothManager.connectDevice(item);
} else {
console.warn('There is no corresponding item in the registry!');
bluetoothManager.deviceTypeRegistry.deviceTypes.forEach(
async item => {
if (item.deviceType === result.value) {
await bluetoothManager.connect(item);
} else {
console.warn(
'There is no corresponding item in the registry!'
);
}
}
});
);
}
});
}
Expand Down Expand Up @@ -151,12 +155,12 @@ export class DropDownRegistry
extends Widget
implements Dialog.IBodyWidget<string>
{
constructor(registry: BluetoothManager.DeviceRegistry) {
constructor(registry: BluetoothManager.DeviceTypeRegistry) {
super();
this._selectList = document.createElement('select');
this.node.appendChild(this._selectList);
this.registry = registry;
registry.itemsList.forEach(item => {
registry.deviceTypes.forEach(item => {
const option = document.createElement('option');
option.value = item.deviceType;
option.text = item.deviceType;
Expand All @@ -169,7 +173,7 @@ export class DropDownRegistry
}

private _selectList: HTMLSelectElement;
public registry: BluetoothManager.DeviceRegistry;
public registry: BluetoothManager.DeviceTypeRegistry;
}

const BluetoothExtensionPlugins: JupyterFrontEndPlugin<any>[] = [
Expand Down
4 changes: 2 additions & 2 deletions src/bluetooth/BluetoothDeviceRunningItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { buildCompleteIdentifier } from '../bluetooth-extension';
import { Menu } from '@lumino/widgets';
import { CommandRegistry } from '@lumino/commands';

export const disconnectDevice = 'bluetooth-manager:disconnect-device';
export const disconnect = 'bluetooth-manager:disconnect-device';

export class BluetoothDeviceRunningItem
implements IRunningSessions.IRunningItem
Expand Down Expand Up @@ -58,7 +58,7 @@ export class BluetoothDeviceRunningItem
}

shutdown() {
this.bluetoothManager.disconnectDevice(this._device);
this.bluetoothManager.disconnect(this._device);
}

private _device: BluetoothManager.Device;
Expand Down
127 changes: 40 additions & 87 deletions src/bluetooth/BluetoothManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ export class BluetoothManager implements IBluetoothManager {
this.deviceListChanged = new Signal<this, Array<BluetoothManager.Device>>(
this
);
this.registeredByAPlugin = new Signal<
this,
BluetoothManager.DeviceRegistry
>(this);
this._registry = new BluetoothManager.DeviceRegistry();
this._deviceTypeRegistry = new BluetoothManager.DeviceTypeRegistry();
this._deviceList = [];
this._identifierRegistry = [];
}
Expand All @@ -26,54 +22,50 @@ export class BluetoothManager implements IBluetoothManager {
return this._deviceList;
}

get registry(): BluetoothManager.DeviceRegistry {
return this._registry;
get deviceTypeRegistry(): BluetoothManager.DeviceTypeRegistry {
return this._deviceTypeRegistry;
}

get identifierRegistry(): Array<string> {
return this._identifierRegistry;
}

async connectDevice(
registryItem: IDeviceRegistryItem
async connect(
registryItem: IDeviceTypeRegistryItem
): Promise<BluetoothManager.Device | undefined> {
const native = await this.requestDevice(registryItem);
if (native) {
const device = await registryItem.factory(native);
if (device && device.isConnected) {
this.addDeviceToList(device);
this._addDeviceToList(device);
device.disconnected.connect(async () => {
this.removeDeviceFromList(device);
this._removeDeviceFromList(device);
});
return device;
}
}
}

async disconnectDevice(device: BluetoothManager.Device) {
async disconnect(device: BluetoothManager.Device) {
await device.disconnect();
device.dispose();
}

// Method to add a device to the list
addDeviceToList(device: BluetoothManager.Device): void {
private _addDeviceToList(device: BluetoothManager.Device): void {
const identifier = buildCompleteIdentifier(device.native);
if (this.identifierRegistry.includes(identifier) === false) {
if (this._identifierRegistry.includes(identifier) === false) {
this._deviceList.push(device);
this.identifierRegistry.push(identifier);
this._identifierRegistry.push(identifier);
} else {
console.warn('The device is already in the identifierRegistry');
console.warn('The device is already in the registry of identifiers');
}
// Emit the signal when the list changes
this.deviceListChanged.emit(this._deviceList);
}

// Method to remove a device from the list
removeDeviceFromList(device: BluetoothManager.Device): void {
private _removeDeviceFromList(device: BluetoothManager.Device): void {
const index = this._deviceList.indexOf(device);
if (index > -1) {
this._deviceList.splice(index, 1);
this.identifierRegistry.splice(index, 1);
this._identifierRegistry.splice(index, 1);
// Emit the signal when the list changes
this.deviceListChanged.emit(this._deviceList);
}
Expand All @@ -82,20 +74,11 @@ export class BluetoothManager implements IBluetoothManager {

removeAllDevices() {
this._deviceList.forEach((device, index) => {
this.removeDeviceFromList(device);
this._removeDeviceFromList(device);
this.deviceListChanged.emit(this._deviceList);
});
}

register(registryItem: IDeviceRegistryItem) {
this._registry.add(registryItem);
this.registeredByAPlugin.emit(this._registry);
console.warn(
`New item from category ${registryItem.deviceType} is added to the registry.`
);
return this._registry;
}

async checkWebBluetoothSupport(): Promise<boolean> {
const isWebBluetoothSupported: boolean = navigator.bluetooth ? true : false;
if (isWebBluetoothSupported === false) {
Expand All @@ -109,7 +92,7 @@ export class BluetoothManager implements IBluetoothManager {
}

async requestDevice(
registryItem: IDeviceRegistryItem
registryItem: IDeviceTypeRegistryItem
): Promise<BluetoothDevice | undefined> {
const isWebBluetoothSupported = await this.checkWebBluetoothSupport();
if (isWebBluetoothSupported) {
Expand All @@ -124,11 +107,7 @@ export class BluetoothManager implements IBluetoothManager {

private _deviceList: Array<BluetoothManager.Device>;
public deviceListChanged: Signal<this, Array<BluetoothManager.Device>>;
public registeredByAPlugin: Signal<
BluetoothManager,
BluetoothManager.DeviceRegistry
>;
private _registry: BluetoothManager.DeviceRegistry;
private _deviceTypeRegistry: BluetoothManager.DeviceTypeRegistry;
private _identifierRegistry: Array<string>;
}

Expand Down Expand Up @@ -204,32 +183,6 @@ export namespace BluetoothManager {
}
}

/*async connectAndGetAllServices(): Promise<
Array<BluetoothRemoteGATTService> | undefined
> {
this.native.addEventListener('gattserverdisconnected', event => {
this.isConnected = false;
this.disconnected.emit(true);
});
const server = this.native.gatt
if (server) {
server.connect();
if (server.connected === true) {
const services = await server.getPrimaryServices();
this.isConnected = true;
if (!services || services.length === 0) {
throw new Error('Server exists but no service found on the device.');
} else { return services; }
}
else {
throw new Error('There is no connection to server. No attempt to get a service.')
}
}
else {
throw new Error('Server is not defined.');
}
}*/

async disconnect(): Promise<void> {
if (this.native) {
this.native.gatt?.disconnect();
Expand Down Expand Up @@ -283,53 +236,53 @@ export namespace BluetoothManager {
}
}

export class DeviceRegistry implements IDeviceRegistry {
private _registry: Array<IDeviceRegistryItem>;
public registryItem: IDeviceRegistryItem;
export class DeviceTypeRegistry implements IDeviceTypeRegistry {
constructor() {
this._registry = [];
this._deviceTypes = [];
this._added = new Signal<this, IDeviceTypeRegistryItem>(this);
}

add(registryItem: IDeviceTypeRegistryItem) {
this._deviceTypes.push(registryItem);
this._added.emit(registryItem);
}

add(registryItem: IDeviceRegistryItem) {
this._registry.push(registryItem);
get deviceTypes(): IDeviceTypeRegistryItem[] {
return this._deviceTypes;
}
get itemsList(): Array<IDeviceRegistryItem> {
return this._registry;

get added(): Signal<this, IDeviceTypeRegistryItem> {
return this._added;
}

private _deviceTypes: Array<IDeviceTypeRegistryItem>;
private _added: Signal<this, IDeviceTypeRegistryItem>;
}
}

/**
* Interface for the bluetooth manager.
*/
export interface IBluetoothManager {
addDeviceToList(Device: BluetoothManager.Device): void;
removeDeviceFromList(Device: BluetoothManager.Device): void;
removeAllDevices(Devices: Array<BluetoothManager.Device>): void;
register(registryItem: IDeviceRegistryItem): BluetoothManager.DeviceRegistry;
connectDevice(registryItem: IDeviceRegistryItem): any;
disconnectDevice(device: BluetoothManager.Device): void;
connect(registryItem: IDeviceTypeRegistryItem): any;
disconnect(device: BluetoothManager.Device): void;
deviceListChanged: Signal<BluetoothManager, Array<BluetoothManager.Device>>;
registeredByAPlugin: Signal<
BluetoothManager,
BluetoothManager.DeviceRegistry
>;
get deviceList(): Array<BluetoothManager.Device>;
get registry(): BluetoothManager.DeviceRegistry;
get identifierRegistry(): Array<string>;
get deviceTypeRegistry(): BluetoothManager.DeviceTypeRegistry;
}

export interface IDeviceRegistryItem {
export interface IDeviceTypeRegistryItem {
deviceType: string;
factory: (
native: BluetoothDevice
) => Promise<BluetoothManager.Device | undefined>;
options: IDeviceOptions;
}

export interface IDeviceRegistry {
add: (registryItem: IDeviceRegistryItem) => void;
get itemsList(): Array<IDeviceRegistryItem>;
export interface IDeviceTypeRegistry {
add: (registryItem: IDeviceTypeRegistryItem) => void;
get deviceTypes(): IDeviceTypeRegistryItem[];
}

export const IBluetoothManager = new Token<IBluetoothManager>(
Expand Down
17 changes: 12 additions & 5 deletions src/movehub-extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ITranslator } from '@jupyterlab/translation';
import { IThemeManager, MainAreaWidget } from '@jupyterlab/apputils';
import { Toolbar } from '@jupyterlab/ui-components';
import {
IDeviceRegistryItem,
IDeviceTypeRegistryItem,
IBluetoothManager,
BluetoothManager
} from '../bluetooth/BluetoothManager';
Expand All @@ -27,7 +27,7 @@ export const connectMoveHub = 'bluetooth-manager:connect-movehub';
export const disconnectMoveHub = 'bluetooth-manager:disconnect-movehub';
export const moveHubServiceUUID = '00001623-1212-efde-1623-785feabcd123';
export const moveHubCharacteristicUUID = '00001624-1212-efde-1623-785feabcd123';
export const movehubRegistryItem: IDeviceRegistryItem = {
export const movehubRegistryItem: IDeviceTypeRegistryItem = {
deviceType: 'LEGO® Move Hub',
options: {
acceptAllDevices: false,
Expand Down Expand Up @@ -56,7 +56,14 @@ const MoveHubRegisterPlugin: JupyterFrontEndPlugin<void> = {
bluetoothManager: BluetoothManager
): void => {
console.log('JupyterLab move-hub-register plugin is activated!');
bluetoothManager.register(movehubRegistryItem);
bluetoothManager.deviceTypeRegistry.added.connect(
async (sender, movehubRegistryItem) => {
console.warn(
`New item from category ${movehubRegistryItem.deviceType} is added to the deviceType registry.`
);
}
);
bluetoothManager.deviceTypeRegistry.add(movehubRegistryItem);
}
};

Expand Down Expand Up @@ -125,7 +132,7 @@ const LEGOMoveHubControlPanelPlugin: JupyterFrontEndPlugin<void> = {
device => device.native.id === (args.deviceID as string)
);
if (selectedDevice && selectedDevice instanceof MoveHub) {
bluetoothManager.disconnectDevice(selectedDevice);
bluetoothManager.disconnect(selectedDevice);
return selectedDevice;
} else {
throw new Error('No device provided or device is invalid');
Expand All @@ -151,7 +158,7 @@ const LEGOMoveHubControlPanelPlugin: JupyterFrontEndPlugin<void> = {

app.commands.addCommand(connectMoveHub, {
execute: args => {
const newDevice = bluetoothManager.connectDevice(movehubRegistryItem);
const newDevice = bluetoothManager.connect(movehubRegistryItem);
return newDevice;
},
caption: 'Connect MoveHub',
Expand Down
2 changes: 1 addition & 1 deletion src/movehub-extension/widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export class MoveHubModel extends DOMWidgetModel {
console.log('not connected yet');*/
if (identifier === '') {
this.movehub =
await MoveHubModel.bluetoothManager.connectDevice(movehubRegistryItem);
await MoveHubModel.bluetoothManager.connect(movehubRegistryItem);
} else {
const selectedDevice = MoveHubModel.bluetoothManager.deviceList.find(
device => device.native.id === identifier
Expand Down
Loading