Files
website/scripts/radio-banks-1-3.ts
2026-10-26 17:24:03 +00:00

179 lines
4.6 KiB
TypeScript

// One-off data fill for scanner banks 1-3 (ham + ISS). Idempotent: reuses a frequency with the
// same freq_hz + name, and only fills empty channels.
import postgres from 'postgres';
const c = postgres(process.env.DB_URL!, { prepare: false, onnotice: () => {} });
const ARISS = 'ARISS https://www.ariss.org/contact-the-iss.html + status page (7 Oct 2026)';
const RDI =
'RDI repeater list via elinek.nl, cross-checked with nl.wikipedia Lijst van amateurrelaiszenders';
type F = {
ch: number;
hz: number;
mode: string;
name: string;
tag: string;
loc?: string;
notes: string;
tags: string[];
src: string;
existing?: number;
};
const rows: F[] = [
{
ch: 1,
hz: 145_800_000,
mode: 'NFM',
name: 'ISS voice downlink (ARISS)',
tag: 'ISS VOICE/SSTV',
notes: '',
tags: [],
src: '',
existing: 330
},
{
ch: 2,
hz: 437_800_000,
mode: 'FM',
name: 'ISS FM repeater downlink',
tag: 'ISS RPT DN',
notes:
'Cross-band voice repeater (NA1SS): uplink 145.990 MHz CTCSS 67 Hz, downlink 437.800. Allow ±10 kHz Doppler.',
tags: ['iss', 'satellite', '70cm'],
src: ARISS
},
{
ch: 3,
hz: 437_825_000,
mode: 'FM',
name: 'ISS APRS digipeater (UHF, active)',
tag: 'ISS APRS UHF',
notes:
'APRS 1200 bd packet; ARISS status says APRS is currently active here (RS0ISS). Decode with software; on the scanner you hear bursts.',
tags: ['iss', 'satellite', 'aprs', '70cm'],
src: ARISS
},
{
ch: 4,
hz: 145_825_000,
mode: 'FM',
name: 'ISS APRS digipeater (VHF)',
tag: 'ISS APRS VHF',
notes: 'Usual worldwide ISS packet frequency (1200 bd APRS); currently moved to 437.825.',
tags: ['iss', 'satellite', 'aprs', '2m'],
src: ARISS
},
{
ch: 5,
hz: 437_550_000,
mode: 'FM',
name: 'ISS SSTV downlink (events)',
tag: 'ISS SSTV UHF',
notes: 'SSTV events (Robot36), announced by ARISS. Decode with an SSTV app.',
tags: ['iss', 'satellite', 'sstv', '70cm'],
src: ARISS
},
{
ch: 6,
hz: 144_800_000,
mode: 'FM',
name: 'APRS (Europe, terrestrial)',
tag: 'APRS EU',
notes: 'IARU Region 1 APRS frequency, 1200 bd packet.',
tags: ['aprs', '2m'],
src: 'IARU Region 1 VHF band plan'
},
{
ch: 51,
hz: 145_500_000,
mode: 'FM',
name: '2 m FM calling',
tag: '2M CALL',
notes: 'FM simplex calling channel (V40).',
tags: ['calling', '2m'],
src: 'IARU Region 1 VHF band plan'
},
{
ch: 52,
hz: 433_500_000,
mode: 'FM',
name: '70 cm FM calling',
tag: '70CM CALL',
notes: 'FM simplex calling channel (U280).',
tags: ['calling', '70cm'],
src: 'IARU Region 1 UHF band plan'
},
{
ch: 53,
hz: 145_450_000,
mode: 'NFM',
name: 'Haagse ronde',
tag: 'HAAGSE RONDE',
notes: '',
tags: [],
src: '',
existing: 328
},
...(
[
[
101,
430_225_000,
'PI2SWK',
'Gouda',
'431.825',
'88.5',
'Also pi2swk.nl (Goudse ronde, EchoLink 669316).'
],
[102, 145_750_000, 'PI3RAZ', 'Zoetermeer', '145.150', '88.5', ''],
[103, 145_675_000, 'PI3RTD', 'Rotterdam', '145.075', '88.5', ''],
[104, 430_300_000, 'PI2RTD', 'Rotterdam', '431.900', '88.5', ''],
[105, 430_087_500, 'PI1DFT', 'Delft', '431.6875', '88.5', 'Same club as WebSDR PI1DFT.'],
[106, 430_350_000, 'PI2HGL', 'Den Haag', '431.950', '88.5', ''],
[107, 430_050_000, 'PI2LDN', 'Leiden', '431.650', '88.5', ''],
[
108,
145_575_000,
'PI3UTR',
'IJsselstein',
'144.975',
'77',
'Regional, wide coverage (Utrecht/Hilversum TX).'
]
] as const
).map(([ch, hz, call, loc, inp, tone, extra]) => ({
ch,
hz,
mode: 'FM',
name: `${call} repeater ${loc}`,
tag: `${call} ${loc}`.slice(0, 16),
loc,
notes: `FM repeater output; input ${inp} MHz, CTCSS ${tone} Hz. ${extra}`.trim(),
tags: ['repeater', hz < 200_000_000 ? '2m' : '70cm'],
src: RDI
}))
];
let added = 0,
set = 0;
for (const r of rows) {
let id = r.existing;
if (!id) {
const [f] =
await c`SELECT id FROM radio.frequencies WHERE freq_hz = ${r.hz} AND name = ${r.name}`;
id = f?.id;
if (!id) {
[{ id }] =
await c`INSERT INTO radio.frequencies ${c({ freq_hz: r.hz, mode: r.mode, band: 'ham', name: r.name, location: r.loc ?? null, notes: r.notes, tags: r.tags, source: r.src })} RETURNING id`;
added++;
}
}
const ins =
await c`INSERT INTO radio.channels ${c({ channel: r.ch, frequency_id: id, alpha_tag: r.tag.slice(0, 16) })} ON CONFLICT (channel) DO NOTHING`;
set += ins.count;
}
console.log(JSON.stringify({ frequenciesAdded: added, channelsSet: set }));
console.log(
JSON.stringify(
await c`SELECT (SELECT count(*)::int FROM radio.frequencies) freqs, (SELECT count(*)::int FROM radio.channels) chans, (SELECT count(*)::int FROM radio.channels WHERE channel <= 150) b123`
)
);
await c.end();