Flutter_Blue Read response from write - android-studio

I do not have the Rep to create a tag for Flutter_Blue. But this uses Flutter_Blue in Android Studio.
I am trying to send commands to a device that my company creates devices and I am developing and Android/IOS application that connects to the devices and sends commands and reads what the device returns.
I have transplanted the example code to find devices and then write to them. I have the following code.
_writeCharacteristic(BluetoothCharacteristic c) async {
await device.writeCharacteristic(c, [0x076, 0x0d, 0x0a],
type: CharacteristicWriteType.withResponse);
setState(() {});
}
This sends a v and crlf to a device. How do I read the device response?
Let me know if there is more I need to accomplish this question properly.
I figured it out, See Below

I could be wrong but I found the spot that gets the response i'm looking for.
I Added this
String x = "";
d.forEach((f) => x+=String.fromCharCode(f));
to
_setNotification(BluetoothCharacteristic c) async {
if (c.isNotifying) {
await device.setNotifyValue(c, false);
// Cancel subscription
valueChangedSubscriptions[c.uuid]?.cancel();
valueChangedSubscriptions.remove(c.uuid);
} else {
await device.setNotifyValue(c, true);
// ignore: cancel_subscriptions
final sub = device.onValueChanged(c).listen((d) {
String x = "";
d.forEach((f) => x+=String.fromCharCode(f));
Response = x;
setState(() {
print('onValueChanged $x');
});
});
// Add to map
valueChangedSubscriptions[c.uuid] = sub;
}
setState(() {});
}
and outputs
onValueChanged DT8610CI-7125

Related

Chrome Extension API Calls order and DOM Information

I'm working on an extension that is supposed to extract information from the DOM based specific classes/tags,etc, then allow the user to save the information as a CSV file.
I'm getting stuck on a couple of places and haven't been able to find answers to questions similar enough.
Where I am tripped up at is:
1) Making sure that the page has completely loaded so the chrome.tabs.query doesn't return null a couple of times before the promise actually succeeds and allows the blocksF to successfully inject. I have tried placing it within a settimeout function but the chrome api doesn't seem to work within such the function.
2) Saving the extracted information so when the user moves onto a new page, the information is still there. I'm not sure if I should use the chrome.storage api call or simply save the information as an array and keep passing it through. It's just text, so I don't believe that it should take up too much space.
Then main function of the background.js is below.
let mainfunc = chrome.tabs.onUpdated.addListener(
async(id, tab) => {
if (buttonOn == true) {
let actTab = await chrome.tabs.query({
active: true,
currentWindow: true,
status: "complete"
}).catch(console.log(console.error()));
if (!actTab) {
console.log("Could not get URL. Turn extension off and on again.");
} else {
console.log("Tab information recieved.")
};
console.log(actTab);
let blocksF = chrome.scripting.executeScript({
target: { tabId: actTab[0]['id'] },
func: createBlocks
})
.catch(console.error)
if (!blocksF) {
console.log("Something went wrong.")
} else {
console.log("Buttons have been created.")
};
/*
Adds listeners and should return value of the works array if the user chose to get the information
*/
let listenersF = chrome.scripting.executeScript({
target: { tabId: actTab[0]['id'] },
func: loadListeners
})
.catch(console.error)
if (!listenersF) {
console.log("Listeners failed to load.")
} else {
console.log("Listeners loaded successfully.")
};
console.log(listenersF)
};
});
Information from the DOM is extracted through an event listener on a div/button that is added. The event listener is added within the loadListeners function.
let workArr = document.getElementById("getInfo").addEventListener("click", () => {
let domAr = Array.from(
document.querySelectorAll(<class 1>, <class 2>),
el => {
return el.textContent
}
);
let newAr = []
for (let i = 0; i < domAr.length; i++) {
if (i % 2 == 0) {
newAr.push([domAr[i], domAr[i + 1]])
}
}
newAr.forEach((work, i) => {
let table = document.getElementById('extTable');
let row = document.createElement("tr");
row.appendChild(document.createElement("td")).textContent = work[0];
row.appendChild(document.createElement("td")).textContent = work[1];
table.appendChild(row);
});
return newAr
I've been stuck on this for a couple of weeks now. Any help would be appreciated. Thank you!
There are several issues.
chrome methods return a Promise in MV3 so you need to await it or chain on it via then.
tabs.onUpdated listener's parameters are different. The second one is a change info which you can check for status instead of polling the active tab, moreover the update may happen while the tab is inactive.
catch(console.log(console.error())) doesn't do anything useful because it immediately calls these two functions so it's equivalent to catch(undefined)
Using return newArr inside a DOM event listener doesn't do anything useful because the caller of this listener is the internal DOM event dispatcher which doesn't use the returned value. Instead, your injected func should return a Promise and call resolve inside the listener when done. This requires Chrome 98 which added support for resolving Promise returned by the injected function.
chrome.tabs.onUpdated.addListener(onTabUpdated);
async function onTabUpdated(tabId, info, tab) {
if (info.status === 'complete' &&
/^https?:\/\/(www\.)?example\.com\//.test(tab.url) &&
await exec(tabId, createBlocks)) {
const [{result}] = await exec(tabId, loadListeners);
console.log(result);
// here you can save it in chrome.storage if necessary
}
}
function exec(tabId, func) {
// console.error returns `undefined` so we don't need try/catch,
// because executeScript is always an array of objects on success
return chrome.scripting.executeScript({target: {tabId}, func})
.catch(console.error);
}
function loadListeners() {
return new Promise(resolve => {
document.getElementById('getInfo').addEventListener('click', () => {
const result = [];
// ...add items to result
resolve(result);
});
});
}

Botframework with NodeJS while prompt system doesn't read what user input the value

Azure BotFramework
SDK4
NodeJS
In dialog state I am using 'return await step.prompt' inside async function. But once user enters the value it is not considering the user input value as a input for prompt instead it is going to luisrecognizer for the match.
I have written the similar code for different dialog where it works fine.
Kindly requesting you provide some valuable input.
Azure BotFramework
SDK4
NodeJS
this.addDialog(new WaterfallDialog('OrderStatusDialog', [
async function(step) {
return await step.context.sendActivity(reply);
},
async function(step) {
var cardValue = step.context.activity.value;
if (cardValue) {
if (cardValue.action == "Order_Number") {
return await step.prompt('textPrompt', 'enter order number');
} else if (cardValue.action == "Serial_Number") {
return await step.prompt('textPrompt', 'enter serial number');
} else {
}
}
return await step.next();
// return await step.endDialog();
},
async function (step) {
var cardValue = step.context.activity;
console.log("****** cardValue");
console.log(cardValue);
console.log("****** step After");
console.log(step);
return await step.endDialog();
}
]));
at prompt step it should read the value what user is entering. Also stack is empty when i console the step ..
Unfortunately, you have a few issues with your code. But, hopefully this will help iron them out. I had no issues running the below code.
One, double check which version of Botbuilder you have installed. At least one call ('this.addDialog') I am unfamiliar with, doesn't appear to be a part of the current SDK, and didn't work for me when testing.
Two, configure your bot like below. Technically, you should be able pass the various steps in as you have them in your question. However, something about yours was not work and I couldn't figure out what. The below setup DOES work, however, and conforms to already accepted practices.
Three, your first step calls 'step.context.sendActivity(reply)'. In the next step you are trying to read the returned value of that call. That isn't going to work as sendActivity simply sends a statement from the bot to the user ("Welcome to my bot!", for example). You need to perform a prompt to capture the user's input response (see below).
It looks like you are trying to read a value from a card. Since you didn't supply that bit of code, I faked the value by supplying the 'Order_Number' and 'Serial_Number' via a text prompt from the user.
You should also take advantage of the bot state options. Rather than use the variable 'cardValue', consider using UserState or DialogState to store user values important to the conversation.
Lastly, in this simple example, order and serial numbers will overwrite each other if you pass thru multiple times.
const START_DIALOG = 'starting_dialog';
const DIALOG_STATE_PROPERTY = 'dialogState';
const USER_PROFILE_PROPERTY = 'user';
const ACTION_PROMPT = 'action_prompt';
const ORDER_PROMPT= 'order_prompt';
const SERIAL_PROMPT= 'serial_prompt';
...
class ExampleBot {
constructor(conversationState, userState) {
this.conversationState = conversationState;
this.userState = userState;
this.dialogState = this.conversationState.createProperty(DIALOG_STATE_PROPERTY);
this.userData = this.userState.createProperty(USER_PROFILE_PROPERTY);
this.dialogs = new DialogSet(this.dialogState);
this.dialogs
.add(new TextPrompt(ACTION_PROMPT))
.add(new TextPrompt(ORDER_PROMPT))
.add(new TextPrompt(SERIAL_PROMPT));
this.dialogs.add(new WaterfallDialog(START_DIALOG, [
this.promptForAction.bind(this),
this.promptForNumber.bind(this),
this.consoleLogResult.bind(this)
]));
}
async promptForAction(step) {
return await step.prompt(ACTION_PROMPT, `Action?`,
{
retryPrompt: 'Try again. Action??'
}
);
}
async promptForNumber(step) {
const user = await this.userData.get(step.context, {});
user.action = step.result;
if (user) {
if (user.action == 'Order_Number') {
return await step.prompt(ORDER_PROMPT, 'enter order number');
} else if (user.action == 'Serial_Number') {
return await step.prompt(SERIAL_PROMPT, 'enter serial number');
} else {
}
}
return await step.next();
}
async consoleLogResult(step) {
const user = await this.userData.get(step.context, {});
user.orderNumber = step.result;
console.log('****** cardValue');
console.log(user);
console.log('****** step After');
console.log(step);
return await step.endDialog();
}
async onTurn(turnContext) {
... //Other code
// Save changes to the user state.
await this.userState.saveChanges(turnContext);
// End this turn by saving changes to the conversation state.
await this.conversationState.saveChanges(turnContext);
}
}
Hope of help!
somehow it worked for me after saving conversation state where ever i am replacing the dialog.
await this.conversationState.saveChanges(context);

Create Multiple Jabber Client Echo Bot

Hai Stackoverflowers,
i had try so many ways to fix my problem and i end up with stack over flow
Programming Language:
Typescript
my main goals:
create Client Class as many as i want and can turn on and turn off the Client, the client will be as Bot that echo text from the friendlist
I use node-xmpp-client Library :
https://github.com/chris-rock/node-xmpp-client
My Code :
import * as Client from 'node-xmpp-client'; // Jabber Helper
export class TerminalJabber {
private ter;
private client;
constructor(ter: any) {
this.ter = ter;
this.client = new Client({
jid: this.ter.settings.username,
password: this.ter.settings.password,
});
}
public turnOn(){
// Turn on Jabber
this.client.on('online', () => {
console.log('online');
const stanza = new Client.Element('presence', { })
.c('show').t('chat').up()
.c('status').t('Happily echoing your <message/> stanzas');
this.client.send(stanza);
});
this.client.on('stanza', (stanza) => {
// Message come here and will echo from here
});
// Catch error
this.client.on('error', (e) => {
console.log('------>', e);
});
}
// Turn Off Jabber
public turnOff () {
// Turn Off Jabber
this.client.end();
return true;
}
}
The Problem is, The Bot Can Start, but never will be disconnect when i call a new class and turnOn() and turnOff().
How I call My code:
// Hit URL
/turnOn/:terId
// Hit URL
app.router.get(/turnOn/:id, turnOnController); // for turn On
app.router.get(/turnOff/:id, turnOfController); // for turn Off
TurnOnController(){
// Get data from database using id
const data = Query ~ ;
const terminal = new TerminalId(data)
terminal.turnOn();
}
TurnOffController(){
// Get data from database using id
const data = Query ~ ;
const terminal = new TerminalID(data)
terminal.turnOff();
}
Maybe you have a solution of my problems ?
have been thinking and read so many post about xmpp, but i cant solve this things,
Please help
sincerely,
Thank you
You need to call the turnOff method on the terminal instance before you create new one.
This also means you need to have access to the instance from both controllers.
var terminals = {};
function turnOnController(){
var id = getIdSomehow();
terminal[id] = new TerminalId(data);
terminal[id].turnOn();
}
function turnOffController(){
var id = getIdSomehow();
if (terminal[id])
terminal[id].turnOff();
}

How to read data from nodejs spawn as it is received

I have a small problem with a nodejs program. I'm trying to use the child_process module but the following code will only trigger the data event once I remove my card from a nfc card reader.
The problem is that the output I need is available before the card is removed.
For example if I put my card on the reader it will take half a second to print some lines inculding the card UID.
Then if I don't release the card, the program nfc-poll will still be working but won't output anything. As soon as I remove my card from the reader, it will output something and then close the buffer. This is when the event data is emitted.
What I'd like is to be able to read every byte as soon as possible to emit the card id as soon as possible.
function NFCReader() {
this.reader = new events.EventEmitter()
this.start_process()
}
NFCReader.prototype = {
start_process: function () {
this._process = cp.spawn('nfc-poll', [], {})
this._process.on('close', this.restart_process.bind(this))
//this._process.stdout.on('data', this.handle_data.bind(this))
this._process.stdout.readableFlowing = true
this._process.stdout.on('data', this.handle_data.bind(this))
this._process.stderr.on('data', this.handle_error.bind(this))
},
handle_data: function (data) {
var _data = data.toString()
var uid_lines = _data
.split('\n')
.filter(function (line) {return line.search('UID') >= 0})
if (uid_lines.length != 1) {
this.reader.emit('error', 'Multiple UID found')
return
}
var card_id = uid_lines[0]
.trim()
.split(':')[1].trim()
.replace(/[ ]+/g, ':')
this.reader.emit('card', card_id)
},
}
I tried to use pipe but it doesn't seem to help.
this is a runStream function from my release tools repo:
const stdin = input ? "pipe" : "ignore";
const out = new StringStream();
const child = execspawn(cmd, Object.assign(options, {
stdio: [stdin, "pipe", 2]
}));
child.on("error", e => out.emit("error", e));
if (input) {
input.pipe(child.stdin);
}
return child.stdout.pipe(out);
You can reproduce it or if you'd care to wait a couple days I could release it as a separate module. I guess there may already be something like that though...

Twilio Node JS - filter sms per phone number

I would like to filter sms per phone number and date the SMS was sent using REST API, however the output of the following code is not available outside of client.messages.each() block.
Please advise how I can use the latest sms code sent to the filtered number:
const filterOpts = {
to: '+13075550185',
dateSent: moment().utc().format('YYYY-MM-DD')
};
let pattern = /([0-9]{1,})$/;
let codeCollection = [];
client.messages.each(filterOpts, (record) => {
codeCollection.push(record.body.match(pattern)[0]);
console.log(record.body.match(pattern)[0], record.dateSent);
});
console.log(codeCollection,'I get an empty array here');//how to get
the latest sms and use it
doSomethingWithSMS(codeCollection[0]);
Twilio developer evangelist here.
The each function doesn't actually return a Promise. You can run a callback function after each has completed streaming results by passing it into the options as done like this:
const codeCollection = [];
const pattern = /([0-9]{1,})$/;
const filterOpts = {
to: '+13075550185',
dateSent: moment().utc().format('YYYY-MM-DD'),
done: (err) => {
if (err) { console.error(err); return; }
console.log(codeCollection);
doSomethingWithSMS(codeCollection[0]);
}
};
client.messages.each(filterOpts, (record) => {
codeCollection.push(record.body.match(pattern)[0]);
console.log(record.body.match(pattern)[0], record.dateSent);
});
Let me know if that helps at all.
Do you have access to the length of the array of messages? If so, you can do something like this
const filterOpts = {
to: '+13075550185',
dateSent: moment().utc().format('YYYY-MM-DD')
};
let pattern = /([0-9]{1,})$/;
let codeCollection = [];
var i = 0
client.messages.each(filterOpts, (record) => {
if (i < messages.length){
codeCollection.push(record.body.match(pattern)[0]);
console.log(record.body.match(pattern)[0], record.dateSent);
i++;
else {
nextFunction(codeCollection);
}
});
function nextFunction(codeCollection){
console.log(codeCollection,'I get an empty array here');
doSomethingWithSMS(codeCollection[0]);
}
messages.each() is running asynchronously, so your main thread moves on to the next call while the client.messages() stuff runs on a background thread. So, nothing has been pushed to codeCollection by the time you've tried to access it. You need to somehow wait for the each() to finish before moving on. Twilio client uses backbone style promises, so you can just add another .then() link to the chain, like below. You could also use a library like async which lets you use await to write asynchronous code in a more linear looking fashion.
const filterOpts = {
to: '+13075550185',
dateSent: moment().utc().format('YYYY-MM-DD')
};
let pattern = /([0-9]{1,})$/;
let codeCollection = [];
client.messages.each(filterOpts, (record) => {
codeCollection.push(record.body.match(pattern)[0]);
console.log(record.body.match(pattern)[0], record.dateSent);
}).then(
function() {
console.log(codeCollection,'I get an empty array here');
if( codeCollection.count > 0 ) doSomethingWithSMS(codeCollection[0]);
}
);

Resources