lavva.webbluetooth
Version:
Library implementing WebBluetooth custom functionality if underlying platform does support it
270 lines • 13.7 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { NativeTypedEvent } from "./ExtendedWebBluetooth";
import { Task } from "./Task";
export class LavvaBluetooth {
constructor() {
this.receiveBuffer = '';
this._maxCharacteristicValueLength = 20;
this.serviceUuid = 0xffe0;
this.characteristicUuid = 0xffe1;
this.receiveSeparator = '\n';
this.sendSeparator = '\n';
this.selectedDevice = null;
this.characteristic = null;
this.gattServer = null;
this.gattService = null;
this.OnGattServiceDisconnectedEvent = new NativeTypedEvent('OnGattServiceDisconnectedEvent');
this.OnCharacteristicValueChangedEvent = new NativeTypedEvent('OnCharacteristicValueChangedEvent');
this.OnConnectedEvent = new NativeTypedEvent('OnConnectedEvent');
this.OnDisconnectedEvent = new NativeTypedEvent('OnDisconnectedEvent');
this.filter = [
{ namePrefix: 'Lavva-', services: [this.serviceUuid] },
{ namePrefix: 'smartAW', services: [this.serviceUuid] },
];
this.handleGattServiceDisconnected = (event) => {
var _a;
console.warn('Gatt Service disconnected');
(_a = this.OnGattServiceDisconnectedEvent) === null || _a === void 0 ? void 0 : _a.Invoke(this.gattServer);
};
this.handleCharacteristicValueChanged = (event) => {
var _a;
try {
const characteristic = event.target;
const value = new TextDecoder().decode(characteristic.value);
console.warn(`Received characteristic value change: ${value}`);
for (const c of value) {
if (c === this.receiveSeparator) {
const data = this.receiveBuffer.trim();
this.receiveBuffer = '';
if (data) {
console.warn(`Received data: ${data}`);
(_a = this.OnCharacteristicValueChangedEvent) === null || _a === void 0 ? void 0 : _a.Invoke(data);
}
}
else {
this.receiveBuffer += c;
}
}
}
catch (error) {
console.error('Error handling characteristic value changed:', error);
}
};
}
SetFilter(filters) {
this.filter = filters;
}
GetConnectedDevice() {
return this.selectedDevice;
}
RequestDeviceAndConnectAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
let dev;
if (this.selectedDevice !== null)
return DeviceConnectionError.AnotherDeviceIsAlreadyConnected;
try {
console.log(`Requesting Bluetooth Device, filter: ${JSON.stringify(this.filter)}`);
dev = yield navigator.bluetooth.requestDevice({ filters: this.filter });
if (dev === undefined || dev === null) {
console.warn('No device selected');
return DeviceConnectionError.NoDeviceHasBeenSelected;
}
}
catch (error) {
console.error('Error requesting device: ', error);
return DeviceConnectionError.NoDeviceHasBeenSelected;
}
try {
console.log(`Selected device: ${dev.name} with ID: ${dev.id}`);
console.warn(`Connecting to GATT Server of device: ${dev.name}`);
this.selectedDevice = dev;
dev.addEventListener('gattserverdisconnected', this.handleGattServiceDisconnected.bind(this));
this.gattServer = yield ((_a = dev.gatt) === null || _a === void 0 ? void 0 : _a.connect());
if (!this.gattServer) {
console.error('Failed to connect to GATT Server');
return DeviceConnectionError.FailedToConnectToGattServer;
}
}
catch (error) {
console.error('Error connecting to GATT Server: ', error);
return DeviceConnectionError.FailedToConnectToGattServer;
}
try {
console.warn(`Getting primary service: ${this.serviceUuid}`);
this.gattService = yield this.gattServer.getPrimaryService(this.serviceUuid);
if (!this.gattService) {
console.error('Failed to get primary service');
return DeviceConnectionError.FailedToGetPrimaryService;
}
}
catch (error) {
console.error('Error getting primary service:', error);
return DeviceConnectionError.FailedToGetPrimaryService;
}
try {
console.warn(`Getting characteristic: ${this.characteristicUuid}`);
this.characteristic = yield this.gattService.getCharacteristic(this.characteristicUuid);
if (!this.characteristic) {
console.error('Failed to get characteristic');
return DeviceConnectionError.FailedToGetCharacteristic;
}
}
catch (error) {
console.error('Error getting characteristic:', error);
return DeviceConnectionError.FailedToGetCharacteristic;
}
try {
console.warn('Starting notifications');
const notif = yield this.characteristic.startNotifications();
if (!notif) {
console.error('Failed to start notifications');
return DeviceConnectionError.FailedToStartNotifications;
}
notif.addEventListener('characteristicvaluechanged', this.handleCharacteristicValueChanged.bind(this));
}
catch (error) {
console.error('Error starting notifications:', error);
return DeviceConnectionError.FailedToStartNotifications;
}
console.warn('Connected to device successfully!');
this.OnConnectedEvent.Invoke(dev);
return dev;
});
}
DisconnectDeviceAsync(device) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d;
try {
if (device !== null) {
console.warn(`Disconnecting device: ${device.name}`);
try {
(_a = this.selectedDevice) === null || _a === void 0 ? void 0 : _a.removeEventListener('gattserverdisconnected', this.handleGattServiceDisconnected);
}
catch (error) {
console.error('Error removing event listener (gattserverdisconnected):', error);
}
try {
(_b = this.characteristic) === null || _b === void 0 ? void 0 : _b.removeEventListener('characteristicvaluechanged', this.handleCharacteristicValueChanged);
yield ((_c = this.characteristic) === null || _c === void 0 ? void 0 : _c.stopNotifications());
console.warn('Stopped notifications');
}
catch (error) {
//console.error('Error stopping notifications:', error);
//return DeviceDisconnectionStatus.FailedToStopNotifications;
}
try {
(_d = device.gatt) === null || _d === void 0 ? void 0 : _d.disconnect();
yield Task.Delay(1000);
}
catch (error) {
//console.error('Error disconnecting device:', error);
//return DeviceDisconnectionStatus.FailedToDisconnect;
}
try {
yield device.forget();
}
catch (error) {
//console.error('Error forgetting device:', error);
//return DeviceDisconnectionStatus.FailedToForgetDevice;
}
this.selectedDevice = null;
this.characteristic = null;
this.gattServer = null;
this.gattService = null;
this.OnDisconnectedEvent.Invoke(device);
}
else {
return DeviceDisconnectionStatus.NoDeviceConnected;
}
}
catch (error) {
console.error('Error disconnecting device:', error);
return DeviceDisconnectionStatus.FailedToDisconnect;
}
return DeviceDisconnectionStatus.DisconnectedSuccesfully;
});
}
SendDataAsync(data) {
return __awaiter(this, void 0, void 0, function* () {
if (!data)
return WriteDataStatus.DataIsEmpty;
try {
data += this.sendSeparator;
const chunks = this.SplitByLength(data, this._maxCharacteristicValueLength);
if (!chunks)
return WriteDataStatus.FailedToWriteValue;
if (!this.characteristic)
return WriteDataStatus.NoDeviceConnected;
// Write first chunk to the characteristic immediately
let res = yield this.WriteValueAsync(chunks[0]);
if (!res)
return WriteDataStatus.FailedToWriteValue;
// Write rest of the chunks to the characteristic
for (let i = 1; i < chunks.length; i++) {
res = yield this.WriteValueAsync(chunks[i]);
if (!res)
return WriteDataStatus.FailedToWriteValue;
}
return WriteDataStatus.Sucess;
}
catch (error) {
console.error('Error sending data:', error);
return WriteDataStatus.FailedToWriteValue;
}
});
}
WriteValueAsync(value) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.characteristic)
return false;
const writer = new TextEncoder().encode(value);
try {
console.warn(`Writing characteristic [${this.characteristic.uuid}] value: ${value}`);
yield this.characteristic.writeValue(writer);
return true;
}
catch (error) {
console.error(`Error writing value: ${value} error:`, error);
return false;
}
});
}
SplitByLength(text, length) {
return text.match(new RegExp(`(.|[\r\n]){1,${length}}`, 'g'));
}
}
export var DeviceConnectionError;
(function (DeviceConnectionError) {
DeviceConnectionError[DeviceConnectionError["NoDeviceHasBeenSelected"] = 0] = "NoDeviceHasBeenSelected";
DeviceConnectionError[DeviceConnectionError["AnotherDeviceIsAlreadyConnected"] = 1] = "AnotherDeviceIsAlreadyConnected";
DeviceConnectionError[DeviceConnectionError["FailedToConnectToGattServer"] = 2] = "FailedToConnectToGattServer";
DeviceConnectionError[DeviceConnectionError["FailedToGetPrimaryService"] = 3] = "FailedToGetPrimaryService";
DeviceConnectionError[DeviceConnectionError["FailedToDiscoverService"] = 4] = "FailedToDiscoverService";
DeviceConnectionError[DeviceConnectionError["FailedToGetCharacteristic"] = 5] = "FailedToGetCharacteristic";
DeviceConnectionError[DeviceConnectionError["FailedToStartNotifications"] = 6] = "FailedToStartNotifications";
})(DeviceConnectionError || (DeviceConnectionError = {}));
export var DeviceDisconnectionStatus;
(function (DeviceDisconnectionStatus) {
DeviceDisconnectionStatus[DeviceDisconnectionStatus["NoDeviceConnected"] = 0] = "NoDeviceConnected";
DeviceDisconnectionStatus[DeviceDisconnectionStatus["FailedToForgetDevice"] = 1] = "FailedToForgetDevice";
DeviceDisconnectionStatus[DeviceDisconnectionStatus["FailedToDisconnect"] = 2] = "FailedToDisconnect";
DeviceDisconnectionStatus[DeviceDisconnectionStatus["FailedToStopNotifications"] = 3] = "FailedToStopNotifications";
DeviceDisconnectionStatus[DeviceDisconnectionStatus["DisconnectedSuccesfully"] = 4] = "DisconnectedSuccesfully";
})(DeviceDisconnectionStatus || (DeviceDisconnectionStatus = {}));
export var WriteDataStatus;
(function (WriteDataStatus) {
WriteDataStatus[WriteDataStatus["Sucess"] = 0] = "Sucess";
WriteDataStatus[WriteDataStatus["DataIsEmpty"] = 1] = "DataIsEmpty";
WriteDataStatus[WriteDataStatus["NoDeviceConnected"] = 2] = "NoDeviceConnected";
WriteDataStatus[WriteDataStatus["FailedToWriteValue"] = 3] = "FailedToWriteValue";
})(WriteDataStatus || (WriteDataStatus = {}));
//# sourceMappingURL=LavvaBluetooth.js.map