Bark + SDR: Get Pushed Only When the Repeater Talks

This is the fifth article in my Bark series. If you have read the first four, you already have Bark, a relay Worker, and a script that can watch a folder. This article uses that same pattern for a different job: I leave an SDR running on one repeater frequency, and I want my phone to tell me only when someone actually talks there. I do not want to listen all day, and I do not want a push every minute.

You need the relay from Article 2. If that test push has not arrived yet, do that article first, then come back here. Article 4 is the same folder-watching idea for a satellite recording, and Article 7 is where automatic restart lives.

The script does not listen to radio by itself. Your SDR program does that, with squelch. When squelch opens, it makes a file. The script just sees the new file and pushes. That is all there is to it.

I put this together slowly, step by step, because I want you to get it working in one run, and to hear a real repeater file at the end, not just a test push. If the steps here feel heavy, start with Article 3 instead. A satellite pass reminder needs only the relay and your phone, and it will show you how Bark works before you add a computer script.

I should also say this plainly: I ran this once, it worked, and I wrote it up for you. I have not run it over a long period to see what breaks over time. If a step fails on your computer, start with your own program and folder, not with the idea that you made a mistake.

Before you start: tools, and how to check each one

Do not start the steps until every check below passes.

  1. Bark and a working relay Worker, from the first three articles. Check: send yourself a test push, as in Article 2. You will test the relay again with the script test in Step 3 below. If it does not arrive, fix that first.
  2. Your relay Worker address and shared passphrase, written on paper. Check: you can read both back without opening Cloudflare.
  3. A computer with an SDR, left running, with sleep mode disabled. Check: the computer does not enter sleep mode for an hour with the SDR program open.
  4. Python on that computer. Check: python --version on Windows, or python3 --version on Mac and Linux, returns a version number.
  5. An SDR program that can record only when squelch opens, and that saves each opening as a file in one folder. Check: set the squelch, talk or wait for traffic, and find one real recording file made by squelch alone. If your program records continuously instead, this article still works, but you will get far more pushes, so set squelch recording first.
  6. One repeater frequency you already listen to by hand, and its mode. Write the frequency on paper. This article watches one frequency only. Start with one, not five.

No two SDR programs put squelch recording in the same place. The threshold control, the record-on-squelch switch, and the output folder may all carry different names. Look for the meaning, not the words: squelch opens, a file appears, in one folder. Set the threshold just above the noise in your own program, and the rest of this article works the same.

If you do not know how to open a terminal yet, jump to the skills section below, then come back here. The checklist above will still be here.

Code repository

The full script is pasted in this article, below. The same file also lives in my public code repository, in the folder sdr-scripts/, as 02-repeater-watch.py. Open that folder, open the file, press Raw, select all, and copy. Change only the lines marked CONFIG. The script contains only placeholders. Do not put your Bark key in it. Your Bark key stays inside the relay Worker.

Before you start, three things to know

Terminal, saving a .py file, and copying from Raw: I wrote those out in Article 4, and I am not going to copy them here again. If you have not done them yet, do them there first, then come back. Two reminders for this article only: save as .py, not .py.txt, and write folder paths with forward slashes.

Step 1: Prove squelch recording works, without any push

Set your SDR program to the repeater frequency from your paper note. Set the squelch just above the noise, so it opens on voice and closes in silence. Turn on squelch recording, and leave it for a while. Then open the recording folder and count the files.

Check point: you have at least one file made by squelch alone, and you know its folder and its file ending, for example .wav. If the folder is empty, your squelch is too tight, or recording is off. Fix that before any script runs. If your program has no squelch recording at all, do not force this article. Use manual recording with the file watcher in Article 4 or Article 7 instead, and come back to this article only with a program that records on squelch.

If your squelch control looks different, judge it by the result, not the knob: noise alone must not open it, real traffic must.

Step 2: Copy the script

Save the code below as repeater-watch.py. Change only the CONFIG lines: relay address, passphrase, folder, file ending, and the cooldown in seconds. I use 600 seconds, ten minutes, so one busy hour cannot flood your phone. The relay itself also throttles an identical title and body to once per ten minutes, but the script cooldown is your own first line of defence.

import json
import os
import sys
import time
import urllib.request

# CONFIG: change these lines only.
RELAY_URL = "https://YOUR-WORKER.workers.dev/push"
RELAY_SECRET = "YOUR-PASSPHRASE"
WATCH_FOLDER = "C:/Recordings"
FILE_ENDING = ".wav"
COOLDOWN_SECONDS = 600
REPEATER_NAME = "YOUR-REPEATER-FREQUENCY"

# Pushes are title-only: on my phone, a push with a body is not
# spoken aloud, so everything goes into the title and there is no body.
def send_push(title):
    data = json.dumps({"title": title, "group": "sdr-repeater"}).encode()
    req = urllib.request.Request(RELAY_URL, data=data, method="POST")
    req.add_header("Content-Type", "application/json")
    req.add_header("X-Relay-Secret", RELAY_SECRET)
    with urllib.request.urlopen(req, timeout=20) as resp:
        print(resp.read().decode())

def main():
    if len(sys.argv) > 1 and sys.argv[1] == "test":
        send_push("Test push, relay path works")
        return
    known = set(os.listdir(WATCH_FOLDER))
    last_push = 0
    while True:
        current = set(os.listdir(WATCH_FOLDER))
        for name in sorted(current - known):
            if name.lower().endswith(FILE_ENDING) and time.time() - last_push >= COOLDOWN_SECONDS:
                send_push("Repeater traffic, %s, %s" % (REPEATER_NAME, name))
                last_push = time.time()
        known = current
        time.sleep(30)

if __name__ == "__main__":
    main()

Check point: the CONFIG lines show your own relay address, your own passphrase, your real folder, and your repeater frequency as a short label, not a secret. The relay address must end with /push, with no slash after it. For the folder path, use forward slashes even on Windows, for example C:/Recordings, not backslashes.

Step 3: Test the push, then test with a real file

Run python repeater-watch.py test, or python3 repeater-watch.py test. On Windows, if typing python opens a store page instead of running anything, use py repeater-watch.py test instead. Your phone should receive a test push within seconds. Then run the script without the word test, and make one squelch recording by hand, or wait for real traffic. The script runs in the foreground, so leave that terminal window open. Closing the terminal stops the script, and a reboot also stops it. For automatic restart after a reboot, see Article 7, Step 4. The script should push one title, “Repeater traffic” plus your frequency label and the new file name, and no body, once.

Check point: one new file gives one push, not five. If you get five pushes for one file, your cooldown is not working, or the script was started twice. Stop one copy and keep one running.

Worked example: 145.500 MHz, FM, step by step

Read this example first, then do Step 4 below with your own values. The example values are filled in, so you can see exactly what each line should look like.

This is a concrete example, not a placeholder. The frequency below is an example frequency only. Replace it with your own local repeater frequency afterwards. The steps stay identical. Only the frequency label changes.

Example scenario: I watch 145.500 MHz, mode FM, with squelch recording on. My program saves to C:/Recordings, with files ending in .wav. I want one push when squelch opens and a new file appears, and no more pushes for ten minutes after that.

Step 1, fill the CONFIG lines like this, line by line. Only the first two lines are yours. The other lines are the example.

RELAY_URL = "https://YOUR-WORKER.workers.dev/push"
RELAY_SECRET = "YOUR-PASSPHRASE"
WATCH_FOLDER = "C:/Recordings"
FILE_ENDING = ".wav"
COOLDOWN_SECONDS = 600
REPEATER_NAME = "145.500 FM"

Step 2, set your SDR program to 145.500 MHz, mode FM. Set the squelch just above the noise. Turn on squelch recording. Wait for traffic, or make one test transmission where you are allowed to do so. Suppose the program saves a file named squelch-1015.wav.

Step 3, start the script without the word test, and leave the terminal open. When that new file appears, and ten minutes have passed since the last push, your phone should receive a push that would read, in this example:

Repeater traffic, 145.500 FM, squelch-1015.wav

Step 4, if a second squelch file appears five minutes later, you should receive no second push, because the cooldown is 600 seconds. That silence is correct. It is the cooldown working, not a failure. After ten minutes, the next new file pushes again.

Step 5, for your own repeater, change only two things: the frequency in your SDR program, and the REPEATER_NAME line, for example to your repeater frequency as a short label. The folder, file ending, and cooldown stay the same, unless your program saves elsewhere.

Step 4: Leave it running, and read the push correctly

Leave the computer, the SDR program, and the script all running. A push means squelch opened and a file was made. It does not mean the traffic was for you, and it does not mean the signal was strong. Open the recording file afterwards if you want the content. The push is only an alert to go and listen.

Check point at the end of a day: the number of pushes roughly matches the number of new squelch files. A large gap means the script stopped, the computer slept, or the folder changed.

When it does not push

Fix one thing at a time, then try again.

  1. Did the test push arrive? If not, the relay address or passphrase is wrong, or the computer has no internet. Fix that first.
  2. Is the script still running in an open terminal? If the terminal is closed, the script stopped. Start it again.
  3. Is squelch recording really making files? Open the folder and count files. If it is empty, squelch is too tight, or recording is off, or your program has no squelch recording.
  4. Is the folder in CONFIG the real folder, with forward slashes? If not, fix the folder path.
  5. Did one new file give more than one push? If yes, the script was started twice. Stop one copy and keep one running.

If a step still fails after the checks above, copy this whole article into an AI tool and let it read the article first. Then tell it your SDR program, your real squelch folder and file ending, your repeater frequency and mode, and the error you saw. Ask it to check your local variables against the article, and to adjust for your program. Do not paste your relay passphrase or your Bark key into any AI tool. Copy the article as published, with placeholders, not your filled-in script.

Appendix: three things that really stop people

  1. Squelch too open. If squelch sits on noise, the program makes files all day, and your phone never stops. Set squelch just above noise first, and test with real voice before leaving it alone.
  2. The program makes a temporary file first. If your program writes a temporary file and renames it later, the script may push for the temporary name. Watch only the final file ending, and check one real file name before trusting the push.
  3. The computer enters sleep mode. A computer in sleep mode makes no files and sends no pushes, and you will think the repeater was quiet. Disabling sleep mode is a tool check, not a detail, and it belongs before Step 1.

More in this series: iPhone Low-Power Instant Ham Radio Reminders; One App, Two Websites: Instant Ham Radio Reminders; Satellite Pass Reminders by Hand: Start at 30 Degrees; Bark + SDR: Never Miss a Satellite Recording Again; Bark + SDR: A Push When the Band Opens to You; Bark + SDR: Know When Recording Finishes or Fails.

这是我的 Bark 系列第 5 篇。如果你已经读过前四篇,你已经有 Bark、转发器,和一个能看文件夹的脚本。这篇用同样的路子做另一件事:我让一台 SDR 守在一个中继频率上,只想在真的有人说话时,让手机告诉我。我不想整天听着,也不想一分钟发送一次推送。

你只需要第 2 篇里的转发器。测试推送还没到,就先去做那篇,再回来。第 4 篇是看卫星录音的文件夹版,第 7 篇是自动重启的办法。

先把一件事说清楚:这篇里的 Python 脚本自己不听无线电。听无线电的是你的 SDR 程序,靠静噪。静噪一打开,程序就录一个文件。脚本只看有没有新文件,出现了就发送一条推送。就这么简单。

这篇我是一步一步慢慢理出来的,就是想让你一遍跑通,最后听到一个真实的中继录音,拿到自己满意的结果,不只是一个测试推送。如果这里的步骤你觉得重,先做第 3 篇,卫星过顶提醒只要转发器和手机,能先让你看到 Bark 是怎么工作的,再回来加电脑脚本也不迟。

还有一句要说清楚:这篇我也是跑了一遍,能跑通,才写出来给大家。没有长时间跑过,看它久了会出什么问题。如果哪一步在你的电脑上失败,先从你自己的程序和文件夹查起,不要先觉得是自己做错了。

开始前:工具准备,和每一件工具的检查

下面每一项检查都通过了,再开始后面的步骤。

  1. 前三篇里的 Bark 和能用的转发器。检查:给自己发一条测试推送。没到就先修好它。
  2. 转发器地址和共享口令,写在纸上。检查:不用打开 Cloudflare,你就能把这两样读出来。
  3. 一台连着 SDR 的电脑,持续运行,禁用休眠功能。检查:SDR 程序持续运行一小时,电脑保持唤醒状态。
  4. 同一台电脑上的 Python。检查:Windows 运行 python --version,Mac 和 Linux 运行 python3 --version,有版本号回来。
  5. 一个能“静噪打开才录音”的 SDR 程序,每次打开都存成一个文件,存在同一个文件夹里。检查:设好静噪,等一次话音,找到一个光靠静噪录出来的真实文件。如果你的程序是连续录音,这篇也能正常运行,但推送会多得多,所以先把静噪录音设好。
  6. 一个你已经已手动监听过的中继频率和模式,写在纸上。这篇仅监听一个频率,先从一个开始,不要一次守五个。

静噪录音在不同 SDR 程序里的位置都不一样,静噪门限的旋钮、静噪触发录音的开关、输出文件夹的名字可能都不同。认意思,不认名字:静噪打开,就出一个文件,存在同一个文件夹里。在你自己的程序里把门限设到刚好高于噪声,剩下的做法都一样。

如果还不知道怎么打开终端,先跳到下面技能那节,做完再回来,上面的清单还在。

代码仓库

完整脚本贴在这篇文章下面。同一份文件也放在我的公开代码仓库里,文件夹是 sdr-scripts/,文件名是 02-repeater-watch.py。打开文件夹,打开文件,按 Raw,全选,复制。只改标着 CONFIG 的那几行。脚本里只有占位符,不要把你的 Bark 密钥写进去。你的 Bark 密钥只留在转发器后台。

开始前先会这三样

终端、存 .py 文件、从 Raw 复制,这三样我在第 4 篇里写过了,这里不再抄一遍。还没做过的,先去第 4 篇做完,再回来。这篇只提醒两句:存成 .py,不是 .py.txt;文件夹路径用正斜杠。

第 1 步:先证明静噪录音能用,还不用推送

把 SDR 程序调到纸上那个中继频率。静噪设到刚好压住噪声,话音来能打开、没话音能关上。打开静噪录音,放一阵子。然后打开录音文件夹,数文件。

核对点:你至少有一个光靠静噪录出来的文件,而且你知道它的文件夹和后缀,比如 .wav。文件夹是空的,说明静噪设得太紧,或者录音功能未开启。先修复这一项,再运行任何脚本。如果你的程序根本没有静噪录音,就不要直接套用本篇方法,用第 4 篇或者第 7 篇里手动录音加文件监控的办法,等换了能静噪录音的程序再回来。

如果你的静噪控制长得不一样,看结果不看旋钮:只有噪声时不能打开,有真实话音时必须打开。

第 2 步:复制脚本

把下面的代码存成 repeater-watch.py。只改 CONFIG 那几行:转发器地址、口令、文件夹、后缀、冷却时间。我用 600 秒,也就是十分钟,这样一个繁忙的小时也不会导致手机收到大量重复推送。转发器本身对完全相同的标题也是十分钟只发送一次推送,但脚本自己的冷却是第一道防线。

代码见上面英文部分的同一段,配置说明相同。

核对点:CONFIG 那几行是你自己的转发器地址、你自己的口令、你真实的文件夹,和你的中继频率短标签,不是秘密。转发器地址必须以 /push 结尾,后面不要再加斜杠。文件夹路径哪怕在 Windows 上也要用正斜杠写,比如 C:/Recordings,不要用反斜杠。

第 3 步:先测推送,再用真实文件测一次

运行 python repeater-watch.py test,Mac 和 Linux 用 python3 repeater-watch.py test。Windows 上如果输入 python 后打开的是应用商店页面而非执行程序,就改用 py repeater-watch.py test。几秒内手机应该收到测试推送。然后不带 test 启动脚本,手动执行一次静噪录音,或者等一次真实话音。脚本在前台运行,终端窗口须保持开启,关闭终端后,脚本将停止运行,重启也会停。重启后自动运行的办法见第 7 篇第 4 步。脚本应该只发送一次只有标题的推送:“Repeater traffic”加上你的频率标签和新文件名,没有正文。

核对点:一个新文件仅发送一次推送,不是五次。一个文件发送了五次推送,说明冷却没起作用,或者脚本被启动了两次。停止其中一个,只保留一个运行。

具体实例:145.500 MHz,FM,一步一步

先读这个实例,再按下面第 4 步用你自己的值做一遍。实例里的值都已填好,你能看到每一行该长什么样。

这是一个具体实例,不是占位符。下面这个频率只是示例频率,之后换成你自己本地的中继频率。步骤完全一样,只换频率标签。

实例情景:我监听 145.500 MHz,模式 FM,开着静噪录音。程序存到 C:/Recordings,文件后缀是 .wav。我想在静噪打开、新文件出现时发送一次推送,之后十分钟内不再推。

第 1 步,一行一行填 CONFIG。只有前两行是你自己的,其他行是这个实例:

RELAY_URL = "https://YOUR-WORKER.workers.dev/push"
RELAY_SECRET = "YOUR-PASSPHRASE"
WATCH_FOLDER = "C:/Recordings"
FILE_ENDING = ".wav"
COOLDOWN_SECONDS = 600
REPEATER_NAME = "145.500 FM"

第 2 步,把 SDR 程序调到 145.500 MHz,模式 FM。静噪设到刚好压住噪声,打开静噪录音。等一次话音,或者在允许的地方做一次测试发射。假设程序存了一个叫 squelch-1015.wav 的文件。

第 3 步,不带 test 启动脚本,终端保持开启。那个新文件一出现,而且距离上次推送已经过了十分钟,你的手机应该收到一条推送,这个实例里会是这样:

Repeater traffic, 145.500 FM, squelch-1015.wav

第 4 步,如果五分钟后又出现第二个静噪文件,你应该收不到第二条推送,因为冷却时间是 600 秒。这种安静是正确的,是冷却在起作用,不是坏了。过了十分钟,下一个新文件才会再推。

第 5 步,换成你自己的中继,只改两处:SDR 程序里的频率,和 REPEATER_NAME 那一行,改成你中继频率的短标签。文件夹、后缀、冷却时间都不用动,除非你的程序存到别的地方。

第 4 步:让它持续运行,并正确理解推送

电脑、SDR 程序、脚本均保持运行。收到推送,只说明静噪打开了、生成了一个文件,不说明话音是找你的,也不说明信号很强。想听内容,事后打开录音文件。推送只是一个提醒你去听的信号。

核对点:一天结束时,推送条数和新增静噪文件数大体对得上。差得很多,说明脚本已停止运行、电脑进入了休眠状态,或者文件夹变了。

运行失败时,先这样排查

一次只改一处,改完再测一次。

  1. 测试推送到了吗?没到,就是转发器地址或者口令错了,或者电脑没联网。先修这个。
  2. 脚本是否仍在保持开启的终端中运行?终端关了,脚本将停止运行。重新启动它。
  3. 静噪录音真的在生成文件吗?打开文件夹数文件。空的,就是静噪太紧,或者录音功能未开启,或者你的程序根本没有静噪录音。
  4. CONFIG 里写的文件夹是真实文件夹吗?路径用正斜杠了吗?不是就改文件夹路径。
  5. 一个新文件发送了不止一次推送吗?是的话,脚本被启动了两次。停止其中一个,只保留一个运行。

如果按上面的顺序查了还是不行,把整篇文章复制给 AI 工具,先让它读完文章。再告诉它你的 SDR 程序、你真实的静噪文件夹和文件后缀、你的中继频率和模式、你看到的报错,让它对照文章检查你的本地变量对不对,按你的程序做相应的调整。不要把转发器口令和 Bark 密钥粘给任何 AI 工具,复制的是发表出来的文章(带占位符的那版),不是你填好值的那份脚本。

附录:真正会卡住人的三条

  1. 静噪设得太开。静噪压不住噪声,程序整天生成文件,手机就停不下来。先把静噪设到刚好压住噪声,用真实话音测一次,再放着不管。
  2. 程序先生成临时文件。如果你的程序先写临时文件、事后再改名,脚本可能对着临时文件名推。只看最终文件的后缀,先确认一个真实文件名,再相信推送。
  3. 电脑进入休眠状态。处于休眠状态的电脑不生成文件、不发送推送,你会误以为中继很安静。禁用休眠是开始前的工具检查,不是小细节,它就该放在第 1 步之前。

这个系列里还有:第 1 篇:为什么用 Bark 做提醒、第 2 篇:一个 App、两个网站、第 3 篇:卫星过顶提醒、第 4 篇:卫星录音、第 6 篇:波段打开、第 7 篇:录音状态。