How to run and read bluetoothctl commands outputs from NodeJS? - javascript

I want to periodically run commands to bluetoothctl via NodeJS, and be able to read the output of those commands.
For example I'd want to run the scan on, and get the output. As well as running devices and read the list. It's not matter that is a string, I can parse it, but I need to be able to interact with the bluetoothctl program.
The problem is that when you type in the terminal the command bluetoothctl it brings you in a "manager" like view, where I guess Node cannot read data from? Am I wrong?
I'm kinda lost, and I couldn't find anything useful. I've found some NodeJS bluetoothctl wrappers, but they're all old and requires deprecated versions of node..
Edit
Here's the code that I have so far. But the problem is that I don't get the expected output from the commands that I run, but instead I get the name of the command that I've called...
import * as cp from 'child_process';
async function sleep(ms) {
await new Promise(r => setTimeout(() => r(), ms));
return;
}
function log(m: string) {
console.log(`[${ShellyBluetoothScanner.name}] ${m}`);
}
export class ShellyBluetoothScanner {
bluetoothctl: cp.ChildProcessWithoutNullStreams;
constructor() {
this.setup();
}
async run() {
log('Running scan and devices list in 2s...');
await sleep(2000);
log('Enabling bluetooth');
this.bluetoothctl.stdin.write('power on');
await sleep(2000);
log('Claering devices');
this.bluetoothctl.stdin.write('remove *');
log('Scan devices for 3s');
this.bluetoothctl.stdin.write('scan on');
await sleep(3000);
log('Print devices');
this.bluetoothctl.stdin.write('devices');
}
private setup() {
log('INFO: Setting up bluetooth');
this.bluetoothctl = cp.spawn('bluetoothctl');
this.bluetoothctl.stdout.on('data', m => console.log('STDOUT Data - ', m.toString()));
this.bluetoothctl.stdout.on('error', error => console.log('STDOUT Error - ', error.message));
log('INFO: Bluetooth setup completed');
}
}
const SBTS = new ShellyBluetoothScanner();
SBTS.run();

I don't believe bluetoothctl was ever intended to be run in this way. It certainly has no documented API and I have seen the commands subtly change in the tool over time which will break your script.
A better way to achieve this is to use the D-Bus API that is documented and intended for this use.
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/adapter-api.txt
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt
There are bindings available at: https://www.npmjs.com/package/dbus
I am sure there are also libraries that maybe helpful. Maybe https://www.npmjs.com/package/node-ble

Related

DiscordJS | I can't get to send a message to an channel through its ID

It's been 1h30 that i'm trying to get my little discord bot to work...
It's main purpose is to spy on a minecraft server and send a message in a specific channel to tell me the server is on or off. However, that's where i can't get anywhere farther...
At this point, my bot responds to my commands and everything is fine, my problem is that i cant use my channel ID to 'select' the target of the message...
My version of discord.js is 14.6.0
Here's my code :
client.channels.cache.get('1039922510755549254')
// and it returns "undefined"
for the rest of my code, it's all copy pasted from de V14 documentation and work fine without the snippet above...
But here it is nonetheless : https://codepen.io/angrysquirrell/pen/bGKWNmg
it's weird because I ctrl+c / ctrl+v the documentation... ( https://discordjs.guide/popular-topics/faq.html#how-do-i-send-a-message-to-a-specific-channel )
Also, i checked that the bot has access to the channel...
Thanks for your help :)
(Sorry if there's any mistakes, english is not my primary language)
I tried :
client.channels.cache.get('1039922510755549254')
//
client.channels.cache.find('ressources')
//
client.channels.cache.find( channel => channel.name === channelName)
and it always returned "undefined", although i should get an object...
The error i get each time is :
file:///C:/Users/guigu/Desktop/Discord%20bot/main.js:72
await channel.send("Hi!");
^
TypeError: channel.send is not a function
at file:///C:/Users/guigu/Desktop/Discord%20bot/main.js:72:15
at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:530:24)
at async loadESM (node:internal/process/esm_loader:91:5)
at async handleMainPromise (node:internal/modules/run_main:65:12)
nb : i tried all i could find on internet but without any success...
So, I'm guessing the Channel object isn't in your cache.
const channel = client.channels.fetch("CHANNEL_ID");
That won't work because the fetch() method returns a Promise, not a GuildChannel, like you want.
So, there are three ways we can go about it:
#1 - Resolving the promise.
Promise.resolve(client.channels.fetch("CHANNEL_ID")).then((channel) => {
channel.send({ content: "Something cool!" });
});
#2 - Fetching then trying again.
await client.channels.fetch("CHANNEL_ID");
// Note: The "await" keyword is only available in async functions (or top-level bodies of modules).
client.channels.cache.get("CHANNEL_ID").send({ content: "Something awesome!" });
#3 - Using the await keyword on the Promise.
I'm not too certain on this one working, I think I might have tried it awhile ago with something and found that it works. If it doesn't, the other two solutions are much more viable.
await client.channels.fetch("CHANNEL_ID").send({ content: "Something odd!" });
async functions
Since I doubt you'll be using your client instance at the top of a module, we'll use an async function. It isn't hard to change a normal function into an async one.
client.on("messageCreate", async(message) => {
});
And that's an async function. If you want to know more about them, here's the official documentation for them:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

How locate the row where the output statement resides in nodejs

As we all know, we can easy to see the line of an output statement in the browser, just like follow picture
enter image description here
but in the nodejs env, how do I know what line is 'output statement' in.
I have this need because I want to know better during development where the information is coming from when the program fails. Of course, I could have each output statement carry a unique character, like console.log('1', '...'), console.log('2', '...') but that feels silly and unhackable to me.
I'll show you a simple piece of code as an illustration
try {
throw new Error('something error')
} catch (error) {
console.log(error.stack)
}
Run the above code I can see the output:
Error: something error
at file:///c:/Users/Linhieng/Desktop/tmp/a.js:2:9
at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
at async loadESM (node:internal/process/esm_loader:88:5)
at async handleMainPromise (node:internal/modules/run_main:61:12)
the above output tell us what line is the error in, but I want to know the line of console.log.
You can monkeypatch console.log with code that parses the stack string, since this is Node.js and the format only varies across releases (unlike on browsers, where it can vary by browser as well):
const realLog = console.log;
console.log = (...msgs) => {
try {
throw new Error("something error");
} catch (error) {
const lines = error.stack.split(/(?:\r\n|\r|\n)+/);
msgs.push(`[${lines[2].trim()}]`);
}
realLog(...msgs);
};
Then for instance, this:
function example() {
console.log("Hi there");
}
example();
shows
Hi there [at example (file:///____/temp.js:13:13)]
At present, the "parsing" is really easy — just split on newlines and take the third element of the array. But you might want to extract more information, or the format could change in future versions to require more complicated "parsing."
I thing woth simple logging the only solution here is a manually passing the according line number. Something like that:
console.log(error, LINE_NUMBER);
Another possible solution probably could be when you use some kind of a external configurable NodeJS debugger software. There probably will be provided a functionality related you your needs.

supertest failing with ECONNRESET

I'm working on a Node.js project and trying to write test cases for the app.
The endpoints are working perfectly fine when I run them in Postman. But when I run the test cases, some of them, (Usually the first one in the order) fails with the error
- Error: read ECONNRESET
I have tried debugging it, searched for a potential solution, but I'm unable to fix it. I'm working with jasmine/supertest for the first time. Maybe I'm missing something I'm unable to anticipate but I haven't been able to find out the issue.
Can anybody help me out with this? Thanks a bunch in advance.
Here is my test code.
it('Gets Users List', async() => {
const response = await request.get('/users')
expect(response.status).toBe(200);
})
and my Controller function
export const index = async (req:Request, res: Response) => {
try {
const users : DataObject = await model.index()
res.status(users.status);
res.json(users.data);
} catch (error) {
res.status(NOT_FOUND);
res.json(error);
}
}
The peculiar behavior that I observed is when I add another method before this one, then this method works fine and the first one returns the same error.
I assume the first call is rejected due to the fact that connection was not established yet? I'm not sure though.
Anybody familiar with this issue?
Thanks in advance.

Handling errors and recoverying with node pg (postgres) client

I am using node module pg in my application and I want to make sure it can properly handle connection and query errors.
The first problem I have is I want to make sure it can properly recover when postgres is unavailable.
I found there is an error event so I can detect if there is a connection error.
import pg from 'pg'
let pgClient = null
async function postgresConnect() {
pgClient = new pg.Client(process.env.CONNECTION_STRING)
pgClient.connect()
pgClient.on('error', async (e) => {
console.log('Reconnecting')
await sleep(5000)
await postgresConnect()
})
}
I don't like using a global here, and I want to set the sleep delay to do an small exponential backoff. I noticed "Reconnecting" fires twice immediately, then waits five seconds and I am not sure why it fired the first time without any waiting.
I also have to make sure the queries execute. I have something like this I was trying out.
async function getTimestamp() {
try {
const res = await pgClient.query(
'select current_timestamp from current_timestamp;'
)
return res.rows[0].current_timestamp
} catch (error) {
console.log('Retrying Query')
await sleep(1000)
return getTimestamp()
}
}
This seems to work, but I haven't tested it enough to make sure it will guarantee the query is executed or keep trying. I should look for specific errors and only loop forever on certain errors and fail on others. I need to do more research to find what errors are thrown. I also need to do a backoff on the delay here too.
It all "seems" to work, I don't want to fail victim to the Dunning-Kruger effect. I need to ensure this process can handle all sorts of situations and recover.

JS Program using Async & Recursion gets stuck in Main process

I am trying to retrieve the Firebase users in a project. I can retrieve them, but the main program never ends. I debug using VS Code or run the script with npm run and it gets stuck both ways. In VS Code there is nothing left on the stack...it just never stops
**Users function (It returns the users without a problem)
admin.auth().listUsers returns a listUsersResult object with properties nextPageToken and a users array
const BATCH_SIZE = 2;
const listAllUsers = async (nextPageToken = undefined) => {
let listUsersResult = await admin.auth().listUsers(BATCH_SIZE, nextPageToken);
if (listUsersResult.pageToken) {
return listUsersResult.users.concat(await listAllUsers(listUsersResult.pageToken));
} else {
return listUsersResult.users;
}
};
Main Routine (this is the one that gets stuck)
const uploadUsersMain = async () => {
try {
// if I comment out this call, then there is no problem
let firestoreUsers = await listAllUsers();
} catch(error) {
log.error(`Unable to retrieve users ${error}`)
}
finally {
// do stuff
}
}
uploadUsersMain();
What could be the issue that stops the main program from ending? What should I look for? Thanks
To shut down your script you should use
await admin.app().delete();
Node.js will quietly stay running as long as there are handles, which can really be anything — a network socket certainly.
You could also use process.exit(), but it's good practice to properly shut down the SDK, instead of exiting abruptly when it might not be finished.

Categories