development · group and LoRa ·
Where the rest of the group is on the map, with no network at all
A paper map tells you what is around you. It does not tell you where the people you set out with are, and on a hike that is the question, because a walking group spreads out over ground with no phone signal. Group draws them on the same screen as the map: one marker each, their initials inside it, and how old the position is underneath. Up to twelve people. The positions travel straight from device to device on a small radio called LoRa, with no SIM, no cell coverage and no server in the middle.
One of the devices we support carries that radio, the LilyGo T5 S3 Pro, and everybody in the group needs one. It is in the published build for that board, switched off until you turn it on. Nobody has walked a range test yet, so this page claims no distance.
What it answers, and what it does not
It answers where is everybody and when were they last heard. It does not say which way to go to reach them, it computes no route, and it sends nothing anywhere on its own. A pencil cross on a paper map says the same thing; this one updates itself.
It is also not a safety device. When the radio does not reach, nothing appears on the panel and nobody is told. Somebody who walks out of range keeps their marker where you last heard them, and the age under it keeps counting up. That growing number is the only warning you get, and it is the warning on purpose: the device never claims a position is fresher than it is. Ages round up, never down, a stale position is drawn as stale so an old one never passes for a new one, and an age the device cannot work out is a question mark instead of a number.
One marker per person: how a group member draws on the map
Each approved member gets the same balloon shape your own saved places use, with a filled head carrying their initials. Your own pins are hollow, so a place and a person never read as the same thing. Twelve people maximum. The list is a fixed size, so the map screen cannot run short of memory because somebody joined.
Freshness is carried by shade, not by shape, because a hollow balloon reads as a different kind of marker while a faded one reads as the same person with older news:
| State | How it draws | When |
|---|---|---|
| Fresh | Filled black head, white initials | Younger than five minutes |
| Stale | Grey head, black initials | Older than five minutes |
| Hidden | Not drawn at all | Older than six hours |
Both limits are settings, and hiding can be switched off entirely. The six hours used
to be thirty minutes until 2026-10-23, and the reason it moved is worth keeping: two
boards sat on a desk for two hours, the marker was gone from the map, and the node list
on the same device said the other board had been heard 223 seconds ago. Two screens
answered one question and contradicted each other, because one means I heard them
and the other means I know where they are. A two-hour-old position is still the
best thing we know about a companion. Drawn faded with 2h under it, that is
exactly what it says.
A caption appears under a marker only when the marker alone cannot answer:
1.2 km when you are zoomed out too far to judge distance,
1.2 km/15m when the member is far and the news is old, 15m
when they are close and the news is old, and nothing at all when the group is together
and talking. Distance rounds to a hundred metres because a satellite position is
accurate to tens of metres, and age rounds up to five minutes because that is how often
the panel revisits it.
E-ink holds whatever was last drawn, so a group that goes quiet would keep showing "everybody is fresh" for as long as you look at it, which is exactly when the age matters. The ages are therefore re-evaluated every five minutes on their own, and the panel is repainted only when the picture would actually differ.
The Group screen: every LoRa node the antenna has heard
Group is its own entry on the home screen, third in the list, and it is where the radio lives: its own state, how often this device announces itself, what this device is called, and every node the antenna has heard, approved or not.
The map menu carries the other half, the members themselves, each with distance, compass direction and age:
RF Roman 450 m NE 1m
MK Marek 440 m SW 1m
JKL Jakub 480 m S 1m
AB Anna --
Selecting one moves the map to them. Two dashes, as on the last row, mean that member has not said anything yet, which is a different fact from a position we distrust. A member the radio has not heard reads as not on LoRa rather than offline, because this screen can only see one radio and must not report the others as silent.
Who is allowed on your map: an allowlist, not a contact list
The roster stored on the device's memory card is an allowlist, not a contact list. A position from an identifier that is not in it is refused, counted and logged, never drawn and never stored. That is the case this feature has to get right: a radio hears whoever is in range, which includes another group on the same channel and anyone who would like to put a stranger on your panel as if they were one of you. Our Bluetooth advertising runs with no pairing, so "in range" is the only credential a stranger would otherwise need.
Announcing yourself is the other half of that bargain, and it is the reason the radio ships switched off. An announcement is a plain broadcast of this device's name and position to anyone in range, so turning the radio on is a decision somebody takes, not a default they inherit.
Each member holds two or three initials, an optional name for the list only, and a list of identifiers rather than one. The same person arrives under a radio key over LoRa and under something else entirely when a phone relays them, and nothing outside your device can tie those together, so your device does it. Two rules hold it: an identifier belongs to one person, and one set of initials belongs to one member.
An identifier is deliberately not a hardware address. A fixed broadcast address is a tracking beacon by definition, and modern phones treat it as one. What belongs here is the transport's durable identity, which under MeshCore is a public key, and that is part of why MeshCore was picked: packets are signed, so a forged position has something to fail against.
The radio: MeshCore on a Semtech SX1262 at 869 MHz
LoRa is a radio made for long range at a very low data rate. It carries tens of bytes at a time over kilometres of open ground, on a licence-free band, with no operator and no subscription behind it. MeshCore is an open mesh protocol built on top of it. Our node is a companion node, not a repeater: it announces itself and listens, and it does not carry other people's traffic. An announcement is a public key, a timestamp, a signature over both, and optionally a name and a coordinate.
We picked MeshCore over Meshtastic, which is the better known of the two, for two reasons that have nothing to do with the radio. Meshtastic's firmware is GPL-3.0 and ours is MIT, so linking it in would relicence the whole image. And MeshCore is a library of about 87 kB in eleven files, while Meshtastic is an application of 82 MB. One embeds in a map reader, the other does not.
| Setting | Value |
|---|---|
| Radio | Semtech SX1262, on the LilyGo T5 E-Paper S3 Pro |
| Frequency | 869.618 MHz, in the 868 MHz European licence-free band |
| Bandwidth | 62.5 kHz |
| Spreading factor | 8 |
| Coding rate | 4/5 |
| Transmit power | 14 dBm |
The three middle rows are the trade between range and speed, and they are set towards range. 869.618 MHz sits in a European licence-free band, so transmitting on it here needs no licence and no call sign. The board also sells in 433, 915 and 920 MHz versions, and which one you may use depends on where you are. We have only run the European one.
This does not need a phone to carry positions between devices. It does need something that knows where each person is, and on this board that is the satellite receiver on the same PCB. The Xteink readers have no receiver and no radio: there the position comes from your phone over Bluetooth, which is why group positions on those devices are a later, different path.
How often a device speaks is a floor, not a period: no faster than this, not exactly this often. Moving sends every 100 m. Stopping after moving sends once, because the group's real question is where somebody halted. Somebody crawling, parked, or with no satellite fix sends at most every ten minutes, and a fix appearing or disappearing sends straight away.
The parked limit was an hour until 2026-11-02. It was shortened after an hour-old marker read as a broken screen on a hike: a stop still has to tell the group where it is, so silence is capped rather than left to the movement test. The move threshold doubles to 200 m when the phone reports a loose fix, because under tree cover a wandering fix otherwise reports movement that never happened.
Receiving costs single-digit milliamps the whole time it is on, and transmitting costs almost nothing by comparison, so the two are gated for different reasons. The radio listens while the map or the Group screen is open and nowhere else: not on Home, not in settings, not asleep. Transmitting is gated for airtime, which is the share of the band one device may occupy, and for the privacy reason above.
What the memory card records, and for how long
Every accepted position is appended to a plain CSV on the card, one file per day: when the sender sent it, when we heard it, who it was, under which identifier, where, which way, how fast, and over which radio. Our own timestamp is the one that matters, because the sender may have no clock and we have one from the phone or from the satellite receiver. Fourteen days are kept and the oldest whole day is dropped, so a file somebody is reading on a laptop does not change under their hands.
A member's position was sent to you on purpose. Your own track is a record of where you went, on a card that is lost with the device, so it stays off until you turn it on. Your own rows are written at most once every thirty seconds or every 25 m; other people's are never throttled, because they are rare and each one is worth keeping. After a reboot the last known position of every member is read back, so whoever spoke on the last trip is on the map before they speak again.
How far does it reach on foot? We have not measured it
The marker layer was built on 2026-09-16 and run on an X4 Pro the same day. Positions over the radio followed on 2026-10-22, verified on two LilyGo T5 S3 Pro boards: an announcement from the second board carried a coordinate, the group layer accepted it and the marker appeared on the first board's map. The marker layer needed no change to accept them, because it was written without knowing which radio would feed it.
What has not happened is the walk. Two boards on a desk say nothing about two people on opposite sides of a hill, and until somebody measures that, this is a feature that works on a desk and may not work where it is meant to. The radio half ships in the published build for the T5 S3 Pro, the only board with a radio. The marker layer itself is in the X4 Pro build too, with nothing to feed it there yet, and out of the X4 and X3 build, which share one binary and one memory budget.
And on 2026-11-02 the two desk boards stopped hearing each other. Three announcements one way, nothing received the other, while both boards heard third-party MeshCore stations far away at minus 98 to minus 105 dBm, which is faint and still readable, and reported identical channel settings. A board on the same desk should arrive near minus 30. A raw ping and pong both ways, bypassing the protocol entirely, timed out in both directions with the listening side's own received-packet counter at zero. That narrows it to the radio hardware on those two boards rather than the code above it, and it is open.
Three more things are not done. A member off the edge of the screen has no marker at the border yet, because the marker we draw at the edge for your own saved places merges with its neighbours, and a merged one would cover somebody's initials. Nobody has checked how a solid black marker behaves in direct sun or whether it ghosts more than a thin outline, which is a question for a day outdoors and not for a desk. And a replayed announcement from somebody recording the channel is not solved: an allowlist stops a stranger, not an impersonator.
What happens next is one walk. Two boards, two people, a hill between them, and the distance written down. That number decides whether this is a feature or a desk demo, and it goes on this page the day somebody has it.