This question might have been asked by many people, but I have no luck to get answer from researching.
My ultimately plan is running a web app with Web Bluetooth API in smartphone with FLIC button to control audios to play. One click, play one audio.
I'm testing the program in my MAC laptop with my iPhoneX first, because I'm thinking if I can get both of them connected, then when I run the web app in smartphone, then I can connect to the FLIC button.
However, I got this error.
Something went wrong. NotSupportedError: GATT Error: Not supported.
Am I missing something? I saw someone mentioned iPhone cannot connect Latop, hopefully this is not true
Below is the code:
$("#bluetooth").on("click", function(){
const controlServiceUUID = '00001805-0000-1000-8000-00805f9b34fb'; // Full UUID
const commandCharacteristicUUID = '00002a0f-0000-1000-8000-00805f9b34fb'; //
var myCharacteristic;
navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: [controlServiceUUID]
})
.then(device => {
console.log("Got device name: ", device.name);
console.log("id: ", device.id);
return device.gatt.connect();
console.log("Here");
})
.then(server => {
serverInstance = server;
console.log("Getting PrimaryService");
return server.getPrimaryService(controlServiceUUID);
})
.then(service => {
console.log("Getting Characteristic");
return service.getCharacteristic(commandCharacteristicUUID);
})
.then(characteristic => {
// 0x01,3,0x02,0x03,0x01
myCharacteristic = characteristic;
return myCharacteristic.startNotifications().then(_ => {
log('Notifications started');
myCharacteristic.addEventListener('characteristicvaluechanged', test);
});
})
.catch(function(error) {
console.log("Something went wrong. " + error);
});
function test(event) {
if (myCharacteristic) {
myCharacteristic.startNotifications()
.then(_ => {
console.log("Notification stopped!");
})
.catch(error => {
console.log("Argh!" + error);
});
}
}
});
Web Bluetooth API is only available on ChromeOS and Android 6 or later with flag option.
(https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API)
Different platforms are at different points in implementation. I have been using this repo for updates on the status of the API:
WebBluetoothCG/web-bluetooth
Note the lack of support for ios
Not sure if this fixes your problem (i'm working on muse eeg), but one "hack" to get rid of this error is to wait some time (e.g. 500ms) after each characteristic write. Most platforms don't support write responses yet and writing multiple commands in parallel will cause this error.
https://github.com/WebBluetoothCG/web-bluetooth/blob/master/implementation-status.md
Is your command characteristic UUID filled in incorrectly? Try replacing it with one that can be written?
const controlServiceUUID = 0xfff0; // Full UUID
const commandCharacteristicUUID = 0xfff4; //
Related
I'm developing an application which scans for BLE devices(Peripherals), then connect to them, read their services and characteristics. For now, I was able to connect to an iPhone which acting as a Peripheral device with certain characteristics and also was able to connect to Fitbit Versa Watch to read the heart sensor data. Although I was able to discover their services, I wasn't able to extract more information from the services like ServiceUUId and their characteristics.
Below is my code is written in react native.
scanAndConnect() {
console.log("Scanning Started");
this.manager.startDeviceScan(null, null, (error, device) => {
if (error) {
// Handle error (scanning will be stopped automatically)
console.log("Error in scanning devices:", error);
return
}
// Check if it is a device you are looking for based on advertisement data
// or other criteria.
console.log("Detected Device Details:", device.id, device.name);
// ||device.localName === 'BLEPeripheralApp')
if (device.name === 'Versa Lite'){ //
// Stop scanning as it's not necessary if you are scanning for one device.
console.log("Device Found, Stopping the Scan.");
console.log("Connecting to:",device.name)
this.manager.stopDeviceScan();
device.connect()
.then((device) => {
// this.info("Discovering services and characteristics")
console.log("Connected...Discovering services and characteristics");
return device.discoverAllServicesAndCharacteristics()
})
.then((device) => {
console.log('Services and characteristics discovered');
//return this.testChar(device)
const services = device.services()
console.log(services);
return device.readCharacteristicForService(services)
// device.readCharacteristicForService("abbaff00-e56a-484c-b832-8b17cf6cbfe8")
// this.info("Setting notifications")
//return this.setupNotifications(device)
})
.then(() => {
const characteristicsData = device.readCharacteristicForService();
console.log(characteristicsData);
//this.info("Listening...")
}, (error) => {
console.warn(error.message);
// this.error(error.message)
})
}
});
}
How do I extract the serviceUUId from the Service method and also read the characteristics of that service? For my iPhone peripheral, I have two mutable characteristics that I should be able to read and write.
How do I read them from service to characteristics to the real value?
Any help/suggestions are much appreciated.
Thanks.
You're missing the method characteristicsForService.
Loop over all the services, get their characteristics by
await device.discoverAllServicesAndCharacteristics();
const services = await device.services();
services.forEach(async service => {
const characteristics = await device.characteristicsForService(service.uuid);
characteristics.forEach(console.log);
});
I'm developing an audio-based PWA and, since I'm not familiar with this technology, I have a couple of doubts regading the cache management and invalidation in the service worker.
The application need to work offline, that I covered using a SW precache.
My only doubt is the amount of data: in the experience there are 5 use case scenarios. Each scenario has ~30MB of audio content, that means around 150MB + all images, js and css in total to precache.
I know that this exceeds the limit of some browsers (se this question and this article)
and in general you must be careful with the storage size, that also depends on the user's device available space on disk.
So that's what I thought: since between one scenario and another, the users will stop by a desk with WiFi connection, my idea is to empty the cache runtime after an user's action (like pressing a button), and replace it with thw new content.
This way I would store only one scenario at a time, that means ~35MB, a reasonable size.
Do you think that's a good approach?
What's the best way to implement this?
Here's my current code:
service-worker.js
const PRECACHE = 'precache-test-v1';
// A list of local resources we always want to be cached.
const PRECACHE_URLS = [
'/',
'/audio/scenario1.mp3',
'/audio/scenario2.mp3',
'/audio/scenario3.mp3',
'/audio/scenario4.mp3',
'/audio/scenario5.mp3',
'/css/style.css',
'/js/bundle.js',
'/img/favicon.png',
'/img/logo.png',
'/img/image1.png',
'/img/image2.png',
'/img/image3.png',
'/img/image4.png',
'/img/image5.png',
];
// never cache these resources
const TO_SKIP = [/* empty for now */];
// The install handler takes care of precaching the resources we always need.
self.addEventListener('install', event => {
const now = new Date();
console.log(`PWA Service Worker installing - :: ${now} ::`);
event.waitUntil(caches.open(PRECACHE).then(cache => {
return cache.addAll(PRECACHE_URLS).then(() => {
self.skipWaiting();
});
}));
});
// The activate handler takes care of cleaning up old caches.
self.addEventListener('activate', event => {
const now = new Date();
console.log(`PWA Service Worker activating - :: ${now} ::`);
const currentCaches = [PRECACHE];
event.waitUntil(
caches.keys().then(cacheNames => {
return cacheNames.filter(cacheName => !currentCaches.includes(cacheName));
}).then(cachesToDelete => {
return Promise.all(cachesToDelete.map(cacheToDelete => {
return caches.delete(cacheToDelete);
}));
}).then(() => self.clients.claim())
);
});
// The fetch handler serves responses for same-origin resources from a cache.
self.addEventListener('fetch', event => {
// Skip cross-origin requests, like those for Google Analytics and the other provided urls.
if (event.request.url.startsWith(self.location.origin) && TO_SKIP.every(url => !event.request.url.includes(url))) {
event.respondWith(
caches.match(event.request).then(resp => {
return resp || fetch(event.request).then(response => {
return caches.open(PRECACHE).then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
}
});
index.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(registration => {
console.log('Registration successful, scope is:', registration.scope);
}).catch(error => {
console.log('Service worker registration failed, error:', error);
});
}
Thank you for your time,
Francesco
Hmm.. instead of precaching 5 videos, you could provide an button Save for offline so that the user can save only that videos that he wants to see later offline:
let videoUrl = url to that video:
button.addEventListener('click', function(event) {
event.preventDefault();
caches.open("myVideoCache").then(function(cache) {
fetch(videoUrl)
.then(function(video) {
cache.add(video);
});
});
});
Do delete 1 entry you need to open your cache and delete it. Pass the path that you stored.
caches.open('myVideoCache').then(function(cache) {
cache.delete('/path/to/audio.mp4').then(function(response) {
console.log("entry deleted");
});
})
More details you can find here: https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker
I'm trying to inflate messages from a third party websocket using javascript, but receiving a pako.js
"invalid stored block lengths" error.
The sample code I'm using to implement the web socket can be found here:
https://github.com/okcoin-okex/API-docs-OKEx.com/tree/master/demo
A full working version of the code can be found implemented here:
https://github.com/Tucsky/SignificantTrades/blob/master/src/exchanges/okex.js
(https://aggr.trade)
I've tried using zlib.js instead of Pako.js, but running into more difficult problems with that library.
I've tried other alternate solutions found on stackoverflow but they don't seem to do what I need.
This is the code I'm running which shows the error.
https://jsfiddle.net/fwkgmvjr/
let myAPI = new WebSocket('wss://real.okex.com:10442/ws/v3');
//When the connection is first opened
myAPI.onopen = event => {
console.log('Socket opened')
myAPI.send('{"op": "subscribe", "args":["futures/ticker:ETH-USD-190927"]}')
}
myAPI.onmessage = event => {
if (event.data instanceof String) {
console.log(event.data)
} else {
try {
console.log(JSON.parse(pako.inflateRaw(event.data, {
to: 'string'
})))
} catch (err) {
console.log(err)
}
}
}
myAPI.onclose = event => {
console.log('Socket closed')
}
myAPI.onerror = event => {
console.log(`[error] ${error.message}`)
}
I expect the message from the websocket to be easily inflatable somehow.
The solution was to add
this.api.binaryType = 'arraybuffer'
when declaring the websocket.
EDITED
I'm facing this issue while trying to create test videos using the TestCase Javascript API.
I'm working with testcafe version 0.22.0 and I already have the prerequisites the request in their documentation.
Basically, the issue is video function doesn't exist in my runner object.
https://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/screenshots-and-videos.html#record-videos
createTestCafe('localhost', 1337, 1338)
.then(testcafe => {
runner = testcafe.createRunner();
return testcafe.createBrowserConnection();
})
.then(remoteConnection => {
// Outputs remoteConnection.url so that it can be visited from the remote browser.
runner
.video(artifactsPath, true)
.src(specsPath + '/run-animation.spec.ts')
.browsers(['chrome'])
.reporter('json')
.run()
.then(failedCount => {
console.log('Error: ', failedCount);
})
.catch(error => {
console.log('Error: ', error);
});
});
You are using the old TestCafe version. The 'Recording Video' feature appeared in a version older than 0.22.0.
The latest TestCafe version (1.1.2) exactly contains this feature.
I'm currently using the expo camera in my application on iOS.
The app crashes when I try to save the image like this.
takePicture = async function() {
this.camera.takePictureAsync().then(data => {
FileSystem.moveAsync({
from: data,
to: `${FileSystem.documentDirectory}photos/Photo_${this.state
.photoId}.jpg`,
}).then(() => {
this.setState({
photoId: this.state.photoId + 1,
});
Vibration.vibrate();
}).catch((err) => {
console.log("Error : " + err);
});
}).catch(error => {
console.log(error);
});
Vibration.vibrate();
console.log("Taking pic");
}
In addition the Vibration.vibrate() doesn't actually vibrate the phone. I receive an error earlier in the execution here:
componentDidMount() {
FileSystem.makeDirectoryAsync(
FileSystem.documentDirectory + 'photos'
).catch(e => {
console.log(e, 'Directory exists');
});
}
The error just says
[Error: Directory 'file:///var/mobile/Containers/Data/Application/X/Documents/ExponentExperienceData/X/photos' could not be created.]
Is there anyone else who has experienced the same issue? If anyone is able to let me know how to add the vibration too this would be fantastic. I've added it in the top of the file as:
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Slider,
Image,
Picker,
Button,
ScrollView,
Vibration,
} from 'react-native';
EDIT: I've solved the issue with saving to the cameraroll. The issue with the vibration still stands.
Thanks
For the first problem you describe, although you solved it via a workaround by saving it to cameraroll, I would suggest you post the edited code to keep the question correctly up to date.
FileSystem Issue
Addressing the FileSystem error issue, the original code should work as it is, but you could check:
If the expo app has appropriate file access permissions (should be automatic via the expo library, but try updating the expo app). Documentation on FileSystem can be found here: https://docs.expo.io/versions/latest/sdk/filesystem.html
You may need to create the intermediate directories (i.e. photos):
like this:
async componentDidMount() {
try {
await FileSystem.makeDirectoryAsync(
`${FileSystem.documentDirectory}photos`,
{
intermediates: true, // creates intermediate directories
}
)
} catch (e) {
console.log(e)
}
}
Vibration Issue
The vibration problem is probably caused by a bug in react-native as described here: https://github.com/facebook/react-native/issues/8955#issuecomment-353373616
As a workaround you could vibrate before setting the state i.e:
takePicture = async function() {
if (this.camera) {
const picture = await this.camera.takePictureAsync();
const pictureFile = await FileSystem.moveAsync(
{
from: picture.uri,
to: `${
FileSystem.documentDirectory
}photos/Photo_${this.state.photoId}.jpg`
}
).catch(err => console.error(err));
Vibration.vibrate();
console.log("Pic taken", this.state.photoId);
return this.setState({
photoId: this.state.photoId + 1
});
}
};