npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@trippnology/lib-js8call

v1.0.3

Published

A library to interface with JS8Call (js8call.com)

Downloads

37

Readme

lib-js8call

A library to help you interface your NodeJS app with JS8Call (tested with JS8Call v2.2.0).

What can I use this for?

Integrate JS8Call into your existing app, or come up with something entirely new! Here are a couple of apps that use this library:

  • js8-cli - Pipe text from anywhere into JS8Call via the command line.
  • JS8Assistant - Companion app that adds some nifty features to make your JS8 sessions more fun and useful.

How about an LED "ON AIR" light to show when you are transmitting? A Rasperry Pi and the Johnny Five library are an easy way to hook up all sorts of hardware. The only limit is your imagination! If you make something cool, create an issue with the details, and I'll add you to the list.

Installation

npm install @trippnology/lib-js8call

Usage

const js8 = require('@trippnology/lib-js8call')();
// Note the extra () at the end

You can now listen to events and act on them as you wish. It's a good idea to wait for a tcp.connected event before you try to interact with JS8Call:

js8.on('tcp.connected', (connection) => {
	// At this point, we have setup the connection
	console.log(
		'Server listening %s:%s Mode: %s',
		connection.address,
		connection.port,
		connection.mode
	);
	// You can now safely do your thing!
	MyApp.init();
});

If you don't want to auto connect, disable TCP and connect when you're ready:

const js8 = require('@trippnology/lib-js8call')({ tcp: { enabled: false } });
// Later, when your app is ready...
js8.tcp.connect().then((connection) => {
	console.log(connection);
});

You can either listen to the "firehose" packet event, emitted on every message we get from JS8Call:

js8.on('packet', (packet) => {
	// Do your custom stuff
	processPacket(packet);
});

... or individual events you are interested in:

js8.on('rig.ptt', (packet) => {
	console.log('[Rig] PTT is %s', packet.value);
});

You can find runnable examples of both approaches in demo/manual-processing.js and demo/individual-events.js respectively.

Don't forget to handle errors:

js8.on('error', (err) => {
	console.log('Something went wrong:');
	console.error(err);
});

Events

Individual event names mirror the JS8Call JSON API, with a few additions:

| Name | Description | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | error | Something went wrong | | rig.ptt.on | PTT has been enabled | | rig.ptt.off | PTT has been disabled | | rig.safe_to_tx | Returns true when PTT is off AND the send buffer is empty. | | rx.directed.to_me | Received a RX.DIRECTED packet addressed to the station callsign. Will change to rx.directed.me when enabled in JS8Call. See #5 | | tcp.connected | Successfully connected to JS8Call via TCP. Returns a connection object with address, port, and mode keys. | | tcp.disconnected | The connection to JS8Call has been closed or dropped. | | tcp.error | Something went wrong with the TCP connection. Returns an error. | | udp.connected | Listening for messages from JS8Call. Returns a connection object with address, port, and mode keys. | | udp.error | Something went wrong with the UDP connection. Returns an error. |

Please note that while JS8Call uses FULL CAPS for message types, event names are in all lower case.

Options

You can pass in any options you wish to set manually when you require the module. Sensible defaults will be provided for anything you omit.

const js8 = require('@trippnology/lib-js8call')({
	debug: true,
	tcp: { host: '192.168.1.123', port: 12345 },
});

Available options

| Option | Type | Default | Description | | -------------------------- | ------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | debug | boolean | false | Enables verbose output | | exit_when_js8call_closed | boolean | true | End the process when we receive a CLOSE message from JS8Call | | get_metadata_at_launch | boolean | true | Queries JS8Call for station metadata at launch. Only available when using TCP. Disable for cli use. | | tcp | object | { auto_reconnect: false, enabled: true, host: 'localhost', port: 2442, seconds_between_reconnect: 5 } | Options for the TCP server | | udp | object | { enabled: false, port: 2332 } | Options for the UDP server |

Features

Sending an API request to JS8Call

This is a low level feature that allows you to construct the request to your own requirements.

// You can send your own JSON string
js8.send(
	'{ "type": "INBOX.STORE_MESSAGE", "params": { "CALLSIGN": "M7GMT", "TEXT": "Testing JSON API" } }'
);
// Or just send an object and it will be converted for you
js8.send({
	type: 'INBOX.STORE_MESSAGE',
	params: { CALLSIGN: 'M7GMT', TEXT: 'Testing JSON API' },
});

Shortcuts

As well as being able to construct your own API messages, some convenience methods and properties have been provided.

Help

| Name | Type | Description | | ------------------------------ | -------- | -------------------------------------------------------------------------------- | | js8.help.valid_message_types | property | Object with 2 keys; incoming and outgoing that list valid API message types. |

Inbox

| Name | Type | Description | | ---------------------------------------- | -------- | ------------------------------------------------------ | | js8.inbox.getMessages() | function | Promise that resolves with an array of message objects | | js8.inbox.storeMessage(callsign, text) | function | Promise that resolves with an INBOX.MESSAGE packet |

Mode

| Name | Type | Description | | ----------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | js8.mode.getSpeed() | function | Promise that resolves with a number representing the current speed. 0 = normal, 1 = fast, 2 = turbo, 4 = slow | | js8.mode.getSpeedDetailed() | function | Promise that resolves with an object with both the setting and a name: { setting: 0, name: 'normal' } | | js8.mode.setSpeed(speed) | function | Promise that resolves with a number representing the current speed. speed should be a number, one of: 0 = normal, 1 = fast, 2 = turbo, 4 = slow |

Rig

| Name | Type | Description | | -------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | js8.rig.getFreq() | function | Promise that resolves with an object containing properties about the current operating frequency | | js8.rig.setFreq(options) | function | Promise that resolves with an object containing properties about the current operating frequency. options should be an object containing at least an OFFSET property, and optional properties DIAL and FREQ | | js8.rig.getPTT() | function | Currently unreliable Promise that resolves with one of; null - the status is unknown, 0 - the PTT is off, or 1 - the PTT is on. | | js8.rig.ptt | property | Currently unreliable The status of the PTT. One of; null - the status is unknown, 0 - the PTT is off, or 1 - the PTT is on. | | js8.rig.safe_to_tx | property | Returns true when PTT is off AND the send buffer is empty. |

RX

| Name | Type | Description | | -------------------------- | -------- | ------------------------------------------------------------------------------- | | js8.rx.getBandActivity() | function | Promise that resolves with an object representing the band activity window. | | js8.rx.getCallActivity() | function | Promise that resolves with an object representing the call window. | | js8.rx.getCallSelected() | function | Promise that resolves with a string containing the currently selected callsign. | | js8.rx.getText() | function | Promise that resolves with a string containing the contents of the QSO window. |

Station

| Name | Type | Description | | ------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- | | js8.station.callsign | property | String containing the station callsign | | js8.station.grid | property | String containing the station grid | | js8.station.info | property | String containing the station info | | js8.station.status | property | The last STATION.STATUS packet received | | js8.station.getMetadata() | function | Promise that resolves with an object with the keys; callsign, grid, info, status. | | js8.station.getCallsign() | function | Promise that resolves with a string containing the station callsign. | | js8.station.getGrid() | function | Promise that resolves with a string containing the station grid. | | js8.station.setGrid(grid) | function | Promise that resolves with a string containing the new station grid. grid should be a string containing a valid Maidenhead locator. | | js8.station.getInfo() | function | Promise that resolves with a string containing the station info. | | js8.station.setInfo(info) | function | Promise that resolves with a string containing the new station info. info should be a string containing the station QTH/info. | | js8.station.getStatus() | function | Promise that resolves with a string containing the station status. | | js8.station.setStatus(status) | function | Promise that resolves with a string containing the new station status. status should be a string containing the station status. |

TCP

| Name | Type | Description | | ------------------- | -------- | -------------------------------------------------------------------------------------- | | js8.tcp.connect() | function | Tries to establish a TCP connection. Promise that resolves with a connection object. |

TX

| Name | Type | Description | | -------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | js8.tx.getText() | function | Promise that resolves with a string containing the contents of the TX window. | | js8.tx.sendMessage(text) | function | Promise that resolves when the message has been transmitted. text should be the string you wish to TX. Will reject if the rig is in use. | | js8.tx.setText(text) | function | Promise that resolves with a TX.TEXT packet. text should be the string you wish to place into the TX window. |

Utils

| Name | Type | Description | | --------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------- | | js8.utils.messageIsToMe(packet) | function | Returns true if the packet is addressed to the configured station callsign. packet should be a packet object. |

Promises

Most functions return a promise, so you can do stuff once it resolves or rejects, if you need to:

js8.tx
	.sendMessage('Your custom text')
	.then(() => {
		console.log('TX finished');
	})
	.catch((err) => {
		console.log('Something went wrong:');
		console.error(err);
	});

Considerations

You will get at error if both TCP and UDP interfaces are enabled at the same time. While this does technically work, it will likely lead to duplicate traffic and headaches for you! TCP only is preferred.


Detecting when JS8Call is TXing is currently unreliable. We currently listen for RIG.PTT messages and cache the value, but a RIG.PTT with a value of offdoesn't mean that the send buffer is empty. As a workaround, we manually check the buffer with js8.tx.getText() when we receive a rig.ptt.off, and if the buffer is empty, we set rig.safe_to_tx to true.

js8.tx.sendMessage() will check the value of rig.safe_to_tx before sending a message:

js8.tx
	.sendMessage('Hello, world!')
	// If it's safe to TX, message is sent and promise resolves
	.then((message) => {
		console.log('Message sent: %s', message);
	})
	// If the rig is busy, the promise rejects
	.catch((err) => {
		console.log(err); // Prints: 'Rig busy'
	});

You can also listen to the rig.safe_to_tx event to monitor this value in your app:

js8.on('rig.safe_to_tx', (safety) => {
	console.log('Is it safe to TX? %s', safety ? 'yes' : 'no');
});

Hopefully, in the future, there will be additional API methods that allow us to check if it is safe to TX before trying to do so. Maybe JS8Call could send a TX.START message when it starts sending a message, and then a TX.END message once the whole transmission has finished or been aborted?

A future enhancement could be a message queue, so users could call js8.tx.sendMessage(), and the message would be sent once the rig becomes available.

Message types

The JS8Call API documentation is incomplete, so we are implementing API features as they are understood. API handling starts here in the source code.

For message types discovered so far, see JS8Call JSON API or console.log(js8.help.valid_message_types) from within your app.

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature develop
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

History

The bulk of this project was written over the Christmas break 2020. Future additions and changes will be noted here.

Credits

Copyright (c) 2021 Rikki Tripp.

A huge thanks to Rick VA1UAV for his feedback, feature suggestions, testing, and bug reports.

License

See LICENSE