Getting on the air

Buy a radio each, download the app, answer three questions. You do not need to have done anything like this before.

Two people can do this. Three or four is better. Everyone needs their own module.


  1. Buy a radio each

    The Waveshare USB-TO-LoRa-HF, one per person. Small, about the price of a takeaway each, plugs into a normal USB port.

    Watch the last two letters. HF covers 868 and 915 MHz: Europe, North America, Australia. LF is a different band for parts of Asia and cannot talk to an HF unit. Everyone needs the same variant. The TCXO version costs slightly more and is worth it.

    An antenna is included. Do not buy a better one. Where you put it matters far more than what it costs.

  2. Download the app

    Or from the releases page, with everything that changed.

    That is every Mac made since 2020. On an older Intel Mac, use the terminal version further down; it works the same.

    Unzip it and open the program inside: loraline.app on a Mac, loraline.exe on Windows, loraline on Linux. About seventeen megabytes, with everything it needs inside it.

    Your computer will complain. It is unsigned software from somebody who has not paid Apple or Microsoft for the privilege of being trusted, and both of them handle that the same way.

    On macOS it says Apple cannot check it for malicious software. Open it once and let it be refused, then go to System Settings → Privacy & Security, scroll to the bottom, and click Open Anyway beside loraline's name. Only the first time; after that you open it normally.

    On macOS 14 and earlier you could right-click and choose Open instead. Sequoia removed that, so the Settings panel is the way now.

    On Windows a blue panel appears. Click More info, then Run anyway.

    On Linux, nothing complains, but you may need chmod +x loraline first.

    This is a reasonable thing to be suspicious of. The whole source is on the same page you downloaded it from, and the command line version below needs no downloaded binary at all.

  3. Plug the module in and open the app

    It opens a window in your browser and asks three things: what people should call you, the passphrase your group agreed, and where in the world you are.

    It finds the module itself by asking every port on your computer whether it is a radio, and it sets the frequency itself. If nothing answers it says so rather than pretending.

    The passphrase is not a password for an account, because there are no accounts. It is the key to the conversation, and everyone needs the same one. Agree it out loud rather than sending it.

    Nobody to agree one with? There is a link under the box for the open channel, which everyone knows and anyone can join. It is for hearing who is about rather than talking to them: anyone in range can read everything on it. More about that.

    Where you are decides the frequency you transmit on, which is a legal matter rather than a preference. Pick where you actually are.

  4. Hand a module to somebody

    They do the same three steps, with the same passphrase and the same band. Within a few seconds you appear in each other's lists.

    Before anyone walks anywhere, it is worth proving it works across a desk: two modules in one computer, two copies of the app. The second one needs a different identity, which the command line version below can do with --identity.


The same thing in a terminal

Everything the app does, done by hand. Better if you want to see what is happening, necessary if you are on something the app is not built for.

  1. Check you have Python

    Open a terminal and type python3 --version.

    Windows
    Press Start, type cmd, open Command Prompt. Use python --version instead. If nothing happens, install from python.org and tick Add Python to PATH during setup.
    macOS
    Press Cmd+Space, type Terminal, press Enter. If Python is missing, macOS will offer to install the developer tools. Accept.
    Linux
    You already have it.

    Anything numbered 3.9 or higher is fine.

  2. Download the source

    From the repository, click the green Code button, then Download ZIP, and unzip it somewhere you can find again.

    Point the terminal at that folder: type cd with a space, drag the folder onto the terminal window, press Enter. Check with ls, or dir on Windows; you should see README.md.

  3. Install what it needs

    pip3 install pyserial pynacl

    pyserial talks to the USB module, pynacl is the encryption. On Windows use pip rather than pip3, and one extra line, because Windows does not ship the terminal interface Python needs:

    pip install windows-curses

    Now check the whole thing works, without any radio attached:

    python3 tests.py

    You want lines beginning ok, ending ALL PASS. After that, anything which goes wrong is hardware or configuration.

  4. Plug in a module and find it

    Plug the first module in. The computer gives it a name and you need to know it.

    Windows
    Open Device Manager, expand Ports (COM & LPT). Yours will be something like COM3.
    macOS
    Run ls /dev/cu.*. Look for something like /dev/cu.usbserial-0001.
    Linux
    Run ls /dev/ttyUSB* /dev/ttyACM*. Usually /dev/ttyUSB0.

    Unplug it and run the command again. The entry that disappears is yours.

    Linux only. If a later step says permission denied, run sudo usermod -aG dialout $USER, then log out of your computer completely and back in. A new terminal window is not enough.

  5. Tell both modules which frequency to use

    They arrive tuned to 868 MHz, the European band. Elsewhere that is somebody else's licensed spectrum.

    Where you areUse
    Europe, UK, Norway--band eu868
    United States, Canada--band us915
    Australia, New Zealand--band au915
    python3 -m loraline config --port /dev/ttyUSB0 --band eu868

    Use your own port name from step 5 and your own band. Each command should come back with a reply. Then unplug that module, plug in the next, and run the same command again: every module needs identical settings.

    These presets cover the common cases. Power limits and duty cycles vary by country, and you are responsible for what your radio transmits.

  6. Prove it works, on one computer

    Plug both modules into the same computer and have them talk across the desk. If that works, everything except distance is solved.

    Open two terminal windows, both pointed at the loraline folder. In the first:

    python3 -m loraline link --port /dev/ttyUSB0 --band eu868 --role pong

    In the second, using the other module's port:

    python3 -m loraline link --port /dev/ttyUSB1 --band eu868 --role ping

    Replies every few seconds, around −30 to −50 dBm, no loss. That is two radios finding each other.

    Now stop both with Ctrl+C and try the actual client. Pick a passphrase everyone in your group will share:

    export LORALINE_KEY="something you all agree on"
    
    python3 -m loraline chat --port /dev/ttyUSB0 --band eu868 --nick yourname
    
    python3 -m loraline chat --port /dev/ttyUSB1 --band eu868 --nick testing \
        --identity ~/.loraline/second

    On Windows, use set LORALINE_KEY=something you all agree on instead of export.

    Each window fills with a contact list on the left and a conversation on the right, and within a few seconds each sees the other. Type in one and it lands in the other, with a double tick when it is confirmed.

    --identity matters: two clients on one computer would otherwise share a key, decide they were the same person, and ignore each other.

  7. Hand the second module over

    They repeat steps 2 to 4 on their own computer, then run one command. Same band, same passphrase, which you tell them in person rather than over this radio.

    export LORALINE_KEY="something you all agree on"
    python3 -m loraline chat --port /dev/ttyUSB0 --band eu868 --nick theirname

    Run the link test from step 7 between the two houses first. It tells you in seconds whether the path works and how much margin you have, which is easier to read than a chat window that stays quiet.

    Stand the antennas upright. A window sill or an upstairs room beats a desk by more than any setting in the config.


Joining from far away, over the internet

Radio reaches a few kilometres. Somebody further away connects over the internet to a person who does have a radio, and that person passes messages between the two sides. The people near the radio never touch the internet; the distant one never touches a radio.

Relaying happens on sealed messages, before anything is decrypted, so the person in the middle cannot read what passes through them.

If you have the radio, you host

Your friend needs an address to connect to, and a home connection does not usually have one. Tailscale is free for personal use and takes about five minutes.

  1. Put both computers on the same private network

    Install it on both machines and invite your friend from the Tailscale admin page. Each machine gets a permanent address starting 100., with no router settings to change and nothing exposed to the open internet.

    Yours is in the app, or from tailscale ip -4.

  2. Run your client with a door open

    python3 -m loraline chat --port /dev/ttyUSB0 --band eu868 \
        --nick yourname --tcp-listen 4242

    Everything else works exactly as before. The status bar gains a relayed count so you can watch messages crossing between radio and internet.

Relayed messages go out over your radio too, so a chatty distant friend spends your airtime. The status bar shows what is left.

Forwarding a port on your router instead means anyone on the internet can connect. They cannot read anything without the passphrase, but they can make your radio transmit.

If you have no radio, you join

This is the short version. Your friend with the radio does all the configuring; you need Python and one command.

  1. They set it up the same way

    The same three steps as above: Python, the source, then pip3 install -r requirements.txt. Nothing about having no radio changes any of it.

    They join over the internet

    Ask your friend for two things: the address of their machine, and the passphrase the group shares. Then:

    export LORALINE_KEY="the passphrase they gave you"
    
    python3 -m loraline chat --nick yourname --tcp-connect 100.x.y.z:4242

    On Windows, use set LORALINE_KEY=the passphrase they gave you instead of the export line.

    No port, no band, no radio settings: you have no radio, so there is nothing to configure. Within a few seconds the contact list on the left fills with everyone else, wherever they happen to be.

If their computer is asleep or their client is closed, yours will keep retrying quietly and connect when they come back. Anything you type while disconnected waits in the queue rather than being lost.


When something does not work

No port appears in step 5
Try a different USB cable, then a different port. Some cables carry power only. On older Windows machines the module may need the CH340 or CP210x driver, which the manufacturer supplies.
Permission denied opening the port
Linux: the dialout group fix in step 5, followed by a full log out. macOS and Windows do not need this.
Every AT command replies "(no reply)"
Either the port name is wrong, or another program has the module open. Close any serial terminal, Arduino IDE or similar, and try again.
The link test sends but nothing comes back
The two modules disagree about something. Run the config command again on both, with identical arguments, and confirm you are using two different port names for two physically different modules.
They connect but never see each other in chat
Different passphrases. LORALINE_KEY must match exactly, including capitals. If one side has no key set, its group messages go out unencrypted and the other side cannot read them.
The screen is full of strange symbols
Your terminal is not set to UTF-8. On Windows, use Windows Terminal rather than the old Command Prompt window.
The internet connection never comes up
Check the address and that your friend's client is actually running with --tcp-listen. If you are using Tailscale, run tailscale status on both machines and confirm each can see the other.
Connected over the internet, but nobody appears
Almost always a mismatched LORALINE_KEY. It must match exactly, capitals included.
It works on the desk but not between houses
Obstruction rather than distance. Antenna higher and nearer a window at both ends, then --sf 12 on every module for range at the cost of speed. The range table says what to expect.

Once it works

Press Tab to move between the group conversation and private ones. Type /help to see everything. /w followed by someone's name opens a private chat with them that nobody else can read, including anyone relaying it.

Then leave it running. The thing that makes it feel like it used to is seeing somebody appear.


The games, and the noticeboard

catacomms, longshore and hearsay are inside the same app. Open it and they are in the switcher across the top; there is nothing else to install and the chat is the same conversation in all of them.

From source, each is its own repository beside loraline:

git clone https://github.com/intervalplace/loraline
git clone https://github.com/intervalplace/catacomms
git clone https://github.com/intervalplace/longshore
git clone https://github.com/intervalplace/hearsay
cd loraline && python -m loraline

Whatever is checked out next door turns up in the switcher. A build made on its own is a chat client and nothing more, which is a perfectly reasonable thing to want.