ESP32 Fake Radio Clock Station
clocksync allows an ESP32 to emulate various Low-Frequency (LF) time signal stations, allowing you to sync radio-controlled clocks (JJY, WWVB, DCF77, MSF, etc.) even if you are out of range of the actual transmitters.
This project is a maintained fork of the original nisejjy project by SASAKI Taroh, customized for modern hardware (M5 Atom Lite, ESP32-S3) with improved Web UI, stability, and signal framing.
- Multi-Station Support: Emulates JJY (Japan), WWVB (USA), DCF77 (Germany), MSF (UK), BSF (Taiwan), and BPC (China).
- Web Control: Simple web interface for status monitoring and configuration.
- Home Assistant Integration: REST API for scheduling transmission (e.g., run only at night).
- Precise Timing: Uses ESP32 hardware timers for accurate carrier generation and modulation.
- OTA Updates: Update firmware wirelessly via Arduino IDE.
Supported Boards:
- M5Stack Atom Lite (Recommended): Works out of the box. The RGB LED indicates status, and the button toggles transmission.
- Generic ESP32 / ESP32-S3: Compatible with standard DevKits.
Wiring Diagram:
ESP32 / M5Atom
+-------------+
| |
| GND [ ]----(Resistor 220-330Ω)----+
| | |
| GPIO 32 [ ]-----------------+ |
| | | |
+-------------+ | |
[ Antenna ] |
[ Coil ] |
| |
+---------+
- Pin: Connect one end of your antenna to
GPIO 32(default).- Note: On M5Stack Atom Lite, this is a pin on the bottom header.
- Ground: Connect the other end of the antenna to a Current Limiting Resistor (220Ω - 330Ω), and then to
GND.- Why a resistor? It protects your ESP32 from drawing too much current, as the antenna coil has very low resistance.
- Antenna Types:
- Ferrite Rod (Recommended): Scavenge one from an old radio clock or buy a ferrite antenna tuned to your target frequency. Important: You must match the frequency! (Tested range > 1m)
- 60 kHz: For WWVB (USA), MSF (UK), JJY (Japan).
- 40 kHz: For JJY (Japan).
- 77.5 kHz: For DCF77 (Germany), BSF (Taiwan).
- 68.5 kHz: For BPC (China).
- Wire Loop: A simple coil of wire (e.g., 30 turns of magnet wire around a water bottle). Short range, but works for any frequency.
- Ferrite Rod (Recommended): Scavenge one from an old radio clock or buy a ferrite antenna tuned to your target frequency. Important: You must match the frequency! (Tested range > 1m)
- Placement: Place your target watch/clock inside or immediately next to the antenna coil. This is a low-power near-field emulator; range is typically < 10cm.
- WiFi Secrets:
- Find the file
secrets_example.hin the file list. - Duplicate it and rename the copy to
secrets.h. - Open
secrets.hand fill in your WiFi details:#define WIFI_SSID "Your_WiFi_Name" #define WIFI_PASS "Your_WiFi_Password"
- Find the file
- Timezone (Critical):
- Open
clocksync.ino. - Find the line
#define TZ "...". - Change the string to match your location (see examples in the file).
- Note: For WWVB, it is best to use
"UTC0"and let the code handle DST, or your clock might have a double-offset error.
- Open
- Upload:
- Install Library: In Arduino IDE, go to
Sketch->Include Library->Manage Libraries.... Search for and installM5Atomby M5Stack. - Select Board: Go to
Tools->Boardand select M5Stack-ATOM (or "ESP32 Dev Module"). - Upload: Connect your device and click the Arrow icon (→).
- Install Library: In Arduino IDE, go to
Once running, the device acts as a time signal transmitter.
- Status LED: Indicates transmission is active.
- Button: Press to toggle transmission ON/OFF.
- Web UI: Visit
http://clocksync.local(or the device IP) to view status.
Control the device via Serial Monitor (115200 baud) or via HTTP (http://clocksync.local/cmd?c=<command>).
| Command | Description | Example |
|---|---|---|
| Stations | ||
sj |
Set station to JJY (40 kHz) (Fukushima) | sj |
sk |
Set station to JJY (60 kHz) (Fukuoka) | sk |
sw |
Set station to WWVB (60 kHz) (USA) | sw |
sd |
Set station to DCF77 (77.5 kHz) (Germany) | sd |
sm |
Set station to MSF (60 kHz) (UK) | sm |
st |
Set station to BSF (77.5 kHz) (Taiwan) | st |
sc |
Set station to BPC (68.5 kHz) (China) | sc |
| Control | ||
e1 / e0 |
Enable / Disable Transmission (Carrier & Logic) | e1 |
pNN |
Set Radio Output Pin (GPIO NN) |
p25 |
g0 - g3 |
Set Drive Strength (0=Weakest, 3=Strongest) | g2 |
| Settings | ||
y1 / y0 |
NTP Sync On / Off | y1 |
l1 / l0 |
LED On / Off | l1 |
x0 - x2 |
DCF/MSF DST Override (0=Std, 1=DST, 2=Auto) | x2 |
| Manual Time | ||
dYYMMDD |
Manually set Date (Year, Month, Day) | d231225 |
tHHmmSS |
Manually set Time (Hour, Min, Sec) | t123000 |
| Debug | ||
h |
Show Help | h |
f |
Frequency Self-Test (Requires jumper PIN_RADIO -> PIN_MEAS) |
f |
status |
(HTTP only) Get text status summary |
| Station | Freq (kHz) | Location | Notes |
|---|---|---|---|
| JJY | 40 / 60 | Japan | Default is end-Low symbol shape. |
| WWVB | 60 | USA | Uses UTC framing; DST bits automapped. |
| DCF77 | 77.5 | Germany | "Start-Low" encoding. |
| MSF | 60 | UK | Includes parity and DST bits. |
| BSF | 77.5 | Taiwan | Quaternary encoding (uncertified). |
| BPC | 68.5 | China | Quaternary encoding (uncertified). |
- Clock isn't syncing:
- Proximity: Move the clock closer to the antenna. It usually needs to be touching.
- Interference: LED power supplies and monitors cause noise. Move away from them.
- Volume: Increase "Volume" (Drive Strength) to
g3using the Serial/Web command. - Antenna: Ensure your antenna wire isn't broken and the resistor is secure.
- Clock shows wrong time:
- Timezone: Check the
#define TZline inclocksync.ino. - Double Correction: If using WWVB, use
"UTC0"as your TZ. If you set it to"EST+5", your clock might subtract 5 hours again, ending up 10 hours off.
- Timezone: Check the
- Compilation Error:
M5Atom.h: No such file: You missed installing the M5Atom library in step 3.
For deep dives into the signal encoding and protocol specifications used by this emulator, see HOW_IT_WORKS.md.