Skip to content

Instantly share code, notes, and snippets.

@bkram
Last active February 16, 2024 14:04
Show Gist options
  • Save bkram/bdd3ac50cba7f5df224e7bd15e524ff6 to your computer and use it in GitHub Desktop.
Save bkram/bdd3ac50cba7f5df224e7bd15e524ff6 to your computer and use it in GitHub Desktop.
fm-dx-console.js
// (c) Bkram
// Console client for https://github.com/NoobishSVK/fm-dx-webserver
// No audio (yet)
// Import necessary libraries
const blessed = require('blessed'); // Library for creating terminal-based UI
const WebSocket = require('ws'); // WebSocket library for communication
const argv = require('minimist')(process.argv.slice(2)); // Library for parsing command-line arguments
// Check if required arguments are provided
if (!argv.url) {
console.error('Usage: node script.js --url <websocket_address>');
process.exit(1);
}
// Extract websocket address from command line arguments
const websocketAddress = argv.url;
// Create a Blessed screen
const screen = blessed.screen({ smartCSR: true });
// Create a title element
const title = blessed.text({
top: 0,
left: 0,
width: '100%', // Set width to occupy the full width of the screen
content: ` fm-dx-webserver console - URL: ${websocketAddress}`, // Include the URL
tags: true,
style: {
fg: 'white',
bg: 'blue',
bold: true // Make the title bold
},
});
// Create a clock widget
const clock = blessed.text({
top: 0,
right: 0,
width: '10%', // Set width to occupy 20% of the screen
align: 'right',
content: '{bold}00:00{/bold}', // Initial placeholder content
tags: true,
style: {
fg: 'white',
bg: 'blue'
},
});
// Create a box to display main content
const mainBox = blessed.box({
top: 1, // Leave space for the title
left: 0,
width: '28%', // Occupy 80% of the screen width
height: '50%', // Reduce height to accommodate the additional view below
tags: true,
border: { type: 'line' },
style: { fg: 'white', border: { fg: '#f0f0f0' } },
});
// Create a box for City, Distance, and Station
const cityDistanceStationBox = blessed.box({
top: 1,
left: '26%', // Position it to the right of the main box
width: '40%', // Occupy 50% of the screen width
height: '50%', // Occupy 40% of the screen height
tags: true,
border: { type: 'line' },
style: { fg: 'white', border: { fg: '#f0f0f0' } },
});
// Create a box to display help information
const helpBox = blessed.box({
top: 1, // Leave space for the title
left: '60%', // Position it to the right of the main box
width: '40%', // Occupy 20% of the screen width
height: '50%', // Same height as the main box
content: '{center}{bold}Help{/bold}{/center}\n Press keys:\n \'q\' to decrease by 1000 kHz\n \'w\' to increase by 1000 kHz\n \'z\' to decrease by 10 kHz\n \'x\' to increase by 10 kHz\n \'a\' to decrease by 100 kHz\n \'s\' to increase 100 kHz\n \'e\' to quit',
tags: true,
border: { type: 'line' },
style: { fg: 'white', border: { fg: '#f0f0f0' } },
});
// Create a box for RT0 and RT1
const rtBox = blessed.box({
top: '50%', // Position it below the main box
left: 0,
width: '100%', // Occupy 50% of the screen width
height: '25%', // Occupy 40% of the screen height
tags: true,
border: { type: 'line' },
style: { fg: 'white', border: { fg: '#f0f0f0' } },
});
// Append title, clock, main box, help box, rt box, and cityDistanceStation box to the screen
screen.append(title);
screen.append(clock);
screen.append(mainBox);
screen.append(cityDistanceStationBox);
screen.append(helpBox);
screen.append(rtBox);
// Function to update the main box content
function updateMainBoxContent(content) {
mainBox.setContent(content);
screen.render();
}
// Function to update the RT box content
function updateRTBoxContent(rt0, rt1) {
rtBox.setContent(`{center}{bold}Radiotext{/bold}{/center}\n{center}${rt0.trim()}{/center}\n{center}${rt1.trim()}{/center}`);
screen.render();
}
// Function to update the City, Distance, and Station box content
function stationData(city, distance, station, power, country, polarization, azimuth) {
cityDistanceStationBox.setContent(`{center}{bold}Station Data{/bold}{/center}\n Station: ${station}\n City: ${city}, ${country}\n Distance: ${distance} km\n Power: ${power} kW [${polarization}]\n Country: ${country}\n Azimuth: ${azimuth}`);
screen.render();
}
// Update clock function
function updateClock() {
const now = new Date();
const hours = ('0' + now.getHours()).slice(-2); // Get hours in 2-digit format
const minutes = ('0' + now.getMinutes()).slice(-2); // Get minutes in 2-digit format
const timeString = `${hours}:${minutes}`;
clock.setContent(`{right}{bold}${timeString}{/bold}{/right}`);
screen.render();
}
// Update clock every second
setInterval(updateClock, 1000);
// Initialize JSON data variable
let jsonData = null;
// WebSocket setup
const ws = new WebSocket(websocketAddress);
// WebSocket event handlers
ws.on('open', function () {
updateMainBoxContent('WebSocket connection established');
});
ws.on('message', function (data) {
try {
jsonData = JSON.parse(data);
const content = `{center}{bold}Tuner{/bold}{/center}\n PS: ${jsonData.ps}\n PI: ${jsonData.pi}\n Frequency: ${jsonData.freq}\n Signal: ${jsonData.signal}\n Stereo: ${jsonData.st}\n `;
updateMainBoxContent(content);
if (jsonData && jsonData.txInfo) {
stationData(jsonData.txInfo.city, jsonData.txInfo.distance, jsonData.txInfo.station, jsonData.txInfo.erp, jsonData.txInfo.itu, jsonData.txInfo.pol, jsonData.txInfo.azimuth);
}
if (jsonData && jsonData.rt0 !== undefined && jsonData.rt1 !== undefined) {
updateRTBoxContent(jsonData.rt0, jsonData.rt1);
}
} catch (error) {
console.error('Error parsing JSON:', error);
}
});
ws.on('close', function () {
updateMainBoxContent('WebSocket connection closed');
});
// Listen for key events
screen.on('keypress', function (ch, key) {
if (key.full === 's') { // Decrease frequency by 100 kHz
if (jsonData && jsonData.freq) {
const newFreq = (jsonData.freq * 1000) + 100;
ws.send(`T${newFreq}`);
}
} else if (key.full === 'a') { // Increase frequency by 100 kHz
if (jsonData && jsonData.freq) {
const newFreq = (jsonData.freq * 1000) - 100;
ws.send(`T${newFreq}`);
}
} else if (key.full === 'q') { // Decrease frequency by 1 MHz
if (jsonData && jsonData.freq) {
const newFreq = (jsonData.freq * 1000) - 1000;
ws.send(`T${newFreq}`);
}
} else if (key.full === 'w') { // Increase frequency by 1 MHz
if (jsonData && jsonData.freq) {
const newFreq = (jsonData.freq * 1000) + 1000;
ws.send(`T${newFreq}`);
}
} else if (key.full === 'z') { // Decrease frequency by 0.01 MHz
if (jsonData && jsonData.freq) {
const newFreq = (jsonData.freq * 1000) - 10;
ws.send(`T${newFreq}`);
}
} else if (key.full === 'x') { // Increase frequency by 0.01 MHz
if (jsonData && jsonData.freq) {
const newFreq = (jsonData.freq * 1000) + 10;
ws.send(`T${newFreq}`);
}
}
});
// Quit on Escape, q, or Control-C
screen.key(['escape', 'e', 'C-c'], function () {
process.exit(0);
});
// Update clock initially
updateClock();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment