Bornhack 2026 badge

Introduction
The BornHack 2026 badge is the Cyber Ægg: an egg-shaped, low-power hacker badge inspired by the 90’s Tamagotchi. It is designed to run for the entire duration of the BornHack camp on a single battery charge, while keeping you connected to everyone else on the field over a long-range LoRa mesh.
Under the playful shell it is a serious little radio computer. A Nordic nRF52840 drives a 1.54 inch black/red/white e-paper display, talks Bluetooth Low Energy to your phone, emulates an NFC tag on its back, and reaches the wider MeshCore network through a dedicated SX1262 LoRa radio. To keep you entertained between messages there is BornPets, a virtual pet with a handful of mini-games.

Front (display and buttons) and back (nRF52840, QWIIC and USB-C connectors, NFC coil).
Features
- Egg-shaped badge inspired by the classic Tamagotchi
- Nordic nRF52840 microcontroller (BLE + USB + NFC)
- 1.54" 152 × 152 black/red/white e-paper display
- SX1262 LoRa radio, part of the MeshCore mesh network
- Bluetooth Low Energy companion connection to the MeshCore app
- NFC tag on the back for location-based games and station taps
- 5-way joystick,
Select / Execute / Cancel buttons, RGB LED and a piezo buzzer - QWIIC (I²C) expansion connector
- USB-C for charging and drag-and-drop file transfer
New to the badge? Start with the Getting started guide. Curious about the virtual pet? See Games. Want to know what is inside? See the Hardware page.
Source code
The Cyber Ægg is open source. Both the hardware design and the firmware live on Codeberg:

- Nordic Semiconductor sponsored their low power yet very capable and fast NRF52840 microcontroller with Bluetooth Low Energy and NFC, making it possible for us to build a device that runs on one battery charge, the whole camp long!
- ALLNET China is our production partner, they take care of sourcing most components and oversee the production process in China, saving us a lot of work and potential headaches and allowing us to focus on the product!
- Procolix sponsored the SX1262 LoRa radio chips, converting the badge into a capable LoRa communications device. Check out their managed hosting solutions for a truely sovereign cloud built on European open source solutions!
- deFEEST sponsored part of the badge hardware, helping us get the components we needed to build it. Find out more at defeest.nl!
- Mollerup Automation sponsored the 3D printed housing for the badge. They are automation, robotics and PLC specialists from Odense, Denmark — see mollerup.info!
1 - Getting started
Welcome to the BornHack 2026 Cyber Ægg badge. This guide takes you from “unbox” to “actually playing with it” in a few minutes.
First power-on
A fresh badge runs a built-in factory self-test on the very first boot. You will see a FACTORY TEST screen with a small PASS/FAIL grid, followed by ALL PASS. After that the badge goes straight to the application on every boot; the self-test never runs again unless the firmware is wiped.
The LED sequence at every boot is:
- Pulsing orange — hardware initialisation
- Pulsing blue — display and LoRa radio coming up (about 13 seconds)
- A single green flash — ready
You then land on the Main screen.
Controls
The badge has a 5-way joystick on the left and two thumb buttons on the right:
| Control | Action |
|---|
| Execute / joystick press (Fire) | Select / activate |
| Cancel | Back / dismiss |
| Up / Down | Move the cursor inside the current screen |
| Left / Right | Switch to the next top-level screen |
Top-level screens
The interface is a carousel — Left / Right cycles through the top-level screens:
| Screen | What it is |
|---|
| Game | BornPets — virtual pet, mini-games and hatchery |
| Main | Root menu: Bornagotchi · Settings · About |
| PMs | Private mesh messages inbox |
| Channel | Group / room mesh chat |
| Adverts | Recently heard mesh adverts |
| Tokens | Collected NFC tokens |
| Clock | Digital / analog watch face and alarm |
| Calendar | Month grid and per-day timeline |
| Name | Big conference-badge name view |
| My QR | Your mesh identity QR code to share with other badges |
Pair with the MeshCore app
The badge speaks the MeshCore companion protocol over Bluetooth Low Energy. Install the MeshCore app on Android / iOS, or open https://app.meshcore.nz/ in a browser that supports Web Bluetooth (Chrome / Edge on desktop or Android).
- Power the badge with USB unplugged — Bluetooth is disabled while USB is connected.
- In the app, scan for devices. Your badge advertises as
Cyber Ægg XXYY, where XXYY is four hex characters unique to your badge. - The phone shows a passkey prompt and the badge shows a 6-digit passkey on its display. Type that number into the phone.
- Once bonded, the app can set the clock, manage contacts, send and receive mesh messages, change the LoRa preset and more.
Set the time
The badge has no battery-backed real-time clock, so the clock resets to “not set” on every reboot. There are two ways to set it:
- MeshCore app — connect over Bluetooth and the app pushes your phone’s time to the badge.
- Near a synced repeater — a known-good mesh repeater advertises its time periodically and your badge picks it up automatically.
Set your timezone once under Main → Settings → Timezone — that setting persists.
Charging
Plug any USB-C cable into the badge to charge it. Charge state is shown on the on-screen battery icon (there is no dedicated charge LED). Remember that Bluetooth is off while USB is connected, so unplug the badge when you want to pair.
Two things that look like faults but aren’t: the charge bolt disappearing while USB is still plugged means charging is complete (it returns by itself if the cell drains), and the battery icon can lag up to a minute behind reality — it is only re-sampled every 60 seconds.
USB drag-and-drop
When plugged in over USB-C the badge appears as a small drive named CYBR<4 hex>. You can drop these files into its root:
| File | Effect |
|---|
ALARMS.ICS | iCalendar file — imports alarms and calendar events |
030000.PCX … 030009.PCX | Sponsor slides shown on the splash carousel |
<6 hex>.PCX | Game sprites |
PETS.CFG | Add / rename pets (with their sprite PCX files) — see Games |
BORNPETS.CFG | Override the BornPets game balance |
LUT.CFG | Custom e-paper waveform (advanced — calibrated display LUT) |
Reboot the badge after copying files (re-plug USB) for the changes to take effect.
LUT.CFG is an advanced tweak: it overrides the panel’s built-in display waveform with a calibrated one (e.g. faster refresh). If a custom LUT ever renders badly, hold Fire (joystick press) while booting to force the safe built-in waveform for that boot, then delete or fix the file. A malformed or wrong-panel LUT.CFG is rejected automatically.
Firmware update
Hold Execute while plugging in USB to enter the bootloader (DFU) mode — the LED blinks red. You can then flash a new firmware image with dfu-util:
dfu-util -d 1915:521f -D cyber-aegg.bin
The firmware is open source and built with Rust / Embassy — see Ranzbak/bornhack-firmware-2026 for source, build instructions and pre-built images.
2 - Quick reference
A one-page cheat sheet for the Cyber Ægg. Print it and tuck it under the strap.
┌─────────────────────────────┐
│ e-paper display │
├─────────────────────────────┤
│ │
│ [UP] │
│ [L][F][R] [CAN] [EXE] │
│ [DN] │
│ │
└─────────────────────────────┘
5-way joystick 2 buttons
(F = press in)
| Button | Anywhere in the menu |
|---|
| Execute / Fire | Select · open · confirm |
| Cancel | Back · cancel · close |
| Up / Down | Move the cursor within a screen |
| Left / Right | Switch top-level screen |
Top-level screens
Left / Right cycles through them:
Game → Main → PMs → Channel → Adverts → Tokens → Clock → Calendar → Name → My QR
LED meanings
| Colour | Meaning |
|---|
| Pulsing orange | Boot — hardware init |
| Pulsing blue | Display + LoRa coming up (~13 s) |
| Single green flash | Boot done |
| Red flicker | Screen refreshing |
| Blue flicker | USB drive write |
| Blinking green | Contacts wipe in progress |
| One-shot red / green / blue | Someone pinged you over the mesh (blinkme) |
Power-on combos
Hold these while connecting USB / resetting:
| Hold | Result |
|---|
| Execute | USB firmware update (DFU mode) |
| Fire (joystick press) | Force safe e-paper waveform (ignore a bad LUT.CFG for that boot) |
| Execute + Cancel + Fire | Factory reset (~40 s — wipes data and settings) |
If the app slot is blank the badge enters DFU on its own.
USB drag-and-drop
Plug in USB-C — the badge mounts as the CYBR<4 hex> drive.
| File you drop | What it does |
|---|
ALARMS.ICS | Imports alarms + calendar events |
030000.PCX … 030009.PCX | Sponsor slides |
<6 hex>.PCX | Game sprite asset |
PETS.CFG | Add / rename pets (with sprite PCX files) |
BORNPETS.CFG | Custom pet balance (KEY=VALUE) |
LUT.CFG | Custom e-paper waveform (advanced) |
Reboot the badge after dropping files.
Firmware update (DFU)
dfu-util -d 1915:521f -D cyber-aegg.bin
Bootloader LEDs in DFU: red blink (idle) → solid blue (flashing) → solid green (done — power-cycle).
Charging
USB-C in any port charges the badge. There is no separate charge LED — the battery icon on the watch / status bar shows the level. Unplug USB to re-enable Bluetooth pairing.
3 - Mesh & messaging
The badge has a LoRa SX1262 radio and speaks the MeshCore mesh protocol. Other badges, MeshCore phones and standalone repeaters all appear as peers. Four carousel screens are mesh-related: PMs, Channel, Adverts and My QR, backed by the Contacts list.
Getting on the same network
Three things must match across every badge in the local mesh:
- LoRa preset — frequency, bandwidth and spreading factor. The default is BornHack 2026 (baked into the firmware). Change it under Main → Settings → LoRa Radio.
- Public channel key — shared automatically via the preset.
- Antenna — make sure the LoRa antenna is connected.
If you can’t see anyone else’s adverts after a minute, check the preset first.
Adverts
Every badge, phone or repeater on the mesh periodically broadcasts an advert — its public name, identity hash and capabilities. Your badge logs these on the Adverts screen as they arrive.
| Key | Action |
|---|
| Up / Down | Scroll the advert list |
| Execute / Fire | Save the highlighted advert as a contact |
| Cancel | Back |
| Left / Right | Next carousel screen |
Private messages (PMs)
The PMs screen is your private inbox — each row is a peer who has messaged you.
| Marker | Meaning |
|---|
● | Heard from less than 5 minutes ago |
* | Favourite |
+ | Discovered, not saved as a contact yet |
R | Repeater |
# | Room / channel server |
S | Sensor |
Use Up / Down to scroll, Execute / Fire to open a thread or start a reply, and Cancel to go back. Replies use the on-screen keyboard (joystick to pick a character, Execute to commit, Cancel to backspace) with about 70 emoji available.
RAM-only
The inbox holds up to 32 messages across 16 peers in RAM. Saved contacts and their threads persist across reboots; messages from unsaved peers vanish when the badge restarts. Save anyone you want to keep.Channels (group chat)
The Channel screen is group / room chat — the same protocol with a broadcast scope. Each row is a channel (for example the default Public channel that ships with the preset). Controls match the PMs screen; everyone on the same preset hears every message in a public channel.
My QR
The My QR screen renders your mesh identity as a QR code. Show it to someone else’s MeshCore phone or badge for instant pairing — no need to wait for an advert to be heard first.
The Contacts list (Main → Bornagotchi → Contacts, or jump there from the Adverts screen) shows everyone the badge has heard or knows: nearby strangers, saved friends, repeaters and rooms.
| Key | Action |
|---|
| Up / Down | Scroll |
| Up on the top row | Open the filter (All / Favorites / People / Repeaters / Rooms / Sensors) |
| Execute / Fire | Popup: PM · Info · Add · Save / Unsave · Forget |
| Cancel | Back |
Popup actions:
- PM — open the message thread.
- Info — hex identity prefix, last-heard time, advert capabilities.
- Add / Save — persist the contact in flash so it survives a reboot.
- Unsave — drop it from flash (stays in the discovery cache until reboot).
- Forget — remove it immediately, even from the discovery cache.
Save what you want to keep
The discovery cache holds up to 32 unsaved peers in RAM and is empty after every reboot until adverts arrive again. Anything you have not Saved — including its message history — is gone on restart. When discovery is full, the oldest unsaved entry is evicted for a new advert.Pinging & visibility
When another badge pings you with the mesh blinkme command your LED briefly flashes in the requested colour — a fun way to find friends in a crowd. Your badge also sends its own adverts so others can see you.
Battery note
The LoRa radio is the single largest battery drain. To save power, Main → Settings → MeshCore lets you mute notification sounds. (The e-paper display itself draws no power once an image is shown.)
Using your phone instead
Prefer to chat from your phone? Install MeshCore on Android / iOS or open https://app.meshcore.nz/, then pair over Bluetooth — see Getting started. Once bonded, contacts, chat and settings are all reachable from the app.
4 - NFC & tokens
The back of the badge has an NFC antenna. Tap a phone or a station reader against it to interact — you don’t have to do anything on the badge, it is always ready.
Two things happen on a tap
A phone reads your broadcast profile
Any standard NFC reader (the built-in Android reader, iOS) sees whatever you have set as your broadcast profile — by default a https://badge.team URL, but you can replace it with your own vanity URL, a vCard and more (see Set your own broadcast data). Tapping with the OS reader simply reads it. Harmless.
BadgeCtl runs a station command
A phone running the BadgeCtl companion app, loaded with the matching event key, can send signed commands when held to the badge. These are used at event stations, where you boost your BornPet’s stats:
| Command | Effect on your BornPet |
|---|
more food | Sets hunger to 0 |
more drugs | Sets sick to 0 |
more inspiration | Sets drained to 0 |
sleep like a bear | Sets tired to 0 |
A short toast on the badge confirms what happened. Each command has a 5-minute cooldown — tapping twice in quick succession does nothing the second time.
Station commands need an active game: pick a pet first (the egg countdown already counts). If your pet has left, start a new egg — a tap with no active pet is silently ignored.
Tokens
Tokens you collect from station taps (and from other badges) land on the Tokens carousel screen. The badge collects many tokens and keeps them until the next reboot, so it is a running record of the stations and badges you tapped during the camp.
When someone pushes a token: onto your badge it shows for about 10 seconds, then the badge reverts to broadcasting your own profile — a pushed token can’t overwrite it.
Set your own broadcast data
The default badge.team URL is not fixed — you can make the badge hand out anything you like. Use any NFC-writer app on your phone (e.g. NFC Tools) and write to the back of the badge:
- Vanity URL — write a URL / URI record (e.g.
annejan.com). A Text record set:https://your.link also works for writer apps that only emit text. - vCard — write a Contact / vCard record; phones tapping you then get your contact card.
- Wi-Fi, or any other record — served verbatim.
The rule is simple: anything you write sticks and survives a reboot — except a token:, which lands on your Tokens screen instead. Keep it short; records are capped at ~127 bytes (fine for a URL or a compact vCard). Long URLs sent via the set: text form are additionally clamped to ~118 characters after the scheme — for anything longer, write a plain URI record instead, or use a link shortener.
There is no NFC “erase” back to the factory default: an empty write (or a writer app’s “format tag”) doesn’t restore the badge.team URL — it just leaves your current profile in place (or stores the empty record). To change what you broadcast, simply write the new record over it.
Setting this is unauthenticated — anyone who can physically tap your badge with a writer app can change it. It is your badge in your pocket; treat physical access accordingly.
What the reader side needs
The badge is always ready; the reader needs:
- The BadgeCtl app installed.
- The matching Ed25519 private key bundled in — BornHack staff hold this for the official stations.
Third-party NFC reader apps can’t issue these commands because they don’t have the key; they only ever see the public URL.
Running your own station
Want your own station? Rebuild the badge firmware with your own Ed25519 public key, then sign the matching commands with your private key in your reader app. The protocol spec, wire format and a signing recipe (Kotlin / Python / Rust) are in the firmware’s NFC_README.md.
How it works (hardware)
The nRF52840 includes an NFC tag PHY driving an on-PCB coil (~2.8 µH) tuned with capacitors to 13.56 MHz. It supports tag mode only (not reader mode) — see the Hardware page.
5 - Clock, alarm & calendar
Three apps share the “watch” carousel slots: Clock, Alarm (opened from the Clock) and Calendar.
Clock
Two switchable watch faces — digital and analog. A small bell icon in the header lights up when an alarm is armed.
Open: push Left / Right until you land on the Clock screen.
| Key | Action |
|---|
| Up / Down | Toggle digital ↔ analog face |
| Execute / Fire | Enter the alarm editor (slot 0) |
| Left / Right | Next / previous carousel screen |
Setting the time
The badge has no backup battery for its real-time clock, so the wall clock resets to None on every boot and reads “Clock not set” until you set it. Two ways:
- MeshCore app over Bluetooth — the phone pushes its time. The easy path.
- Mesh time advert — stand near a synced LoRa repeater and the badge picks the time up over the air. On-air time is only accepted from a trusted source: a signature-verified repeater / companion advert or a channel you hold the key for. A crowd of other badges won’t set your clock.
Set the timezone once under Main → Settings → Timezone — it persists across reboots (default +2, CEST for BornHack).
No seconds hand
A BLE-set time overrides on-air refinement until the next reboot. There is no seconds hand — e-paper refresh is too slow for one.Alarm
Push Execute / Fire on the Clock screen to open the alarm editor.
| Key | Action |
|---|
| Up / Down | Move between fields (Hour → Minute → Days → Tone → Enabled) |
| Execute / Fire | Drill into / out of a field’s edit mode |
| Cancel | Exit back to the watch face |
The Days field cycles: Daily · Weekdays · Weekends · None · Custom. The Tone field offers ten built-in tunes: Beep, Imperial March, Rickroll, Pink Panther, Sandstorm, Startup, Trololo, Daisy Bell, Nokia, Samsung.
When an alarm fires the buzzer plays the chosen tone up to five times, 8 seconds apart. Any button press silences it; if you ignore it, it stops itself after about 32 seconds.
Set the clock first
Alarms only fire when the clock is set. After a reboot, if you haven’t paired or heard a time advert, the alarm won’t go off — pair first.Calendar
A month grid with a per-day timeline of imported iCalendar events.
Open: Left / Right to the Calendar screen (right of Clock). The grid is shown without a cursor; push Execute / Fire to enter active mode.
Active mode:
| Key | Action |
|---|
| Up / Down | Move the cursor ±7 days (jump a week) |
| Left / Right | Move the cursor ±1 day |
| Execute / Fire | Open the day-detail timeline |
| Cancel | Back to the passive view |
Day detail (timeline):
| Key | Action |
|---|
| Up / Down | Scroll ±1 hour |
| Left / Right | Scroll long event titles horizontally |
| Execute / Fire | Full day-list (all events as a list) |
| Cancel | Back to the month view |
Loading events
The badge imports events at boot from a file named ALARMS.ICS in the root of the USB drive:
- Plug the USB-C cable into your computer.
- Open the drive labelled
CYBR<4 hex>. - Drop your
.ics file in the root, renamed to ALARMS.ICS. - Eject the drive.
- Reboot the badge (unplug USB or reset).
You can use the official BornHack programme .ics straight from https://bornhack.dk/.
Limits
Up to 31 events are stored. Multi-day events are clamped to end at 23:59 on their start day (e-paper doesn’t draw events spanning days). All events are RAM-only and re-imported on every boot from ALARMS.ICS.Import limits & quirks
The parser is deliberately minimal. If events are missing or look odd, one of these is usually why:
- File size: 16 KiB max. Anything past that is silently cut off mid-event. A full conference programme easily exceeds this — trim it first with the firmware’s
scripts/strip_ics.py (drops DESCRIPTION/UID/etc. and supports --from / --to / --max to select a range). - 31 events max. Import stops quietly at the cap; later events in the file never appear.
- No recurrence.
RRULE is ignored — a repeating event imports as its first occurrence only. Export “expanded” per-occurrence ICS instead (the BornHack programme already is). - No all-day events. A DATE-only
DTSTART is dropped without warning. Give the event a real start time. - ASCII only. Non-ASCII characters in titles are stripped, not transliterated (
Æ, accents and emoji simply vanish). - Timezones. Only
Z-suffixed (UTC) timestamps are shifted to local time — always by the built-in default of UTC+2 (right for BornHack), because the import runs before your persisted timezone setting is applied. Floating and TZID=-zoned times are taken as-is. When in doubt, export in UTC. - Fired events disappear from the Calendar until reboot. Imported events are one-shot alarms: once one has fired it no longer shows on the grid or day view. Rebooting re-imports everything.
- Edits apply at boot only. Replace
ALARMS.ICS, eject the drive properly, then power-cycle the badge.
6 - Games
The Game screen runs BornPets — a virtual pet inspired by the 90’s Tamagotchi — plus a set of mini-games you launch from the pet’s Play menu.
BornPets
Hatch a snail or a cat, then keep it fed, healthy, rested and entertained.
Hatching
The first time you open the Game screen you see the hatchery. Push Execute / Fire to start, pick a pet from the roster (the built-ins are Bartholomeus, Cat and Slug), then wait about a minute for the egg to hatch. After hatching you name your pet — up to 12 characters via the on-screen keyboard. The save persists across reboots. You can rename the roster or add your own pets — see Custom pet roster below.
Stats
Your pet has decaying stats — the higher they get, the worse off the pet is. Watch out for:
| Stat | Fix with | Notes |
|---|
| Hunger | Feed | The pet gets hungry and other stats worsen |
| Tired | Rest / sleep | Or Hibernate for long sleeps |
| Drained | Play or a mini-game | Lack of inspiration — also resets “miserable” |
| Sick | Heal | Use when the sick icon appears |
| Miserable | Play | Makes the other stats decay faster, so treat it early |
Stats interact: when several stats are bad the pet becomes miserable faster, and miserable makes everything else worse. Stay ahead of the spiral.
Controls
| Key | Action |
|---|
| Up / Down | Switch between the top (actions) and bottom icon rows |
| Left / Right | Move along the current row |
| Execute / Fire | Activate the highlighted icon |
| Cancel | Back out |
Hibernate
Putting the badge away for more than a few hours? Open the action menu and choose Hibernate — stats freeze until you wake the pet. Forget to hibernate before storing the badge and the pet keeps decaying, so it may have starved by the time you find it again.
Game modes
Two difficulty presets, picked via Main → Bornagotchi → Mode:
- Classic — the original balance the badge ships with.
- Casual — roughly half the decay speed and more relief per action, for people who don’t want to baby-sit.
The setting persists in flash. A * next to the mode name means the change is queued — reboot the badge for it to take effect.
Mini-games
Open the bottom-row Play menu in BornPets and pick a game. Each win reduces the drained stat without raising hunger, so they are free entertainment. Cancel always exits a mini-game.
| Game | Goal |
|---|
| Tic-Tac-Toe | Draw or beat the computer (Normal or Impossible difficulty) |
| Lights Out | Toggle a 5×5 grid until every light is off |
| Nim | Force the computer to take the last stick |
| Maze | Reach any border exit of an 18×18 maze |
| Black Hole | Beat the AI’s adjacent-sum on a 21-cell pyramid |
| Triple Born | A Triple Town style merge game on a 6×6 board |
| BornJeweled | Accessible match-3 with a 30-move limit |
Inside a game: the joystick moves the cursor, Execute / Fire places or selects, and Cancel quits back to the Play menu.
Make your own pet
Want a companion that isn’t a snail or a cat? The CyberÆgg Pet Maker is a browser-based sprite and animation editor for BornPets:
scene.rs/pets/
With it you can:
- Start from a preset (Bartholomeus, Cat, Slug) or a Blank canvas.
- Draw each animation frame with the badge’s palette — black, red, white and transparent (white is the e-paper background; transparent means “not drawn”).
- Preview animation states (e.g. Idle) with speed and onion-skin controls.
- Optionally tune the game balance (
BORNPETS.CFG) — how fast stats decay and recover. - Download ZIP to get everything packaged for the badge.
Installing a custom pet
The badge exposes a USB drive when plugged in over USB-C (see Getting started). Unzip the export from the Pet Maker and copy the sprite files — plus PETS.CFG, and BORNPETS.CFG if you made one — into the root of the CYBR<4 hex> drive, then reboot the badge.
Custom pet roster: PETS.CFG
PETS.CFG is the pet roster shown in “Choose your Pet”. It is a plain-text file with one PREFIX=NAME per line, editable without reflashing the firmware:
# --- current pets (rename if you like) ---
0=Bartholomeus
1=Cat
2=Slug
# --- add your own (needs 05xxxx.PCX / 06xxxx.PCX sprites) ---
5=Dragon
6=Ghost
- PREFIX is the pet’s sprite-prefix byte (decimal):
0, 1, 2 — the built-in pets (listing them just renames them)3, 4 — reserved (sponsors, menu icons) and ignored5–7 — your own custom pets
- NAME is up to 16 ASCII characters.
A pet’s sprites are the matching PPAAFF.PCX files on the badge — PP is the prefix, AA the animation part, FF the frame. The firmware just counts the PCX files present (for example 050100…050104 = five idle frames), so there is no fixed frame count or header to maintain. Export sprites at the pet’s prefix from the Pet Maker and drop them next to PETS.CFG on the drive. Lines beginning with #, and reserved or malformed rows, are ignored.
Custom balance: BORNPETS.CFG
If you only want to change the difficulty (not the sprites), drop a plain-text BORNPETS.CFG in the root of the badge’s USB drive with one KEY=VALUE per line:
# speed up hunger decay, slow down the drained stat
HUNGER_RATE=4
DRAINED_INTERVAL=180
Eject the drive and reboot. When a config is active a small * appears after the pet’s name. Delete the file and reboot to return to a preset. The Pet Maker can generate this file for you, and the firmware’s USER_GAMES.md documents every supported key and its range.
A few gotchas:
- Edits apply at boot only. Eject the drive properly (so the write is flushed), then power-cycle. No
* after the pet name = no override was applied. - The parser is silent. Unknown keys are skipped, and a value that isn’t a plain whole number (no units, decimals or minus sign) drops the whole line without any on-screen error.
- The documented “reasonable range” is advice, not a limit. Values are only clamped to the raw integer type —
HUNGER_RATE=1000 really does make hunger fill ~300× faster, and your pet will be starving before you’ve unplugged the cable. If a wild value wrecked your pet, delete the file and reboot to fall back to the preset.
7 - Hardware
The Cyber Ægg is a low-power LoRa badge built around a Nordic nRF52840 microcontroller. The design goal is to run for the entire week of BornHack on a single battery charge, so a lot of care goes into keeping the power consumption down in both hardware and firmware.
The full KiCad design is open source at Ranzbak/bornhack2026-hardware.
Prototype
At the time of writing the design is still at prototype stage. Some of the RF circuits (NFC, LoRa, Bluetooth) still carry U.FL / IPEX connectors to make tuning easier, and the on-PCB antennas are not yet fully characterised. Consider this design beta — do not order your own boards yet.Overview
| Component | Part | Interface |
|---|
| Microcontroller | Nordic nRF52840 | — |
| Display | 1.54" black/red/white e-paper, 152 × 152, SSD1675 / SSD1675B controller | SPI |
| LoRa radio | Semtech SX1262 | SPI |
| Bluetooth Low Energy | nRF52840 built-in radio | — |
| NFC | nRF52840 NFC tag PHY + on-PCB coil | — |
| Expansion | QWIIC (I²C) connector | I²C |
| Input | 5-way joystick + Execute / Cancel buttons | GPIO |
| Feedback | RGB LED, piezo buzzer | GPIO / PWM |
| Power | Li-ion battery, USB-C for power and data | — |
Display
The badge uses a 1.54 inch tri-colour (black / red / white) e-paper display with a resolution of 152 × 152 pixels, driven by an SSD1675 / SSD1675B controller. E-paper keeps the badge readable in bright camp sunlight and draws no power to hold an image, which is a big help for the week-long battery goal.
By default the panel is driven with the waveform LUT stored in its own OTP. Advanced users can override this with a calibrated waveform (for example a faster refresh) by dropping a LUT.CFG file on the USB drive — see the firmware’s LUT.md. Holding Fire while booting always forces the safe built-in waveform.
Because the Cyber Ægg is inspired by the 90’s Tamagotchi egg-shaped toy, the buttons carry the same names:
| Button | Function |
|---|
| Select | Navigate through the menu options |
| Execute | Start the option under the cursor |
| Cancel | Cancel the current operation |
To make navigation more intuitive, the Select button is implemented as a 5-way joystick with a press action.
Bluetooth
Bluetooth Low Energy is provided directly by the nRF52840. It operates in the 2.4 GHz band and uses an on-PCB antenna based on a Texas Instruments reference design (included in the standard KiCad 9 library). See the TI application note SWRA228 for details.
LoRa
Long-range connectivity is provided by a dedicated Semtech SX1262 radio with the matching/balun circuit specified in the Semtech application note AN1200.54. The LoRa antenna is a Texas Instruments design documented in SWRA416. On the network side the badge speaks MeshCore, so it can join the wider camp mesh out of the box.
NFC
The nRF52840 includes an NFC PHY, used here to drive a resonant circuit consisting of an on-PCB coil (roughly 2.8 µH) and tuning capacitors, forming a tank circuit matched to 13.56 MHz. The nRF52840 only supports tag functionality (not reader mode), which the firmware uses for location-based games and station taps.
QWIIC
The badge carries a QWIIC connector — a standardised I²C connector used by a large range of SparkFun and third-party breakout boards. Two 10 kΩ pull-up resistors are fitted on the board, and the nRF52840’s internal pull-ups can be enabled as well when the bus capacitance is high.
Power
The badge is powered by a Li-ion battery and charged over USB-C. Bluetooth is disabled while USB is connected to keep the charging path simple, so unplug the badge when you want to pair with the MeshCore app.
8 - FAQ & troubleshooting
Quick answers to the things people most often hit with the Cyber Ægg. If none of these help, file a bug (see the bottom of the page).
General
The badge won’t wake / the display stays blank.
Plug in USB-C. If the LED never blinks, hold Execute while plugging in and re-flash the firmware with dfu-util — see Getting started → Firmware update.
A fresh flash (or factory reset) shows the factory test, then a “ready to ship” screen — and hangs there.
By design. After an all-pass self-test the badge stamps its pass flag, draws the ship screen and halts (green LED pulsing). Power-cycle once more; the second boot skips the test and starts the app.
“Battery voltage critical” screen at boot, the badge goes no further.
The cell measured below 3.0 V at power-on, so the firmware halts to protect it. Charging is hardware-controlled and continues anyway — leave USB plugged in for a while, then power-cycle manually (the badge does not reboot itself off this screen).
The clock keeps resetting on every reboot.
Expected — there is no battery-backed RTC. Pair over Bluetooth with the MeshCore app once per boot, or wait until you are near a synced mesh repeater. Note that on-air time is only accepted from a trusted source — a signature-verified repeater / companion advert or a channel you hold the key for. A crowd of other badges won’t set your clock; a phone pairing always will.
Bluetooth isn’t visible / I can’t pair.
Two things to check: USB is plugged in (Bluetooth is disabled whenever USB is connected — unplug), or Bluetooth was switched off in Main → Settings → Bluetooth (the toggle persists across reboots; set it back to BLE: ON).
My alarm never fired.
The clock hasn’t been set yet this boot — alarms only fire once the time is known. If the clock is set, check the alarm’s Days field — None never fires, and a Weekdays / Weekends / Custom mask only fires on matching days (the header bell shows for any enabled alarm regardless of its day mask).
No mesh peers show up.
Walk around — LoRa range varies with terrain and antenna orientation. Also check your LoRa preset under Main → Settings → LoRa Radio; it must match the rest of the local mesh. See Mesh.
I reformatted the badge’s USB drive and everything is gone.
Don’t reformat. The badge only understands its own FAT12 layout; if boot finds anything else (exFAT, NTFS, odd sector sizes) it silently re-formats the whole partition — wiping every file. To clear files, delete them normally instead. If it already happened: copy your .PCX / .ICS / .CFG files back on and reboot.
The charge bolt disappeared while USB is still plugged in.
Charging is complete — the bolt returns by itself if the cell drains. Also, the battery icon can lag up to a minute behind reality; it is only re-sampled every 60 seconds.
Display (e-paper)
Red only shows up sometimes — e.g. after switching screens.
Working as designed. Staying on one screen uses fast black/white refreshes that don’t repaint the red plane; red repaints on a full refresh (a screen switch, or periodically). It isn’t disabled — it just refreshes less often than black/white.
No red at all / washed-out screen after adding a custom LUT.
Your LUT.CFG is a fast waveform that skips red. Delete LUT.CFG from the badge’s USB drive, or hold Fire (joystick press) while booting to force the built-in tri-colour waveform for that boot. See Hardware → Display.
Blinking white LED / won’t finish booting after dropping a LUT.CFG.
A bad or wrong-panel LUT.CFG is rejected automatically, but if the screen is unreadable, hold Fire while booting to force the safe built-in waveform, then delete or fix the file.
The badge boots fine but ignores my LUT.CFG.
Rejection is silent. Common causes: wrong variant letter for your panel, the wrong key copied from the calibration tool (it wants the flat band_lut hex field, not stage_luts), a file over ~2.8 KB (trim comments and unneeded band overrides), or bad hex length (each LUT value must be exactly 214 hex characters). Holding Fire at boot also forces the built-in waveform for that boot. Details in the firmware’s LUT.md.
Mesh / Bluetooth
The MeshCore app says “connected” but nothing works — can’t set the clock, no contacts, messages won’t send.
Stale pairing. The phone forgot the bond (you removed it in Bluetooth settings, or switched phones) but the badge still has it, so every command is rejected as unauthenticated. Fix: Main → Settings → Bluetooth → Clear pairings (wipes all bonds and reboots the badge), then pair fresh. The badge keeps at most 4 bonds — pairing a fifth phone silently doesn’t stick.
The Channel screen shows “BLE client connected” and the buttons are dead.
By design: while the phone app is connected the on-badge channel browser locks (only Left / Right / Cancel work). Close or disconnect the app and the screen unlocks immediately.
My PMs and the peers I’d heard are gone after a reboot.
The PM inbox and the recently-heard list live in RAM only. Saved contacts persist — when you meet someone you want to message later, open their entry and save them before powering off.
NFC
My vanity URL / vCard doesn’t stick.
Write it with an NFC-writer app as a normal URL/URI, vCard or Wi-Fi record — anything you write (except a token:) becomes your broadcast profile and persists across reboots. See NFC & tokens → Set your own broadcast data.
A token I received disappeared / a URL I tapped reverted.
A token: write is intentionally transient — it lands on the Tokens screen (kept until reboot) and the broadcast reverts to your own profile after about 10 seconds. A pushed token can’t overwrite your profile.
A station tap did nothing — no toast, pet unaffected.
Station commands only apply while you have an active game: pick a pet first (the egg countdown already counts), or start a new egg if your pet has left. Also: station commands come through the signed BadgeCtl reader — writing the phrase (e.g. more food) as a plain text record with a generic NFC app doesn’t feed your pet; it just becomes your broadcast profile, and your badge now proudly hands out “more food” to every phone that taps it. Write a new URL / vCard to fix that.
Game / BornPets
The pet area shows “No sprites on flash”.
The boot scan found zero .PCX files — typical after a factory reset, a drive reformat, or a fresh flash without the asset set. Copy the sprite .PCX files back onto the CYBR<hex> drive and reboot.
A sprite I made shows wrong colours / doesn’t show at all.
The badge needs a very specific PCX flavour: 2 bits-per-pixel, single plane, RLE, with the fixed palette order 0 = black, 1 = red, 2 = white, 3 = transparent (the file’s own palette is ignored). A normal 256-colour or 24-bit export is silently skipped. The Pet Maker and the firmware’s asset tool get all of this right.
BORNPETS.CFG / a mode change seems to have no effect.
Both apply at boot only — eject the drive properly (so the file is flushed) and power-cycle. No * after the pet name = no override was applied. See Games.
Where to file bugs
Found something broken? Open an issue on the firmware repository:
https://codeberg.org/Ranzbak/bornhack-firmware-2026/issues