refactor, added README
This commit is contained in:
parent
352174cd83
commit
221b739774
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
node_modules/
|
||||
apikey.txt
|
||||
ptt_daemon
|
||||
ptt_daemon
|
||||
config.js
|
@ -8,7 +8,7 @@ function ClientQuery() {
|
||||
this.onMessage = function (data) { };
|
||||
|
||||
this.log = function (msg) {
|
||||
if (!this.debug) { console.log(msg) }
|
||||
if (!this.debug) { console.log('TS3:', msg) }
|
||||
}
|
||||
|
||||
this.parse = function (res) {
|
||||
@ -42,13 +42,18 @@ function ClientQuery() {
|
||||
}.bind(this)
|
||||
|
||||
this.notifyOn = function (action, args, callback) {
|
||||
console.log('Register notify ' + action)
|
||||
if (this.actions[action] === undefined) {
|
||||
console.log('TS3: Register notify ' + action)
|
||||
} else if (this.actions[action] !== callback) {
|
||||
console.log('TS3: Change notify ' + action)
|
||||
}
|
||||
|
||||
this.actions[action] = callback;
|
||||
this.send(`clientnotifyregister event=${action} ${args}`)
|
||||
}
|
||||
|
||||
this.notifyOff = function (action, args) {
|
||||
console.log('Unregister notify ' + action)
|
||||
console.log('TS3: Unregister notify ' + action)
|
||||
this.send(`clientnotifyunregister event=${action} ${args}`)
|
||||
.then(() => {
|
||||
this.actions[action] = undefined;
|
||||
@ -59,7 +64,7 @@ function ClientQuery() {
|
||||
this.log('Request: ' + data)
|
||||
return new Promise(function (resolve, reject) {
|
||||
this.sock.write(data + '\n', 'utf8', (res) => {
|
||||
console.log('Sent: ' + data)
|
||||
console.log('TS3: Sent: ' + data)
|
||||
|
||||
let func = (data) => {
|
||||
if (data.toString() != 'error id=0 msg=ok\n\r') {
|
||||
@ -89,9 +94,7 @@ function ClientQuery() {
|
||||
|
||||
this.reInitActions = function () {
|
||||
let act = this.actions;
|
||||
console.log('actions', Object.keys(act))
|
||||
Object.keys(act).forEach(function (key) {
|
||||
console.log('addNotifyMemes Lol', key, 'schandlerid=1', typeof (act[key]))
|
||||
this.notifyOn(key, 'schandlerid=1', act[key])
|
||||
}.bind(this));
|
||||
}
|
||||
@ -127,7 +130,7 @@ function ClientQuery() {
|
||||
|
||||
|
||||
sock.on('close', () => {
|
||||
console.log('Socket closed, reopening..');
|
||||
console.log('TS3: Socket closed, reopening..');
|
||||
sock.destroy();
|
||||
this.connect(host, port, apikey);
|
||||
});
|
||||
|
23
README.md
23
README.md
@ -0,0 +1,23 @@
|
||||
# ts3_remote_ham
|
||||
|
||||
A simple Node.js app that triggers the PTT line of a transceiver when someone in the same channel of a TeamSpeak 3 server starts speaking.
|
||||
|
||||
## Requirements
|
||||
- TeamSpeak 3 with the [Client Query](https://www.myteamspeak.com/addons/L2FkZG9ucy85NDNkZDgxNi03ZWYyLTQ4ZDctODJiOC1kNjBjM2I5YjEwYjM%3D) plugin, which is pre-installed by default.
|
||||
- If using the serial port, GCC to compile the ptt_daemon.c utility.
|
||||
|
||||
## Supported setups
|
||||
- FLrig via its XML-RPC server. This should be enabled by default in FLrig.
|
||||
- microHam microKeyer via [mhuxd](https://github.com/dj5qv/mhuxd) or really any tty device (RS-232, USB UART adapters). The `ptt_daemon` utility is responsible for enabling the RTS line of the serial port (high = PTT on).
|
||||
|
||||
## Usage:
|
||||
1. Clone the repository, enter it.
|
||||
2. `$ npm i` to install the dependencies.
|
||||
3. `$ npm run compile` to compile the ptt_daemon (optional).
|
||||
4. Start TeamSpeak.
|
||||
5. Go to the menu Tools > Options > Addons and click the button *Disabled* to enable the Client Query plugin.
|
||||
6. Open the plugin's settings and copy the API key. Paste it into the `config.js` file created automatically in step 2.
|
||||
7. `$ npm run start` to run the program.
|
||||
8. If using the serial port implementation, change the provider to "serial" and set the path in `config.js`.
|
||||
|
||||
Be aware that by running this program on a public server may lead to unauthorized transmissions using your rig, or even damage the rig by exceeding the recommended long-time power limits. Make sure to not let the remote client linger unsupervised. You can mute the reception by pressing the *Mute Speakers/Headphones* button (a "sound muted" voice line will be played) through remote desktop on the remote client. It is recommended to change the local capture activation method to push to talk during remote operation.
|
22
config.sample.js
Normal file
22
config.sample.js
Normal file
@ -0,0 +1,22 @@
|
||||
const config = {};
|
||||
|
||||
config.teamspeak = {
|
||||
ip: '127.0.0.1',
|
||||
port: '25639',
|
||||
|
||||
// Key returned by the Client Query plugin in TeamSpeak. Can also be found in ~/.ts3client/clientquery.ini
|
||||
// It should look something like LKT9-ZLDM-LFK0-CLSB-UDEE-2YVJ.
|
||||
apiKey: '',
|
||||
};
|
||||
|
||||
config.provider = 'flrig'; // flrig or serial
|
||||
config.providerOptions = {
|
||||
serial: {
|
||||
port: '/dev/mhuxd/ptt1', // path to the serial port of the radio or the VSP created by mhuxd
|
||||
},
|
||||
flrig: {
|
||||
url: 'http://127.0.0.1:12345', // URL to the FLrig XML-RPC server
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
35
daemon.js
35
daemon.js
@ -1,36 +1,37 @@
|
||||
import * as fs from 'fs';
|
||||
import ClientQuery from "./ClientQuery.js";
|
||||
import flrig from './providers/flrig.js';
|
||||
import mhuxd from './providers/mhuxd.js';
|
||||
import serial from './providers/serial.js';
|
||||
import config from './config.js';
|
||||
|
||||
const apikey = fs.readFileSync('./apikey.txt').toString();
|
||||
const client = new ClientQuery();
|
||||
try {
|
||||
await client.connect('127.0.0.1', '25639', apikey);
|
||||
await client.connect(config.teamspeak.host, config.teamspeak.port, config.teamspeak.apiKey);
|
||||
} catch (error) {
|
||||
console.error('Cannot connect to TS3 query. Is TeamSpeak running?', error);
|
||||
console.error('Cannot connect to TS3 query. Is TeamSpeak running?', error);
|
||||
}
|
||||
|
||||
|
||||
// client.request('sendtextmessage targetmode=2 msg=Node.JS').then( res =>{ console.log(res.toString()) });
|
||||
await new Promise(r => setTimeout(r, 50));
|
||||
|
||||
const speakingUsers = {};
|
||||
const whoamiData = client.parse((await client.request('whoami')).toString());
|
||||
|
||||
const provider = flrig();
|
||||
const provider = {
|
||||
flrig, serial
|
||||
}[config.provider](config.providerOptions);
|
||||
|
||||
client.notifyOn('notifytalkstatuschange', '', data => {
|
||||
let args = client.parse(data.toString());
|
||||
if (args.clid === whoamiData.clid)
|
||||
return;
|
||||
let args = client.parse(data.toString());
|
||||
if (args.clid === whoamiData.clid)
|
||||
return;
|
||||
|
||||
speakingUsers[args.clid] = parseInt(args.status) === 1;
|
||||
if (Object.values(speakingUsers).find(el => el)) {
|
||||
// someone is speaking
|
||||
provider.pttDown();
|
||||
} else {
|
||||
// nobody is speaking
|
||||
provider.pttUp();
|
||||
}
|
||||
speakingUsers[args.clid] = parseInt(args.status) === 1;
|
||||
if (Object.values(speakingUsers).find(el => el)) {
|
||||
// someone is speaking
|
||||
provider.pttDown();
|
||||
} else {
|
||||
// nobody is speaking
|
||||
provider.pttUp();
|
||||
}
|
||||
});
|
||||
|
1
package-lock.json
generated
1
package-lock.json
generated
@ -7,6 +7,7 @@
|
||||
"": {
|
||||
"name": "ts3-remote",
|
||||
"version": "1.0.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL",
|
||||
"dependencies": {
|
||||
"@foxglove/xmlrpc": "^1.3.0",
|
||||
|
@ -4,7 +4,9 @@
|
||||
"description": "TS3 remote client for MicroKeyer PTT.",
|
||||
"main": "daemon.js",
|
||||
"scripts": {
|
||||
"start": "node daemon.js"
|
||||
"start": "node daemon.js",
|
||||
"compile": "gcc -o ptt_daemon ptt_daemon.c",
|
||||
"postinstall": "cp -n config.sample.js config.js"
|
||||
},
|
||||
"type": "module",
|
||||
"author": "ericek111",
|
||||
|
@ -1,14 +1,22 @@
|
||||
import { XmlRpcClient } from "@foxglove/xmlrpc";
|
||||
|
||||
export default function flrig() {
|
||||
const client = new XmlRpcClient(`http://127.0.0.1:12345`);
|
||||
export default function flrig(opts) {
|
||||
const client = new XmlRpcClient(opts.flrig.url);
|
||||
|
||||
const setPtt = async (state) => {
|
||||
try {
|
||||
await client.methodCall('rig.set_ptt', [state]);
|
||||
} catch (ex) {
|
||||
console.error(`Cannot send rig.set_ptt(${state}) to flrig (${opts.flrig.url}) -- perhaps it's not running? ${ex.code ?? 'unknown'} at ${ex.erroredSysCall ?? '?'}`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pttDown: () => {
|
||||
client.methodCall('rig.set_ptt', [1]);
|
||||
setPtt(1);
|
||||
},
|
||||
pttUp: () => {
|
||||
client.methodCall('rig.set_ptt', [0]);
|
||||
setPtt(0);
|
||||
}
|
||||
};
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
export default function() {
|
||||
return {
|
||||
pttDown: () => {
|
||||
spawn('/home/omega/Documents/ts3_remote/ptt_daemon', ['/dev/mhuxd/fsk1', '1']);
|
||||
},
|
||||
pttUp: () => {
|
||||
spawn('/home/omega/Documents/ts3_remote/ptt_daemon', ['/dev/mhuxd/fsk1', '0']);
|
||||
}
|
||||
};
|
||||
};
|
12
providers/serial.js
Normal file
12
providers/serial.js
Normal file
@ -0,0 +1,12 @@
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
export default function serial(opts) {
|
||||
return {
|
||||
pttDown: () => {
|
||||
spawn('./ptt_daemon', [opts.serial.port, '1']);
|
||||
},
|
||||
pttUp: () => {
|
||||
spawn('./ptt_daemon', [opts.serial.port, '0']);
|
||||
}
|
||||
};
|
||||
};
|
@ -24,8 +24,9 @@ int main(int argc, char **argv)
|
||||
int flags;
|
||||
ioctl(fd, TIOCMGET, &flags);
|
||||
|
||||
// The below flags can be replaced by TIOCM_DTR to use the DTR line instead, See $ man "TIOCMSET(2const)"
|
||||
if (rtsEnable != 0) {
|
||||
flags |= TIOCM_RTS;
|
||||
flags |= TIOCM_RTS; // brings the RTS line high
|
||||
} else {
|
||||
flags &= ~TIOCM_RTS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user