This is the sixth article in my Bark series. If you have read the first five, you already have Bark, a relay Worker, and scripts that watch files. This article watches a different file: the decode log of WSJT-X. When WSJT-X decodes a station you want, on a frequency and mode you want, the script pushes to your phone. You do not have to stare at the decode screen all day.
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 folder-watching version, this one is the log-watching version, and Article 7 is where automatic restart lives.
A push here means WSJT-X decoded something. It does not mean you worked that station. Go and listen first, then decide if you want to call.
These notes took me a while to sort out, because I wanted one clean run: copy, fill, test, and then a real decode push, with a result you are happy with at the end. If that sounds like too much at once, try Article 3 first. It is the simplest one in the series, a phone reminder for a satellite pass, with no log file and no matching to set up.
Before you start, one more honest note: this is a process I ran once, saw work, and then shared. It is not a long-term test. If a decode does not push, check your own log file and your own wanted items first, before assuming the script is broken.
Before you start: tools, and how to check each one
Do not start the steps until every check below passes.
- 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.
- Your relay Worker address and shared passphrase, written on paper. Check: you can read both back without opening Cloudflare.
- A computer with an SDR or a radio, running WSJT-X, with sleep mode disabled. Check: WSJT-X stays open and decoding for at least ten minutes without the computer entering sleep mode.
- Python on that computer. Check:
python --versionon Windows, orpython3 --versionon Mac and Linux, returns a version number. - WSJT-X already decoding by hand. Check: open WSJT-X, open its log directory from the File menu, and find a log file that grows while it decodes. On most systems this file is called
ALL.txt. If no log grows, WSJT-X is not decoding yet, and no script can help. - One wanted item, written on paper, not ten. For example: one frequency, one mode, and your own callsign. In my example that callsign is BG7BAG. In yours, it is your own callsign. Start with one. A wanted list that is too broad is the fastest way to flood your phone. Write the frequency exactly as WSJT-X shows it in the log, for example
14.074for 20m FT8, not the band name20m. The log file contains frequencies, not band names, so a band name will never match.
WSJT-X is the same program for everyone, but the computer in front of it is not. The radio or SDR in front, the audio path, and the log folder on your system will differ. That is fine. This article only needs one thing from WSJT-X: a log file that grows while it decodes. Open its log directory from the File menu, copy the path you actually find, and use that path in your copy, whatever system you are on.
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 03-band-opening.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. One reminder for this article only: copy the log path from the file manager, do not type it from memory, and save as .py, not .py.txt.
Step 1: Find your real log file, and prove it grows
Open WSJT-X. From the File menu, open the log directory. Look for ALL.txt. Watch it for a minute while WSJT-X decodes. Its size should grow, and its last lines should show recent decodes with time, frequency, and callsigns.
Check point: you can point at one real ALL.txt file, read its exact folder, and see a new line appear while WSJT-X runs. Copy that folder path from the file manager or from the file properties. Do not type it from memory. If the file does not grow, stop here. The script watches this file, and a still file gives no pushes, ever.
If your log folder is not where the example says, that is normal. Use the folder you opened from the File menu, not the example path.
Step 2: Copy the script
Save the code below as band-opening.py. Change only the CONFIG lines: relay address, passphrase, log file path, wanted frequency text, wanted mode text, and wanted callsign text. I match by simple text in the new log line, so keep each wanted item short and exact, for example a frequency such as 14.074, a mode such as FT8, and your own callsign, BG7BAG in my example. The relay address must end with /push, with no slash after it. For any folder or file path, use forward slashes even on Windows, for example C:/Users/..., not backslashes, because a backslash in a Python string can eat the next letter. The script pushes at most once per ten minutes for the same wanted item, so a busy decode screen cannot flood your phone.
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"
LOG_FILE = "C:/Users/YOUR-NAME/AppData/Local/WSJT-X/ALL.txt"
WANTED_FREQ = "14.074"
WANTED_MODE = "FT8"
WANTED_TEXT = "YOUR-WANTED-CALL-OR-PREFIX"
COOLDOWN_SECONDS = 600
# 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-dx"}).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
pos = os.path.getsize(LOG_FILE)
last_push = 0
while True:
size = os.path.getsize(LOG_FILE)
if size < pos:
pos = 0
if size > pos:
with open(LOG_FILE, "r", errors="ignore") as f:
f.seek(pos)
for line in f:
if WANTED_FREQ in line and WANTED_MODE in line and WANTED_TEXT in line:
if time.time() - last_push >= COOLDOWN_SECONDS:
send_push("Band open, " + line.strip()[:120])
last_push = time.time()
pos = size
time.sleep(15)
if __name__ == "__main__":
main()
Check point: the CONFIG lines show your own relay address, your own passphrase, your real log file path, and one wanted item only. The log path in the example is only an example. Replace it with the path you found in Step 1.
Step 3: Test the push, then test with a real decode
Run python band-opening.py test, or python3 band-opening.py test. On Windows, if typing python opens a store page instead of running anything, use py band-opening.py test instead. Your phone should receive a test push within seconds. Then run the script without the word test, and leave WSJT-X decoding. 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. When a new decode line matches all three wanted items, the script pushes one title, “Band open” plus that decode line, and no body.
Check point: a decode that matches only two of the three items must not push. If it pushes, one of your wanted items is too short, for example a single letter that appears everywhere. Make that item longer and more exact, and test again.
Worked example: 14.074 MHz, FT8, my callsign BG7BAG, 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 prefix below is an example only. Replace it with the prefix you want afterwards. The steps stay identical.
Example scenario: I want a push when WSJT-X decodes a line containing my own callsign, BG7BAG, on 14.074 MHz, mode FT8. BG7BAG is my callsign. In your copy, replace it with your own callsign. My log file is the real ALL.txt file I found in Step 1. For this example, I write its path as below. Replace that path with your real path.
Step 1, fill the CONFIG lines like this, line by line. Only the first two lines are yours, and the log path is yours. The other three lines are the example, with my callsign in the third one.
RELAY_URL = "https://YOUR-WORKER.workers.dev/push"
RELAY_SECRET = "YOUR-PASSPHRASE"
LOG_FILE = "C:/Users/YOUR-NAME/AppData/Local/WSJT-X/ALL.txt"
WANTED_FREQ = "14.074"
WANTED_MODE = "FT8"
WANTED_TEXT = "BG7BAG"
COOLDOWN_SECONDS = 600
Step 2, open ALL.txt and find a real line that looks like this example line. The callsign in this line is my callsign, BG7BAG. In your copy, that place will hold your own callsign.
261103_100000 14.074 Rx FT8 -10 0.5 1234 CQ BG7BAG
Read that line left to right: frequency 14.074, mode FT8, callsign BG7BAG. All three match the CONFIG above, so this line would push.
Step 3, start the script without the word test, and leave WSJT-X decoding and the terminal open. When a new line like the one above appears, your phone should receive a push that would read, in this example:
Band open, 261103_100000 14.074 Rx FT8 -10 0.5 1234 CQ BG7BAG
Step 4, check the two lines that must not push. A line on 7.074, mode FT8, with callsign BG7BAG, must not push, because the frequency does not match. A line on 14.074, mode FT4, with callsign BG7BAG, must not push, because the mode does not match. If either one pushes, one of your wanted items is too short. Make it longer and test again.
Step 5, for your own wanted item, change only three lines: WANTED_FREQ to your frequency as it appears in the log, WANTED_MODE to your mode, and WANTED_TEXT to your own callsign, in place of BG7BAG. The log path, relay lines, and cooldown stay the same.
Step 4: Leave it running, and read the push correctly
Leave WSJT-X, the radio or SDR, and the script all running. A push means a decode matched your list. Go to the radio, listen on that frequency, and decide yourself whether to call. Do not treat a push as a completed contact, and do not call blindly from the push text alone.
Check point at the end of a day: pushes match recent decode lines in ALL.txt. If pushes arrive with no matching decode line, your wanted text is matching something else in the log. Read the pushed line, find it in the log, and tighten the wanted item.
When it does not push
Fix one thing at a time, then try again.
- Did the test push arrive? If not, the relay address or passphrase is wrong, or the computer has no internet. Fix that first.
- Is the script still running in an open terminal? If the terminal is closed, the script stopped. Start it again.
- Is the log file really growing? Open
ALL.txtand watch it while WSJT-X decodes. If it does not grow, WSJT-X is not decoding. - Does your wanted frequency appear in a real log line, exactly as you wrote it? Open the log, find one line with your station, and compare the frequency, mode, and callsign letter by letter. A band name in place of a frequency will never match.
- Is the file name really ending in
.py, and does the code use straight quotes? If not, fix the file name and the quotes, then run the test again.
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 WSJT-X setup, your real log path, your wanted frequency, mode, and callsign, and the log line or error you saw. Ask it to check your local variables against the article, and to adjust for your system. 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
- The wanted list is too broad, or written as a band name. Ten frequencies, ten modes, and a short prefix will push all day, and a band name such as
20mwill never match, because the log contains frequencies such as14.074, not band names. Start with one frequency, one mode, and one callsign, your own, and add a second item only after a quiet day. - The log path is wrong. WSJT-X log folders differ by system and by install. The example path in the script is not your path. Step 1 exists for this reason: find your real file first, then point the script at it.
- WSJT-X is open but not decoding. A still log file gives no pushes, and that silence is correct, not a script failure. Check that decodes appear on screen and that the log file grows, before blaming the script or the relay.
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: Get Pushed Only When the Repeater Talks; Bark + SDR: Know When Recording Finishes or Fails.
这是我的 Bark 系列第 6 篇。如果你已经读过前五篇,你已经有 Bark、转发器,和能看文件的脚本。这篇看的是另一个文件:WSJT-X 的解码日志。WSJT-X 解出一个你要的台,频率和模式也对,脚本就往你手机上发送一条推送。你不用整天盯着解码屏幕。
你只需要第 2 篇里的转发器。测试推送还没到,就先去做那篇,再回来。第 4 篇是看文件夹版,这篇是看日志版,第 7 篇是自动重启的办法。
先把一件事说清楚:这篇脚本推来的,只说明解出了一个信号,不说明你通联上了。去听一听,再自己决定叫不叫。
这篇我整理了好一阵,就是想让你一次走通:复制、填好、测试,然后收到一次真实解码的推送,拿到自己满意的结果。如果一下子觉得太多,先做第 3 篇,那是系列里最简单的一篇,卫星过顶的手机提醒,不用管日志文件,也不用设匹配,步骤也简单得多。
开始之前再说一句老实话:这篇是我跑了一遍、看到能用、才分享出来的过程,不是长时间测试的结果。如果解码没有推送,先查你自己的日志文件和你自己要的那几项,再去怀疑脚本坏了。
开始前:工具准备,和每一件工具的检查
下面每一项检查都通过了,再开始后面的步骤。
- 前三篇里的 Bark 和能用的转发器。检查:给自己发一条测试推送。
- 转发器地址和共享口令,写在纸上。检查:不用打开 Cloudflare,你就能把这两样读出来。
- 一台连着 SDR 或者电台、运行 WSJT-X 的电脑,禁用休眠功能。检查:WSJT-X 持续解码十分钟,电脑保持唤醒状态。
- 同一台电脑上的 Python。检查:Windows 运行
python --version,Mac 和 Linux 运行python3 --version,有版本号回来。 - WSJT-X 已经能够手动解码。检查:打开 WSJT-X,从 File 菜单打开日志目录,找到一个解码时一直在变大的日志文件,大多数系统里这个文件叫
ALL.txt。没有日志在变大,说明 WSJT-X 还没解出来,什么脚本都帮不上。 - 一个你要的东西,写在纸上,不要写十个。比如:一个频率、一个模式、你自己的呼号。我实例里的呼号是 BG7BAG,你的就换成你自己的呼号。先从一个开始。想要的清单太宽,是最容易导致手机收到大量重复推送的做法。频率要按 WSJT-X 日志里显示的那样写,比如 20 米 FT8 写
14.074,不要写波段名20m。日志里只有频率,没有波段名,写波段名永远对不上。
WSJT-X 本身是同一个程序,但它前面的电台或者 SDR、音频通路、你系统里的日志文件夹都不一样。这不要紧。这篇只要 WSJT-X 的一件事:解码时一直在变大的日志文件。从 File 菜单打开日志目录,把你实际找到的路径抄下来,用在你自己的脚本里,不管你用的是哪个系统。
如果还不知道怎么打开终端,先跳到下面技能那节,做完再回来,上面的清单还在。
代码仓库
完整脚本贴在这篇文章下面。同一份文件也放在我的公开代码仓库里,文件夹是 sdr-scripts/,文件名是 03-band-opening.py。打开文件夹,打开文件,按 Raw,全选,复制。只改标着 CONFIG 的那几行。脚本里只有占位符,不要把你的 Bark 密钥写进去。你的 Bark 密钥只留在转发器后台。
开始前先会这三样
终端、存 .py 文件、从 Raw 复制,这三样我在第 4 篇里写过了,这里不再抄一遍。还没做过的,先去第 4 篇做完,再回来。这篇只提醒一句:日志路径从文件管理器里复制,不要凭记忆手打;存成 .py,不是 .py.txt。
第 1 步:找到你真实的日志文件,并证明它在变大
打开 WSJT-X,从 File 菜单打开日志目录。找 ALL.txt。WSJT-X 解码时看它一分钟,大小应该在变大,最后几行应该有最近的解码,带时间、频率和呼号。
核对点:你能指着一个真实的 ALL.txt 文件,说出它的准确文件夹,而且 WSJT-X 运行时能看到新行出现。文件夹路径从文件管理器或者文件属性里复制,不要凭记忆手打。文件不动,就先停在这里。脚本监测的就是这个文件,文件不动就永远不会有推送。
如果你的日志文件夹不在实例说的位置,这是正常的。用你从 File 菜单打开的那个文件夹,不要照抄实例路径。
第 2 步:复制脚本
把下面的代码存成 band-opening.py。只改 CONFIG 那几行:转发器地址、口令、日志文件路径、要的频率文字、要的模式文字、要的呼号文字。我用新日志行里的简单文字匹配,所以每一项都要写得短而准确,比如频率写 14.074,模式写 FT8,呼号写一个前缀。转发器地址必须以 /push 结尾,后面不要再加斜杠。任何文件夹或者文件路径,哪怕在 Windows 上也要用正斜杠写,比如 C:/Users/...,不要用反斜杠,因为 Python 字符串里的反斜杠会吃掉下一个字母。同一项十分钟内最多发送一次推送,这样繁忙的解码屏幕也不会导致手机收到大量重复推送。
代码见上面英文部分的同一段,配置说明相同。
核对点:CONFIG 那几行是你自己的转发器地址、你自己的口令、你真实的日志文件路径,而且目标只有一项。脚本里的示例路径只是示例,换成你在第 1 步找到的真实路径。
第 3 步:先测推送,再用真实解码测一次
运行 python band-opening.py test,Mac 和 Linux 用 python3 band-opening.py test。Windows 上如果输入 python 后打开的是应用商店页面而非执行程序,就改用 py band-opening.py test。几秒内手机应该收到测试推送。然后不带 test 启动脚本,让 WSJT-X 继续解码。脚本在前台运行,终端窗口须保持开启,关闭终端后,脚本将停止运行,重启也会停。重启后自动运行的办法见第 7 篇第 4 步。新解码行三项全对上,脚本就发送一条只有标题的推送:“Band open”加上那行解码,没有正文。
核对点:只对上三项里的两项,一定不能推。推了,说明有一项写得太短,比如一个字母到处都出现。把那一项写长、写准确,再测一次。
具体实例:14.074 MHz,FT8,我的呼号 BG7BAG,一步一步
先读这个实例,再按下面第 4 步用你自己的值做一遍。实例里的值都已填好,你能看到每一行该长什么样。
这是一个具体实例,不是占位符。下面这个前缀只是示例,之后换成你要的前缀。步骤完全一样。
实例情景:我想在 WSJT-X 解出一行带有我自己呼号 BG7BAG 的解码时收到推送,频率 14.074 MHz,模式 FT8。BG7BAG 是我的呼号,你抄的时候换成你自己的呼号。日志文件就是第 1 步找到的真实 ALL.txt。这个实例里路径照下面写,换成你真实的路径。
第 1 步,一行一行填 CONFIG。只有前两行是你自己的,日志路径也是你自己的,其他三行是这个实例,第三行就是我的呼号:
RELAY_URL = "https://YOUR-WORKER.workers.dev/push"
RELAY_SECRET = "YOUR-PASSPHRASE"
LOG_FILE = "C:/Users/YOUR-NAME/AppData/Local/WSJT-X/ALL.txt"
WANTED_FREQ = "14.074"
WANTED_MODE = "FT8"
WANTED_TEXT = "BG7BAG"
COOLDOWN_SECONDS = 600
第 2 步,打开 ALL.txt,找一行长得像下面这行示例的真实行。这行里的呼号只是示例写法,不是真实电台。你真实的行里,同一个位置会是一个真实呼号。
261103_100000 14.074 Rx FT8 -10 0.5 1234 CQ BG7BAG
从左往右读:频率 14.074,模式 FT8,呼号 BG7BAG。三项都和上面 CONFIG 对得上,所以这一行会推。
第 3 步,不带 test 启动脚本,WSJT-X 继续解码,终端保持开启。像上面那样的新行一出现,你的手机应该收到一条推送,这个实例里会是这样:
Band open, 261103_100000 14.074 Rx FT8 -10 0.5 1234 CQ BG7BAG
第 4 步,检查两行一定不能推的行。频率 7.074、模式 FT8、呼号 BG7BAG 的行,一定不能推,因为频率对不上。频率 14.074、模式 FT4、呼号 BG7BAG 的行,一定不能推,因为模式对不上。哪一行推了,就说明有一项写得太短,写长、写准确,再测一次。
第 5 步,换成你自己的目标,只改三行:WANTED_FREQ 改成日志里出现的你的频率,WANTED_MODE 改成你的模式,WANTED_TEXT 改成你自己的呼号,把 BG7BAG 换掉。日志路径、转发器那两行、冷却时间都不用动。
第 4 步:让它持续运行,并正确理解推送
WSJT-X、电台或者 SDR、脚本均保持运行。收到推送,只说明有一次解码对上了你的清单。去电台上,在那个频率上听一听,再自己决定叫不叫。不要把推送当成已经通联成功,也不要光看推送文字就盲目呼叫。
核对点:一天结束时,推送和 ALL.txt 里的最近解码行对得上。推送来了、日志里却没有对应的解码行,说明你要的文字匹配到了日志里的别的东西。读一读推送的那行,在日志里找到它,把想要的项收紧。
运行失败时,先这样排查
一次只改一处,改完再测一次。
- 测试推送到了吗?没到,就是转发器地址或者口令错了,或者电脑没联网。先修这个。
- 脚本是否仍在保持开启的终端中运行?终端关了,脚本将停止运行。重新启动它。
- 日志文件真的在变大吗?打开
ALL.txt,WSJT-X 解码时监测它。不变大,就是 WSJT-X 还没解出来。 - 你要的频率在真实日志行里出现了吗?打开日志,找到有你要的台的那一行,频率、模式、呼号一个字母一个字母对。写成波段名代替频率,永远对不上。
- 文件名真的是以
.py结尾吗?代码里是直引号吗?不是就改文件名、改引号,再次运行测试。
如果按上面的顺序查了还是不行,把整篇文章复制给 AI 工具,先让它读完文章。再告诉它你的 WSJT-X 设置、你真实的日志路径、你要的频率、模式和呼号、你看到的日志行或报错,让它对照文章检查你的本地变量对不对,按你的系统做相应的调整。不要把转发器口令和 Bark 密钥粘给任何 AI 工具,复制的是发表出来的文章(带占位符的那版),不是你填好值的那份脚本。
附录:真正会卡住人的三条
- 想要的清单太宽,或者写成了波段名。十个频率、十个模式、一个短前缀,手机将全天频繁收到推送;而写成
20m这样的波段名则永远对不上,因为日志里只有14.074这样的频率,没有波段名。先从一个频率、一个模式、一个呼号、你自己的呼号开始,安静地运行一天,再加第二项。 - 日志路径写错了。WSJT-X 的日志文件夹因系统和安装方式而不同,脚本里的示例路径不是你的路径。第 1 步就是为这个设的:先找到你真实的文件,再把脚本指过去。
- WSJT-X 开着但没解码。日志文件不动就不会有推送,这种安静是正确的,不是脚本坏了。先确认屏幕上有解码出现、日志文件在变大,再去归咎于脚本或者转发器。
这个系列里还有:第 1 篇:为什么用 Bark 做提醒、第 2 篇:一个 App、两个网站、第 3 篇:卫星过顶提醒、第 4 篇:卫星录音、第 5 篇:中继守听、第 7 篇:录音状态。