Multi-radio DMR codeplug generator for Western Washington/Oregon
Generate customized DMR codeplugs for three radio variants from a variety of online sources using dzcb (DMR Zone Channel Builder).
This project extends the upstream example-codeplug to support simultaneous generation of multiple radio formats with radio-specific optimizations.
This project generates codeplugs for three radio variants:
- Output Format: Anytone CPS (Windows-only import)
- CPS Version: 1.11
- Features: Analog, Digital DMR repeaters, GMRS, simplex
- Status: ✅ Fully supported (CPS import only, dmrconfig not supported upstream)
- Output Formats: Anytone CPS + dmrconfig
- CPS Version: 1.21 (Anytone), OpenRTX (dmrconfig)
- Features: Analog, Digital DMR repeaters, GMRS, simplex, advanced features
- Status: ✅ Fully supported (dual-format output)
- Output Formats: dmrconfig (recommended) + GB3GF CSV (experimental)
- Import Tools:
- dmrconfig (Linux/Mac, fully supported)
- GB3GF CSV:
⚠️ Currently incompatible - Format mismatch with OpenGD77's native CSV import
- Features: Analog, Digital DMR repeaters, GMRS, simplex, GPS coordinates (in progress)
- Status: ✅ dmrconfig fully supported | ⏳ GB3GF CSV format work in progress
Active Sources:
- PNWDigital: Live repeater network (https://pnwdigital.net)
- SeattleDMR: Live repeater network (https://seattledmr.org)
- Repeaterbook Proximity: Live repeater data from defined proximity zones (14 zones covering Washington/Oregon)
- Local K7ABD Files: Manual zone/channel definitions
Create / edit codeplug source files under /input.
This project uses multiple subdirectories under /input to generate simultaneous codeplugs for three radios:
input/AT-D578UV_III_Plus/→ Anytone CPS format onlyinput/AT-D878UV_II_Plus/→ Anytone CPS + dmrconfig formatsinput/OpenGD77/→ dmrconfig + GB3GF formats
Each subdirectory contains:
generate.py: Python script that builds the codeplug using dzcb APIk7abd/: Zone/channel definitions in K7ABD CSV formatorder.csv: Preferred zone/channel/contact orderexclude.csv: Zone/channel/contact exclusionsreplacements.csv: Object name replacements (regex)scanlists.json: Additional scanlists- Radio-specific config template (e.g.,
d878uv-default.conffor dmrconfig)
See dzcb README.md for more information on input file formats.
# Install dependencies
pip install tox
# Build all three radio variants
tox
# Or run directly
python3 input/generate_all.pyGenerated codepl ugs will be in OUTPUT/ subdirectories organized by radio:
OUTPUT/AT-D578UV_III_Plus/anytone/→ Anytone CPS filesOUTPUT/AT-D878UV_II_Plus/anytone/→ Anytone CPS filesOUTPUT/AT-D878UV_II_Plus/dmrconfig/→ dmrconfig .conf fileOUTPUT/OpenGD77/dmrconfig/→ dmrconfig .conf fileOUTPUT/OpenGD77/gb3gf/→ GB3GF CSV files
- Fork this repo
- In the newly forked repo, click the "Actions" tab and enable Github Actions for your fork.
- Customize codeplug input files in
/inputfor each radio variant:- Update zone/channel definitions in
k7abd/subdirectories - Adjust
order.csv,exclude.csv,replacements.csvas needed - Modify radio-specific config templates (
.confor.jsonfiles) with your Radio ID/Name - Update
scanlists.jsonfor custom scan lists
- Update zone/channel definitions in
- Github
codeplugsworkflow will automatically build all three radio codepl ugs when you push to main - When a Release is published, the generated codepl ugs will be hosted publicly with stable URLs
- Linux, macOS, or Windows
- Python 3.8 or later
- tox
See dzcb WALKTHROUGH for step-by-step instructions.
Previously, the upstream dzcb 0.3.10 had a bug where Analog CSV files generated from Repeaterbook proximity searches were missing the required "Zone" column header, causing KeyError: 'Zone' during parsing.
Status: ✅ Fixed - The root cause was UTF-8 Byte Order Mark (BOM) in K7ABD CSV files. After removing the BOM, repeaterbook proximity has been re-enabled.
Current Configuration: All three radios now include repeaterbook data from Washington and Oregon within 50-mile radius of defined proximity points (Seattle, Tacoma).
OpenGD77 now has native CSV import support built into the CPS, but the current dzcb GB3GF output format is incompatible with OpenGD77's import expectations.
Workarounds:
- Use the dmrconfig output for OpenGD77 on Linux/Mac (fully supported, recommended)
- Copy/paste rows from the GB3GF CSV files directly into OpenGD77 CPS as a temporary workaround
The upstream dmrconfig tool doesn't recognize the AT-D578UV radio model.
Workaround: AT-D578UV codepl ugs are generated in Anytone CPS format only. Import through Windows CPS software.
- VS Code: File → Save with Encoding → UTF-8
- Excel: Save As → CSV UTF-8
- LibreOffice: Tools → Options → Load/Save → Default file format
Editors like Notepad++ and Sublime Text add a UTF-8 BOM by default, which breaks dzcb's CSV parsing.
- Zone names must be unique across all CSV files
- Channel names can be identical in different zones
- Keep names under 20 characters for compatibility with all radio models
Before pushing to production:
# Build locally
python3 input/generate_all.py
# Check for errors in logs
tail -20 OUTPUT/*/dzcb.*.log
# Verify all three radios produced output
ls OUTPUT/AT-D578UV_III_Plus/anytone/
ls OUTPUT/AT-D878UV_II_Plus/anytone/
ls OUTPUT/AT-D878UV_II_Plus/dmrconfig/
ls OUTPUT/OpenGD77/dmrconfig/
ls OUTPUT/OpenGD77/gb3gf/Then import into CPS/dmrconfig or GB3GF tool to validate.