Uncaught (in promise) : NotSupportedError: GATT Error Unknown - bluetooth-gatt

I am trying to write data which is 490 in length to a device using Web Bluetooth API. When I try to write I get NotSupportedError: GATT Error Unknown.
I am using chrome browser on android.
My app is in Angular 7 and I am using #types/web-bluetooth.
Below is the code:
navigator.bluetooth
.requestDevice({
filters: [{ name: this.deviceName }],
optionalServices: [this.GATT_SERVICE],
})
.then((device) => {
return device.gatt.connect();
})
.then((server) => {
return server.getPrimaryService(this.GATT_SERVICE);
})
.then((service) => {
this.gattService = service;
return this.gattService.getCharacteristic(this.GATT_CHAR);
})
.then((characteristic) => {
characteristic.writeValueWithResponse(this.arraybufferdata);
})
.catch(async (err) => {
console.log(err);
});
Can someone please help?

Is the issue related to the length? Can you reproduce error with less bytes in this.arraybufferdata?
Nit: You may want to return promise so that error gets propagated.
.then((characteristic) => {
return characteristic.writeValueWithResponse(this.arraybufferdata);
})

Related

TypeError: undefined is not a function (near '...device.monitorCharacteristicForService...')

I'm trying to pull data from a glucose monitor. I've connected successfully and have the correct UUIDs for the relevant services and characteristics but I'm getting the error below:
TypeError: undefined is not a function (near '...device.monitorCharacteristicForService...')
Does anyone know why this might be? Code below shows the connecting function and the attempt to monitor the data. Both are being i nitiated by button presses.
Note I'm trying to run on android.
const connectDevice = device => {
manager.stopDeviceScan();
manager.connectToDevice(device.id).then(async device => {
await device.discoverAllServicesAndCharacteristics();
manager.stopDeviceScan();
setDisplayText(`Device connected\n with ${device.name}`);
setConnectedDevice(device);
setDevices([]);
device.services().then(async service => {
console.log(service)
})
}
);
}
const getData = async device => { await
device.monitorCharacteristicForService(
'00001808-0000-1000-8000-00805f9b34fb',
'00002A18-0000-1000-8000-00805f9b34fb',
(error, characteristic) =>{
if (error) {
console.error("Error at receiving data from device", error);
return;
} else {
console.log('Characteristic', characteristic)
}},
)};

Vuejs error after passing axios interceptor

I have a problem that I can't solve with vue.js
I intercept queries that return an error (axios interceptor), and when it passes through this interceptor, the catch of the axios query is still taken into account.
Except that I wait for an error "error.api". which I don't receive, so it generates a console error.
Here is the code:
axios.interceptors.response.use(null, error => {
let path = '/login';
switch (error.response.status) {
case 401: path = '/login'; break;
case 404: path = '/404'; break;
}
store.commit('logout')
router.push(path);
return Promise.reject(error);
});
this error
2.js:376 Uncaught (in promise) TypeError: Cannot read property 'api' of undefined
And finally, the axios query and the error is generated by the last line (err.api[0])
deleteApi(id) {
this.$store.dispatch('deleteApi', id)
.then((res) => {
this.$toast.success(res.data.success)
this.deleteApiModal(id)
})
.catch(err => this.$toast.error(err.api[0]))
},
I finally found a solution but very dirty, which I find repetitive for not much.
It's on each call axios, to put a condition that checks if "err" exists...
I would have preferred to be able to interact on the interceptor to have managed this in only one place.
If someone has a better solution, I'll take it !
deleteApi(id) {
this.$store.dispatch('deleteApi', id)
.then((res) => {
this.$toast.success(res.data.success)
this.deleteApiModal(id)
})
.catch(err => { if(err) this.$toast.error(err.api[0]) })
},

RxJS HTTP request error handling

In my project, I use RxJS to handle HTTP request. I came into a confusing point about the error handling part as following:
.switchMap((evt: any) => {
return http.getComments(evt.params)
.map(data => ({ loading: false, data }))
.catch(() => {
console.log('debugging here');
return Observable.empty();
});
})
in the above code, inside the switchMap operator, I use the http.getComments function to send request, which is defined by myself as following:
getComments(params) {
return Observable.fromPromise(
this.io.get(path, { params })
);
}
in this function, I use fromPromise operator convert the returned Promise to observable.
The problem is when HTTP request failed, the catch operator inside switchMap can not work, the debugging console can't output. So what's wrong with my code.
Do you really need to catch the error inside the switchMap anyway? You can handle your error in your source if you want.
.switchMap((evt: any) =>
http.getComments(evt.params).map(data => ({ loading: false, data }))
})
.subscribe(console.log, console.error);
Any way, your source code does not look to have any error, maybe your promise is not been rejected when the http fails and is just resolving with an error as a response (this is a guess because I've seen that before)
Your code should work. Here a simplified simulation, where http calls are substituted by a function which raises an error.
import {Observable} from 'rxjs';
function getComments(params) {
return Observable.throw(params);
}
const params = 'abc';
Observable.of(null)
.switchMap(_ => {
return getComments(params)
.map(data => ({ loading: false, data }))
.catch(err => {
console.log('debugging here', err);
return Observable.empty();
});
})
.subscribe(
console.log,
error => console.error('This method is not called since the error is already caught', error),
() => console.log('DONE')
)

Relay subscriptions not working with react-native

I'm using Express Graphql server with react native and Relay. My device does connects to the subscription but it does not subscribe to it. Here's my index.js on the server
const subscriptionServer = SubscriptionServer.create(
{
execute,
subscribe,
schema,
onOperation: (message, params, webSocket) => {
console.log(params)
return params;
},
onConnect: () => {
// My device does connects
console.log("client connected")
}
},
{
server,
path: '/subscriptions'
},
);
app.use('/graphql', graphqlHTTP({
schema,
graphiql: true
}));
app.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
subscriptionsEndpoint: `ws://127.0.0.1:8080/subscriptions`
}));
server.listen(PORT, ()=> {
console.log("Groceries running on port " + PORT)
console.log(
`subscriptions is now running on ws://localhost:${PORT}/subscriptions'}`
);
});
The resolver for subscription on the server, it was quite troublesome to figure out since everyone is using executable schema from apolloGraphql.
export default {
type: OrderEdges,
args: {
ShopId: {type: GraphQLID},
},
subscribe: withFilter(() => pubsub.asyncIterator('orderConfirmed'), (payload, variables) => {
console.log(payload)
console.log(variables)
return payload.orderConfirmed.node.ShopId == variables.ShopId;
}),
}
Now the react-native client. My subscription setup with relay environment.
const setupSubscriptions = (config, variables, cacheConfig, observer) => {
const query = config.text; //does console logs the query
const subscriptionClient = new SubscriptionClient(`ws://192.168.0.100:8080/subscriptions`, {reconnect:true});
subscriptionClient.request({query, variables}, (err, result) => {
console.log(err) // doesn't get call inside the request method
observer.onNext(data:result)
})
}
My subscription method,
export default function() {
const variables = {
ShopId: shop.getShop()[0].id
}
requestSubscription(
environment,
{
subscription,
variables,
onCompleted: (res, err) => {
console.log(res)
console.log(err)
},
updater: (store) => {...},
onError: error => console.error(error),
onNext: (response) => {console.log(response)}
});
}
the component where I'm calling to subscribe,
import subscription from '../../GraphQLQueries/subscriptions/orderConfirmed';
class OrdersBox extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
//initializing subscription
orderSubscriptions();
}
When the device starts the app, my device is connected to the web socket as I can see the console.log statement inside the onConnect method in SubscriptionServer. But when the payload is published after a mutation, the subscribe method doesn't get called. I can't seem to figure out what I'm doing wrong. Maybe it's some react-native specific config that I'm missing cuz everything seems to work fine when I test it on graphiql.
I can't find any example of react-native and relay subscriptions used with express graphql.
note: Everything is working when I use subscription with graphiql. But not with react-native and relay.
Thanks in advance guys
....
I wasn't returning the subscriptionClient.request method. Adding a return statement solved the problem. You don't have to return when using subscribe method in subscriptions-transport-ws#0.8.3. But version 0.9.1 replaces the subscribe function with request which does require it to return.
try:
function setupSubscription(config, variables, cacheConfig, observer) {
const query = config.text;
const subscriptionClient = new SubscriptionClient(websocketURL, {
reconnect: true
});
const client = subscriptionClient.request({ query, variables }).subscribe({
next: result => {
observer.onNext({ data: result.data });
},
complete: () => {
observer.onCompleted();
},
error: error => {
observer.onError(error);
}
});
return {
dispose: client.unsubscribe
};
}
subscriptions-transport-ws#0.9.1

Compressing base64 encoded images in React-Native on Android does not recognise 'data' protocol

Issue
Within a React-Native (0.43) application we are using a component that uses a SectionList to render photos sorted by day. Each section can contain multiple images. Photos are taken using the react-native-image-crop-picker library and uploaded to the backend, or queued locally if no internet connection is available, encoded in base64 format. The image resolution is set to 800x800 pixels (requirement for other purposes of the images). On phones with lower memory, rendering ~20 images will crash the app due to insufficient memory. This issue can only be reproduced on low-end Android phones but I expect this to be a low memory issue and not related to the OS. To tackle this issue, thumbnails need to be generated to test if this is the case. Independent of when these thumbnails are generated (before sending to server or on-the-fly before loading component). The code below works fine for iOS but for Android it throws the error: Unknown protocol: data which comes from the ImageEditor.cropImage() function.
Snippet from main .js file
//The mergeReduxWithMeteor function takes care of merging the redux state,
//containing images not yet uploaded to the server,
//and the Meteor data as received by the server.
//No issues here...
helpers.mergeReduxWithMeteor(props.photoStore, props.SynergySummaryReady ? props.SynergyData : [])
//The imageHelper.compressPhoto does the actual compression
//No issues with the promise chain as is.
.then((data) => {
return Promise.all(data.map(imageHelper.compressPhoto))
})
// The remaining functions take care of the formatting for the SectionList.
// No issues here either... :)
.then((data) => {
return helpers.clusterDataByDay(data)
})
//We populate the resulting data in the state that is used for the SectionList
.then((data) => {
this.setState({NotHorusData: data})
})
.catch((error) => console.error(error))
imageHelper.compressphoto()
export function compressPhoto(photo) {
return new Promise((resolve, reject) => {
let imageSize = {
offset: {
x: 0,
y: 0
},
size: {
width: IMAGE_SIZE,
height: IMAGE_SIZE
},
displaySize: {
width: IMAGE_TARGET_SIZE,
height: IMAGE_TARGET_SIZE,
},
resizeMode: 'contain'
}
ImageEditor.cropImage(`data:image/jpeg;base64,${photo.data.userPhoto}`, imageSize, (imageURI) => {
ImageStore.getBase64ForTag(imageURI, (base64Data) => {
resolve({
...photo,
data: {
...photo.data,
userPhoto: base64Data,
}
})
}, (error) => reject(error))
}, (error) => reject(error))
})
}
Approach 1: Fix data protocol issue on Android
Issue on Github from RN addresses the same issue but no solution is provided.
Approach 2: Bypass data protocol issue by providing uri on Android
Although less favourable due to the added communication/delay, another approach is to avoid the data protocol issue by providing a temporary URI provided by ImageStore. See the adapted code below for Android.
if(Platform.OS === 'android'){
ImageStore.addImageFromBase64(`data:image/jpeg;base64,${photo.data.userPhoto}`, (tempURI) => {
ImageEditor.cropImage(tempURI, imageSize, (imageURI) => {
ImageStore.getBase64ForTag(imageURI, (base64Data) => {
ImageStore.removeImageForTag(tempURI)
resolve({
...photo,
data: {
...photo.data,
userPhoto: base64Data,
}
})
}, (error) => reject(error))
}, (error) => reject(error))
}, (error) => reject(error))
}
Unfortunately ImageStore.addImageFromBase64 is not recognised on Android.
Does anyone have any experience with ImageEditor and ImageStore on Android that might be helpful in this situation? Any other approaches are welcome too!
I managed to resolve the issue with the use of react-native-fetch-blob and react-native-image-resizer for both iOS and Android. Performance is unexpectedly good in comparison to the implementation in the question above. I shared the code below for others to use :)
export function compressPhoto(photo) {
return new Promise((resolve, reject) => {
let tempUri = `${cache}/Vire_${photo.data.userPhotoDate}.jpg`
fs.writeFile(tempUri, photo.data.userPhoto, "base64")
.then(() => {
ImageResizer.createResizedImage(
`file:${tempUri}`, IMAGE_TARGET_SIZE, IMAGE_TARGET_SIZE, "JPEG", 100, 0).then((resizedImageUri) => {
fs.readFile(`${resizedImageUri}`, "base64")
.then( data => {
resolve({...photo, data: { ...photo.data, userPhoto: data }})
})
.catch(error => reject(`readFile:error: ${error}`))
},
(error) => reject(`createResizedImage:error: ${error}`)
)
})
.catch( error => {
reject(`writeFile:error: ${error}`)
})
})
}
The gist is storing base64 encoded picture in the cache-directory and using imageResizer to fetch the image, compress it, and read it again in base64 for use.