Skip to main content

Repeater Setup Guide

So you've decided to run a repeater. Nice. This guide gets a MeshCore repeater online, tagged with the right Michigan regions, tuned, and verified.

Before You Start​

  • Flash Repeater firmware via the web flasher. Use a Chromium-based browser, since the flasher needs the Web Serial API. This guide requires firmware 1.16 or later; if a repeater is running anything older, upgrade it first.
  • Mount high with line of sight and use a real external antenna. Elevation and antenna quality matter more than transmit power.
  • Use a stable power supply: wall adapter, POE, or solar with battery backup. Avoid bus-powered USB hubs.
  • Connect over USB with the Web Serial console at config.meshcore.io.
nRF52 boards only: Install OTAFIX

Flash OTAFIX before the repeater firmware as it falls back to DFU mode when an OTA update fails. See the install instructions here.

CLI Syntax

The MeshCore CLI uses spaces, not =. Typing set path.hash.mode = 1 can silently fail or store garbage. Always use set path.hash.mode 1.

Quick Start​

The full setup for a new repeater on firmware 1.16 or later. Replace everything in <angle brackets>, and swap the region line for your area (see Pick Your Regions). Each block links to a step below that explains it.

# 1. Confirm firmware and radio (expect role = Repeater, 910.525 / 62.5 / 7 / 5)
ver
get role
get radio

# 2. Identity and security
set name <YourRepeaterName>
set lat <42.7336>
set lon <-84.5555>
set owner.info <your_contact_details>|michmesh.com/mcr
password <your_admin_password>

# 3. Michigan network standards
set path.hash.mode 1
set advert.interval 240
set flood.advert.interval 24
set flood.max 32
set agc.reset.interval 500
set dutycycle 100
set loop.detect moderate

# 4. Regions (Grand Rapids example: use your own subregion / local region)
# Define them only. Scoping is on hold: no region default, no unscoped cap.
region def midwest mi mi-west grr
region save

# 5. Delay profile (SUBURBAN shown: pick yours from Delay Profiles)
set txdelay 0.8
set direct.txdelay 0.4
set rxdelay 3

# 6. Clock, then reboot and verify
clock sync
reboot

After it reboots, reconnect and run clock, region, and get public.key. Before the repeater goes up, check its public key prefix for collisions.

Clock Sync Required

Repeaters boot with an old date. Without a correct clock, relayed message timestamps will be wrong. With GPS-capable firmware and hardware, run gps on then gps sync. Otherwise run clock sync from the companion app or Web Serial after every reboot or power cycle.

Step-by-Step Setup​

1. Confirm Firmware and Role​

Repeater firmware sets the role automatically. You should see role = Repeater. If ver shows a version older than 1.16, upgrade before going further: the region commands in this guide need it.

ver
board
get role

2. Verify Radio Settings​

Read back the radio configuration and confirm it matches the Michigan preset. If you selected USA/Canada (Recommended) in the web flasher, it already does:

SettingValue
Frequency (MHz)910.525
Bandwidth (kHz)62.5
Spreading factor7
Coding rate5
get radio
get tx

Only if the read-back didn't match, set them manually:

set radio 910.525,62.5,7,5
set tx <power>

3. Set Name and Location​

Set the name the rest of the mesh will see, and the repeater's coordinates. Location isn't required, but it's what lets everyone see where coverage already exists and where the gaps are. Coordinates are decimal degrees, not degrees/minutes/seconds.

set name <YourRepeaterName>
set lat <42.7336>
set lon <-84.5555>

4. Set Owner Info​

Free-text contact details so somebody can reach you about the node: an email address, a Discord handle, an amateur radio callsign, or whatever else will actually reach you. Optional, but a repeater nobody can contact is a repeater nobody can tell you is misbehaving. | characters become line breaks.

set owner.info <your_contact_details>|michmesh.com/mcr

End it with |michmesh.com/mcr, a short link to this page, so anyone who looks up your repeater can find the Michigan setup standard. Keep the link in owner info rather than the repeater name: once location is set, adverts only carry the first 23 characters of the name, and the link would crowd out or truncate it.

5. Set an Admin Password​

Repeater firmware ships with the admin password set to the literal string password. Until you change it, anyone in radio range can log in over the mesh and reconfigure your node. Change it before the repeater goes up.

password <your_admin_password>

Leave guest.password alone on purpose. It defaults to blank, which is what lets community members log in as guests and query repeater status.

6. Apply Michigan Network Standards​

These apply to every Michigan repeater regardless of location or height.

set path.hash.mode 1
set advert.interval 240
set flood.advert.interval 24
set flood.max 32
set agc.reset.interval 500
set dutycycle 100
set loop.detect moderate

7. Set Regions​

Define the full region ancestry for the area the repeater serves. See Regions for what to carry.

region def midwest mi <subregion> <local_region>
region save

Leave off <local_region> if your area doesn't have one yet. Don't set a default scope or cap unscoped floods: scoping is on hold. If you already did, undo it.

8. Pick a Delay Profile​

Choose the delay profile that matches the repeater's elevation and apply its three commands.

9. Sync the Clock​

# GPS-capable firmware + hardware:
gps on
gps sync

# Otherwise: companion app or Web Serial, after every reboot:
clock sync

10. Reboot and Verify​

Reboot, reconnect serial, then confirm settings persisted, the regions took, and time is correct.

reboot
clock
get role
get path.hash.mode
region
region default
get flood.max.unscoped

region default should answer default scope is <null> and get flood.max.unscoped should answer > 64, the firmware default.

Regions​

Regions let traffic be scoped so it only floods as far as it's useful. A repeater forwards scoped traffic only for regions it carries, so the regions you configure decide what your repeater will pass on. Michigan's region names and county assignments come from the draft Michigan MeshCore Regions RFC, developed by Michigan operators.

Scoping Is On Hold​

info

Some repeaters had already started scoping traffic and others hadn't, so operators agreed to keep the mesh open for now. Until the group decides otherwise:

  • Define regions on repeaters with region def and region save, as below.
  • Don't set region default, set flood.max.unscoped, or use region denyf.
  • Don't set a default scope or channel scopes on companions.

Already changed something? See Undo Scoping Changes for repeaters and Undo Region Scoping for companions.

The Michigan Hierarchy​

midwest
└── mi
├── mi-west
│ ├── grr Grand Rapids
│ ├── azo Kalamazoo
│ └── mkg Muskegon (example)
├── mi-central
│ ├── thumb
│ └── midstate
├── mi-east
│ └── det Detroit (example)
├── mi-north Northern Lower Peninsula
│ └── tvc Traverse City (example)
└── mi-upper Upper Peninsula
└── mqt Marquette (example)

Local regions marked example aren't settled yet. Check with operators near you before carrying one, and if your area doesn't have a local region, stop at the subregion.

Pick Your Regions​

A repeater carries every level above it: midwest, mi, its subregion, and its local region if there is one. MeshCore does not inherit regions, so each one has to be configured. Find your county below for a default subregion:

SubregionCounties
mi-westAllegan, Barry, Berrien, Branch, Calhoun, Cass, Ionia, Kalamazoo, Kent, Montcalm, Muskegon, Newaygo, Oceana, Ottawa, St. Joseph, Van Buren
mi-centralArenac, Bay, Clinton, Eaton, Genesee, Gladwin, Gratiot, Hillsdale, Huron, Ingham, Iosco, Isabella, Jackson, Midland, Ogemaw, Saginaw, Sanilac, Shiawassee, Tuscola
mi-eastLapeer, Lenawee, Livingston, Macomb, Monroe, Oakland, St. Clair, Washtenaw, Wayne
mi-northAlcona, Alpena, Antrim, Benzie, Charlevoix, Cheboygan, Clare, Crawford, Emmet, Grand Traverse, Kalkaska, Lake, Leelanau, Manistee, Mason, Mecosta, Missaukee, Montmorency, Osceola, Oscoda, Otsego, Presque Isle, Roscommon, Wexford
mi-upperAlger, Baraga, Chippewa, Delta, Dickinson, Gogebic, Houghton, Iron, Keweenaw, Luce, Mackinac, Marquette, Menominee, Ontonagon, Schoolcraft

The county table is a starting point, not a border. A repeater carries the subregion of the area it actually covers: a hilltop site in Ionia County whose footprint is mostly Grand Rapids belongs in mi-west and grr. If operators in your area have agreed on something different, that agreement wins.

Examples:

RepeaterCommand
Grand Rapidsregion def midwest mi mi-west grr
Kalamazooregion def midwest mi mi-west azo
Lansingregion def midwest mi mi-central
Detroitregion def midwest mi mi-east
Traverse Cityregion def midwest mi mi-north
Marquetteregion def midwest mi mi-upper

Undo Scoping Changes​

If you followed an earlier version of this guide, your repeater may have a default scope or an unscoped cap. Leave the regions you defined in place and run:

region default <null>
set flood.max.unscoped 64

Both save immediately, so no reboot is needed. 64 is the firmware default, which means no cap.

If you also blocked unscoped traffic with region denyf *, reopen it. Unlike the two commands above, allowf needs a region save:

region allowf *
region save

Then check it:

region default
get flood.max.unscoped
region

Expect default scope is <null>, > 64, and a tree where every line, including the top * line, ends in F:

* F
midwest F
mi F
mi-west F
grr F

Default Scope (On Hold)​

region default <region> would scope the repeater's own adverts to that region. It's on hold, so don't set it.

Unscoped Cap (On Hold)​

set flood.max.unscoped <hops> would drop traffic with no region once it had travelled that many hops. It's on hold, so leave it at the firmware default of 64.

Scoped traffic only travels through repeaters that carry its region, so a mesh where some repeaters scope and others don't loses messages in between. That's why these wait until everyone moves together.

Repeaters on a Boundary​

A repeater can carry more than one subregion. A site on the mi-west / mi-central line that really serves both can carry both, and then it forwards traffic scoped to either. That makes it a bridge, and bridges are a network decision, not a site decision:

  • Carry a neighboring subregion only if you serve companions there. Hearing a neighbor's repeater on a good day isn't coverage.
  • A few deliberate bridges per boundary, announced in the group, beat every edge repeater quietly carrying both.
region def midwest mi mi-west grr
region def midwest mi mi-central
region save

Companion Settings​

Companion region setup, and how to undo a default scope or channel scope set earlier, is on Getting Started, with screenshots for both apps.

Claim a Unique Public Key Prefix​

Repeaters identify each other by the leading bytes of their public key. The firmware generates that key at random on first boot, and nothing stops it from landing on a prefix a nearby repeater already uses. See Public Key Prefix for why the 2-byte prefix matters.

Prior to going online

The public key is the repeater's identity. Rekeying means everyone who already has this repeater as a contact has to re-add it, and admin sessions tied to the old identity stop working. Check your prefix now: rekeying a repeater that's already carrying traffic disrupts everyone using it.

1. Read Your Current Prefix​

get public.key
  • The first 2 hex characters (1 byte) are what apps and contact lists show. There are only 256 of these, so duplicates turn up quickly in any busy area.
  • The first 4 hex characters (2 bytes) are what path.hash.mode 1 stamps into routing paths. This is the one that has to be unique. Two repeaters sharing it both answer to the same path entry and both retransmit, which causes routing issues.

2. Back Up the Key You Already Have​

Before changing anything, save the private key. It's the only way to restore this repeater's identity after a flash erase, or to move that identity onto replacement hardware.

get prv.key

3. Check It Against the Repeaters You Can Hear​

Collisions only cause problems between repeaters in range of each other, so the check that counts is a local one. Ask your own node what it actually hears:

neighbors

Each line reads <8 hex chars>:<seconds since heard>:<SNR>, so a1b2c530:143:8 is a neighbor whose key starts a1b2c530, heard 143 seconds ago. That last number is SNR times four, so halve it twice; 8 means 2 dB. Compare the first four characters of each line against your own, and run this from your repeater once it's on the air.

You'll see roughly the eight most recently heard, even though the repeater tracks more than that. If neighbors replies -none-, either nothing has been heard yet or the neighbour table isn't compiled into that variant.

Your companion app's contact list is worth checking too. It collects every repeater it has heard an advert from, which usually reaches further than a single node's neighbour table. MeshMapper is another way to see what's already on the air in your region. However you go about it, the goal is the same: no collision with the repeaters near you.

4. Generate and Apply a Replacement Key​

There is no on-device key generation command, so this step happens in the browser. Open the MeshCore config tool in a Chromium-based browser and connect to the repeater.

Click Edit (the pencil icon) next to Public Key, enter the four-character prefix you claimed, click Generate, then Use This Key once it finishes.

Set your own prefix

Avoiding collisions is the requirement; picking a prefix you actually recognise is the bonus: your callsign, your initials, anything that makes your repeater easy to spot in a contact list. The MeshCore Key Generator will grind keys until it finds one starting with the characters you want, entirely in your browser, so your keys never leave your device.

To apply a key from it, connect through USB serial or log in to the repeater from a companion node and run:

set prv.key <your_private_key>
reboot

5. Reboot and Verify​

Reboot and confirm the new prefix took.

reboot
get public.key

The first four hex characters should be the prefix you claimed. Back up this new key as well, since it replaced the key from step 2.

get prv.key

To restore a saved key later, paste it back and reboot:

set prv.key <128_hex_characters>
reboot

The firmware validates the key before accepting it and replies OK, reboot to apply! New pubkey: .... If you see Error, bad key, check you copied all 128 characters.

Delay Profiles​

Higher elevation nodes wait longer before retransmitting, letting local nodes handle nearby traffic first. The network self-organizes without manual routing. Choose the profile that best matches your repeater's location.

ProfileTypical siteNeighborstxdelaydirect.txdelayrxdelay
INFRASTRUCTUREWater tower, cell tower, commercial rooftop20+223
ELEVATEDGrain elevator, silo, tall barn10–201.513
SUBURBANTypical rooftop5–100.80.43
LOCALIndoor, ground level, low roof1–30.30.13
MOBILEVehicle, hiking, bikevaries223

INFRASTRUCTURE: Highest Elevation​

Tall fixed infrastructure such as water towers, cell towers, or commercial rooftops with clear line of sight across the area. Backbone of the MichMesh network (e.g. W8CMN sites).

set txdelay 2
set direct.txdelay 2
set rxdelay 3

ELEVATED: Mid Elevation​

Grain elevators, tall barns, silos, or other rural structures with moderate height advantage. Bridges infrastructure nodes to suburban coverage.

set txdelay 1.5
set direct.txdelay 1
set rxdelay 3

SUBURBAN: Average Elevation​

Typical rooftop install serving a neighborhood.

set txdelay 0.8
set direct.txdelay 0.4
set rxdelay 3

LOCAL: Low Elevation​

Indoor, ground-level, or low roof. Only sees a few neighbors.

set txdelay 0.3
set direct.txdelay 0.1
set rxdelay 3

MOBILE: Variable Elevation​

Vehicle, hiking, bike. Always defers to fixed infrastructure.

set txdelay 2
set direct.txdelay 2
set rxdelay 3

Settings Reference​

path.hash.mode: Path ID Size​

Michigan Standard

Michigan settled on path.hash.mode 1 as of May 20, 2026. Make sure to set this on any repeater, and on your companion too. It sets the ID size on the packets your node floods, including the advert the rest of the mesh uses to learn a path back to you. It has no effect on what your node receives.

Every node has a short ID taken from its public key. As a packet floods across the mesh, each repeater that relays it stamps its own ID into the packet, building up a record of the route it took. That record is what lets the mesh learn a path back. path.hash.mode sets how many bytes long your ID is in that record.

ModeID sizePossible IDs
01 byte256
12 bytes65,536
23 bytes16,777,216

Repeater firmware still ships on mode 0. With only 256 IDs to go around, two repeaters in the same area will sooner or later end up with the same one, and the mesh can no longer tell which of them a path actually goes through. Mode 1 makes that vanishingly unlikely. The MeshCore CLI reference has the full details.

Public Key Prefix​

A repeater stamps itself into a packet's routing path using the leading bytes of its public key (its prefix) and matches inbound direct packets against that same prefix. path.hash.mode sets the width: mode 1 means 2 bytes, so four hex characters out of 65,536 possibilities.

Don't confuse that with the 1-byte prefix apps display. Destination addressing is a fixed 1 byte regardless of path.hash.mode, and with only 256 values duplicates are routine; the firmware handles them by attempting decryption, so they're cosmetic. The 2-byte path prefix is the one that must be unique: two repeaters sharing it both claim the same path entry and both retransmit. The prefix is part of the keypair, so claiming a different one means generating a new key.

txdelay / direct.txdelay​

Controls how long a repeater waits before retransmitting a received packet. The firmware works out unit = estimated_airtime × txdelay, then picks the actual delay uniformly at random between 0 and 5 × unit. Higher values create a wider random window, meaning more deference to other nodes. direct.txdelay is the same but for routed point-to-point messages (usually set lower for faster delivery). Both accept 0–2; repeater firmware ships at txdelay 0.5 and direct.txdelay 0.3.

rxdelay: SNR-Based Path Selection​

Only affects flood packets. Direct (point-to-point) packets are always processed immediately. Delays processing of floods based on signal quality (SNR). Strong signal = processed immediately. Weak signal = delayed and likely dropped as a duplicate. The mesh naturally prefers the strongest, cleanest paths without manual routing. It accepts 0–20 and ships off (0).

agc.reset.interval: Radio Deafness Prevention​

Periodically resets the LoRa radio's Automatic Gain Control (AGC) to prevent "deafness" caused by strong out-of-band RF interference. Without this, the SX1262 AGC can lock up, clamping the noise floor at -120 dBm and making the repeater unable to hear weaker signals until rebooted. Especially important for repeaters near broadcast towers or other RF sources.

dutycycle: Airtime Throttle​

Repeater firmware ships with an airtime budget factor of 1.0. The dispatcher computes duty_cycle = 1 / (1 + airtime_factor), so that default works out to 50%: the repeater accrues transmit budget at half of elapsed time and defers sending once it runs dry. The US 915 MHz ISM band has no duty cycle limit, so a repeater left at the default is giving away half its airtime. set dutycycle 100 drives the factor to 0 and removes the throttle.

loop.detect: Packet Storm Protection​

Before repeating a flood, the repeater counts how many times its own hash already appears in that packet's path and drops the packet once the count hits a threshold. Defaults to off. The three levels set how many repeats it tolerates, and the threshold tightens as the hash gets wider:

Level1-byte2-byte3-byte
minimal421
moderate211
strict111

How often the repeater sends a zero-hop advert, heard only by nodes in direct range. Accepts 60–240 minutes and defaults to 0, which is off.

flood.advert.interval: Network-Wide Advert Timer​

How often the repeater floods an advert across the whole mesh, so nodes out of direct range can still find it. Accepts 3–168 hours and defaults to 47.

flood.max: Flood Hop Limit​

Drops a flood packet once its recorded path has reached this many hops. Repeater firmware defaults to 64.

Worth knowing before you tune it: a packet's path field holds 64 bytes total, so at path.hash.mode 1 (2-byte hashes) a flood can only ever carry 32 hops before it runs out of room. Setting 32 costs nothing and matches what other networks publish, but genuinely bounding flood propagation would need a value well below it. For unscoped traffic, flood.max.unscoped would do that, but it's on hold.

Full Settings Audit​

A deeper audit than the setup steps. Run this before and after a field install to verify everything persisted.

You do not need to be at the repeater for most of this. A companion node logged in as admin can run it over the mesh. Only stats-core, stats-radio and stats-packets need a direct USB connection.

Serial connection settings: 115200 baud, 8 data bits, 1 stop bit, no parity, no flow control. The line ending has to include a carriage return, so CR or CRLF both work. LF on its own does not: the firmware discards it and your command never runs.

Identify and Time-Sync​

ver
board
clock
clock sync

Confirm Radio and Identity​

get name
get role
get radio
get tx
get dutycycle
get repeat
get path.hash.mode
get loop.detect
get public.key

Check Regions​

region
region default
get flood.max.unscoped

Every line of region should end in F, region default should be <null>, and flood.max.unscoped should be 64. Anything else is left over from scoping; see Undo Scoping Changes.

From the app, Discover Regions (Scan Local) should show every nearby configured repeater reporting mi and its ancestry.

Check Location and Adverts​

get lat
get lon
get advert.interval
get flood.advert.interval
get flood.max
get flood.max.advert

Audit Owner and Delay Tuning​

get owner.info
get rxdelay
get txdelay
get direct.txdelay

Observe Health and Neighbors​

stats-core
stats-radio
stats-packets
discover.neighbors
neighbors

Optional Site-Specific Checks​

Only run these when the hardware or install actually uses bridge mode, GPS, or power-saving.

# Bridge parameters
get bridge.enabled
get bridge.delay
get bridge.source
get bridge.baud

# GPS state
gps on
gps sync
gps off

# Power saving
powersaving on
powersaving off

This guide is adapted from the Colorado Mesh Repeater Setup Guide, with additional recommendations from the Bay Area MeshCore Repeater Setup Guide and the PugetMesh Repeater Setup Guide. Region guidance comes from the Michigan MeshCore Regions RFC. Thank you to the Colorado Mesh, Bay Area MeshCore and PugetMesh communities for the thorough documentation.