LoRaWAN: Installing Basic Station and connecting to The Things Network V3 Stack

With the migration of The Things Network to the version 3 stack, I thought it was an opportune time to upgrade my Raspberry PI based gateway from the legacy Semtech packet forwarder to Basic Station.

Basic Station

LoRaWAN gateway maintainers should be using secured and encrypted connections to the LoRaWAN Network Server (LNS) rather than the old legacy packet forwarder using UDP packets.

Semtech provide opensource software called LoRa Basics™ Station for this purpose:

Basic Station exchanges data as JSON encoded objects over secure WebSockets.  The gateway identifies itself with a secret API key, ensuring it’s authorised.

In addition to security, the protocol allows for LNS discovery and load sharing and also includes CUPS or Configuration and Update Server allowing for easy management of gateway fleets.

Installation

These instructions assume you have a functional operating system installed on your PI with network enabled and working.  I prefer to use Raspberry Pi OS Lite without a desktop.

You will also require git to be installed. To install, execute:

sudo apt-get update
sudo apt-get install git

The SPI interface port on the Raspberry Pi is normally switched off by default. To enable SPI, you will want to run:

sudo raspi-config 

and under (3) interface options, enable (I4) SPI – automatic loading of the SPI kernel module. If you are using a CoreCell concentrator, you will also need to enable I2C – (I5) – automatic loading of the I2C kernel module.

While you are there, we have the GPS module’s TX and RX lines connected to the serial port. The serial port is normally enabled as a console. Disable (P6) shell messages on the serial connection, but leave the serial port hardware enabled.

Now clone the latest version of Basic Station:

git clone https://github.com/lorabasics/basicstation.git
cd basicstation

If you are using a Corecell SX1302/SX1303 based concentrator (RAK5146, RAK2287 etc) build with platform=corecell:

make platform=corecell variant=std

Or If you are using an older SX1301 based concentrator (RAK833, RAK2245, RAK2247 etc) build with platform=rpi:

make platform=rpi variant=std

During the build process, dependencies such as mbed TLS and the libloragw SX1301 and SX1302/SX1303 (Corecell) Driver/HAL are downloaded and compiled.

Configuration

A couple of configuration files are needed to start Basic Station. The good news is, unlike the old packet forwarder, most of the parameters (i.e. the channel plan configuration) are obtained from the LNS. The station.conf file now really only describes the hardware and this shouldn’t change provided the hardware remains fixed.

You will want to keep all the configuration files together. I normally create a folder called TTN in my home directory for this purpose:

cd ~
mkdir TTN
cd TTN

The first thing Basic Station needs to know is what LNS to establish a connection with.  Log into The Things Network Cluster Picker and select the closest geographically located server to minimize network latency. Currently the following LNS exist:

  • Europe 1: eu1.cloud.thethings.network
  • North America 1: nam1.cloud.thethings.network
  • Australia 1: au1.cloud.thethings.network

Create a file called tc.uri and populate it with the server name. Packet transport with the The Things Network V3 LNS happens on port 8887.

(CUPS communicate on port 443)

wss://{eu1|nam1|au1}.cloud.thethings.network:8887

Next we need to establish a trust relationship. This involves copying the root certificate (expires Jun 2035) to a file called tc.trust.

curl https://letsencrypt.org/certs/isrgrootx1.pem.txt -o tc.trust

We also need to create a tc.key file to authorise the gateway – more on this later.

Finally, create the station configuration file – station.conf.

If using a SX1302/SX1303 based concentrator (CoreCell) populate station.conf with:

{
    "radio_conf": {                       /* Actual channel plan is controlled by the server */
        "lorawan_public": true,           /* is default */
        "clksrc": 0,
        "device": "/dev/spidev0.0",
        "pps": true,                      /* default SPI device is platform specific */
        "antenna_gain": 0,                /* antenna gain, in dBi */
        "full_duplex": false,
        "radio_0": {
            /* freq/enable provided by LNS - only hardware-specific settings are listed here */
            "type": "SX1250",
            "rssi_offset": -215.4,
            "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0},
            "tx_enable": true
        },
        "radio_1": {
            "type": "SX1250",
            "rssi_offset": -215.4,
            "rssi_tcomp": {"coeff_a": 0, "coeff_b": 0, "coeff_c": 20.41, "coeff_d": 2162.56, "coeff_e": 0},
            "tx_enable": false
        }
        /* chan_multiSF_X, chan_Lora_std, chan_FSK provided by LNS */
    },
    "station_conf": {
      "log_file":    "stderr",
      "log_level":   "INFO",
      "log_size":    10e6,
      "log_rotate":  3
    }
}

Or if using an older SX1301 based concentrator populate with:

{
   "radio_conf": {                  /* Actual channel plan is controlled by the server */
       "lorawan_public": true,      /* is default */
       "clksrc": 1,                 /* radio_1 provides clock to concentrator */
       "device": "/dev/spidev0.0",  /* default SPI device is platform specific */
       "pps": true,
       "radio_0": {
           /* freq/enable provided by LNS - only hardware-specific settings are listed here */
           "type": "SX1257",
           "rssi_offset": -166.0,
           "tx_enable": true
       },
       "radio_1": {
           "type": "SX1257",
           "rssi_offset": -166.0,
           "tx_enable": false
       }
       /* chan_multiSF_X, chan_Lora_std, chan_FSK provided by LNS */
   },
   "station_conf": {
     "log_file":    "stderr",
     "log_level":   "DEBUG",
     "log_size":    10e6,
     "log_rotate":  3
   }
}

Further details of the configuration file can be found here.

The only part you are likely to want to change is the log settings. Instead of logging to file, we send the output to stderr for debugging.

The log levels are:

XDEBUG, DEBUG, VERBOSE, INFO, NOTICE, WARNING, ERROR, CRITICAL

When you put your gateway into production, you may want to reduce the log level to notice to minimise ware on the flash memory.

Reset

The SX1301/SX1302/SX1303 Digital Baseband chip should be reset after power-up. However, this initial reset of the SX130x is not performed by Basic Station/libloragw. We have to do this externally and use gpioset that comes with the gpiod.

On my gateway, the SX1303 reset line connected to GPIO25 of the Pi, but it may be different. For example, if you are using a RAK2003/RAK2247 Pi Hat, you will want to use GPIO17.

Install the gpiod package:

sudo apt-get install gpiod

Create the following script and call it reset_gw.sh. Where 25=1, 25 specifies the GPIO pin number.

#!/bin/sh
gpioset --mode=time --usec=500 pinctrl-bcm2835 25=1
gpioset --mode=time --usec=500 pinctrl-bcm2835 25=0

And make the script an executable:

chmod 755 reset_gw.sh

Now we can reset the SX1301 by running ./reset_gw.sh

Testing

Basic Station can be started as a daemon using the -d switch. However, for testing it is best to execute it in the foreground, so you can more easily see what is going on and watch out for any errors.

To start Basic Station complied for Corecell, run:

~/basicstation/build-corecell-std/bin/station --radio-init=./reset_gw.sh 

It expects the configuration files to be in the current directory. If they are not, you can specify their location using the –home=dir  switch.

If using a device based on the SX1301, you will find the executable in the ~/basicstation/build-rpi-std/bin/station folder.

Registering the Gateway on The Things Network

To register your gateway with TTN, you will need the gateway’s EUI.

The gateway/station’s EUI is made up from the Raspberry Pi’s MAC address and should be shown in the first couple of lines of output when the station starts – for example:

2021-02-15 03:52:20.285 [SYS:INFO] Station Ver : 2.0.5(corecell/std) 2021-02-15 02:15:54
2021-02-15 03:52:20.288 [SYS:INFO] Package Ver : (null)
2021-02-15 03:52:20.288 [SYS:INFO] proto EUI   : 0:b827:eb35:6ab9       (/sys/class/net/eth0/address)
2021-02-15 03:52:20.289 [SYS:INFO] prefix EUI  : ::1    (builtin)
2021-02-15 03:52:20.289 [SYS:INFO] Station EUI : b827:ebff:fe35:6ab9

Log into the console of the cluster you intend to register with and click “Go to gateways

Then click Add Gateway. The following dialog should appear:

Enter your Gateway EUI into the Gateway EUI field, give your gateway a unique Gateway ID and a suitable name.

Now set the correct frequency plan for your country or location:

And click Create gateway. You should now have an enrolled gateway.

But, not so fast. If you try to connect your gateway now, it is likely to fail repeatedly with the connection being closed by the peer.

[TCE:INFO] Connecting to INFOS: wss://eu1.cloud.thethings.network:8887
[TCE:INFO] Infos: b827:ebff:fe35:6ab9 muxs-::0 wss://eu1.cloud.thethings.network:8887/traffic/eui-B827EBFFFE356AB9
[AIO:ERRO] Recv failed: SSL - The peer notified us that the connection is going to be closed

You need to add an API key to authorise your gateway.

Click API keys and then + Add API key (in the top righthand corner).

Give your API key a name and change the rights to grant individual rights to “link as Gateway to a Gateway Server for traffic exchange, i.e. write uplink and read downlink” as per the example below. Then click Create API key to create it.

Now you will be given a one time opportunity to copy the key. Click the copy button (highlighted below by the red box) and …

And paste it into the command below (over the xxxx) to create the tc.key file.

export LNS_KEY="xxxx"
echo "Authorization: Bearer $LNS_KEY" | perl -p -e 's/\r\n|\n|\r/\r\n/g' > tc.key

Now start/restart station and your gateway should successfully register.

Starting at boot

If you want to start Basic Station on boot-up, the easiest option is to modify the /etc/rc.local file and add:

/home/pi/basicstation/build-corecell-std/bin/station --radio-init=/home/pi/TTN/reset_gw.sh --home=/home/pi/TTN --log-file=station.log --daemon

The –log-file switch allows us to override the settings in the station.conf file. This allows for the best of both worlds, you can spawn it and have the output sent to stderr for debugging and when it is spawn at boot, logged to file.

Troubleshooting

[RAL:VERB] Station device: /dev/spidev0.0 (PPS capture enabled)
[RAL:ERRO] Concentrator start failed: lgw_start
[RAL:ERRO] ral_config failed with status 0x08

If your concentrator fails to start and exhibits messages similar to above – relating to the Radio Layer (RAL), then you normally have a Hardware SPI communications problem. Check the following:

  • Have you reset the SX130x? (This is normally the number 1 issue encountered)
  • Is SPI enabled?
  • Have you specified the correct SPI device (/dev/spidev0.0)?
  • Is the wiring correct, does the LoRa concentrator module have power etc.
[HAL:ERRO] [lgw_start:1105] failed to open I2C for temperature sensor on port 0x39
[RAL:ERRO] Concentrator start failed: lgw_start
[RAL:ERRO] ral_config failed with status 0x08

If you receive the above message on CoreCell gateways, check (using raspi-config) that you have I2C enabled. I2C is used to talk to the STTS751 Temperature Sensor on the CoreCell Reference Design.

[HAL:INFO] [lgw_start:1111] no temperature sensor found on port 0x39
[HAL:INFO] [lgw_start:1111] no temperature sensor found on port 0x3B
[HAL:INFO] [lgw_start:1111] no temperature sensor found on port 0x38
[HAL:ERRO] [lgw_start:1120] no temperature sensor found.
[RAL:ERRO] Concentrator start failed: lgw_start
[RAL:ERRO] ral_config failed with status 0x08

If you receive the message above the libloragw HAL can find the I2C port, but is unable to find the STTS751 Temperature Sensor. On some concentrators (RAK Wireless) the temperature sensor has been omitted. There doesn’t appear to be a switch we can pass to disable this.

STTS751 Temperature Sensor – Semtech CoreCell SX1302CSS915GW1 Reference Design

The best option so far has been to patch the source file and rebuild: (assumes you are in the basicstation directory)

wget www.beyondlogic.org/patches/V2.1.0-corecell-disable-stts751.patch 
patch -p1 deps/lgw1302/platform-corecell/libloragw/src/loragw_stts751.c < V2.1.0-corecell-disable-stts751.patch 
make platform=corecell variant=std

Once the patch has been applied and basicstation rebuilt, it should now report a ‘phantom’ temperature sensor on the first I2C address:

[HAL:INFO] [lgw_start:1115] found temperature sensor on port 0x39
[RAL:INFO] Concentrator started (2s469ms) 




14 Comments

  1. Very good instruction! Thank you!

    I have one question, i have an RPi with ic880A an an GPS-Modul!

    With an other implementation, the GPS-Signal was used by the packet-tracer with modyfying the local_config.jason with:

    “gps_tty_path”: “/dev/ttyUSB0”,
    “gps” true,
    “fake_gps”: false,

    Is it possible to implement GPS in the station.conf?

    Greetings

    E_T

    • Yes, the example above with “pps”: true is all you need (and the GPS PPS routed into the concentrator).

      The Basic Station documentation (core features) provide a good summary:

      No Dependency on Local Time Keeping: A Station obtains time synchronization from the LNS. There is no need for a local UTC-based clock. For Class B, a Station only requires a PPS routed to the concentrator. Synchronization of the PPS pulse with the global GPS time then is negotiated with the LNS. No NMEA-based interface, or any other kind of interface to a GPS module, is required. If present, however, it is used to augment health information.

    • Check the terminating characters of tc.key – the file should end in \r\n (0x0D, 0x0A). I find if you use an editor like nano, it will be terminated with only 0x0A which will cause an error, “tc contains malformed auth token – expecting: {header: value\r\n}*”

  2. A very good instruction, after a few typos it worked, at least…
    The hardware (your hat) is not there yet, missing a few components.
    Get without the hardware a lot of responses on the pi and server console. Is this normal?
    Thanks for your work and regards…

    • Wijnand – the hat has the UART of the GPS connected to the UART of the Raspberry Pi. By default the Pi has the console accessible on the UART, hence the GPS responds to this and sends responses back. What you want to do is turn off the login shell – execute raspi-config, and choose “3 Interface Options”, then “P6 Serial Port”. You will be asked “Would you like a login shell to be accessible over serial?”, choose “No”.

  3. hi, I am hanging at the “Testing” point:
    ttn@ttn:~/TTN $ ~/basicstation/build-rpi-std/bin/station –radio-init=./reset_gw.sh
    2021-11-12 14:07:32.170 [SYS:WARN] Station in NO-CUPS mode
    2021-11-12 14:07:32.864 [AIO:ERRO] Recv failed: SSL – The peer notified us that the connection is going to be closed
    2021-11-12 14:07:33.253 [AIO:ERRO] [3] WS upgrade failed with HTTP status code: 401
    2021-11-12 14:07:43.704 [AIO:ERRO] Recv failed: SSL – The peer notified us that the connection is going to be closed
    2021-11-12 14:07:44.065 [AIO:ERRO] [3] WS upgrade failed with HTTP status code: 401

    • Sounds like you are missing the GCC Gnu C Compiler.

      Ignore the above. I gave 64 bit a go myself. Rpi 64 bit appears to report the architecture as aarch64-linux-gnu and the current build tools don’t have any support for it.

      The quickest way to resolve this is to edit the setup.gmk file and change the line
      ARCH.rpi = arm-linux-gnueabihf
      to
      ARCH.rpi = aarch64-linux-gnu

  4. Good Morning,

    I have everything working and running from the TTN folder using the ~/basicstation/build-rpi-std/bin/station command (I changed the station.conf to include the bash script). It works just fine, but when I try to run it as a Daemon with the -d or the –daemon it errors out with Failed to open log file /var/tmp/station.log: Permission denied. I know I don’t need sudo to run the file and if I run the station with Sudo it gives me more errors. I have no clue what I’m doing wrong here, everything looks ok except running as a daemon.

    Thank you for the help!
    Mike

  5. Hi, I’m developing a LoRa weather station system and a few weeks ago noticed what i believe to be your gateway was only a few kilometres away from me (I’m in Old Noarlunga). Today I received my LoRa modules and was hoping to use the gateway to test them but I can’t see the gateway on the map anymore. Is it still online or is it not being run anymore?

    Nikolai

  6. I have just gone through this process with an RK833 HAT on a 3B.

    I get a certificate error when starting up (see below) and wondered what the correct format of the key in the tc.key file is – do I need the quotes around the key or not?

    apologies for noob level question…

    2023-11-13 09:07:57.986 [any:ERRO] Parsing trust certificate: X509 – The CRT/CRL/CSR format is invalid, e.g. different type expected
    2023-11-13 09:07:57.986 [AIO:ERRO] tc trust certificates rejected by MBedTLS
    2023-11-13 09:07:57.987 [TCE:INFO] INFOS reconnect backoff 0s (retry 0)
    2023-11-13 09:07:57.987 [any:ERRO] Parsing trust certificate: X509 – The CRT/CRL/CSR format is invalid, e.g. different type expected
    2023-11-13 09:07:57.987 [AIO:ERRO] tc trust certificates rejected by MBedTLS
    2023-11-13 09:07:57.987 [TCE:INFO] INFOS reconnect backoff 10s (retry 1)
    2023-11-13 09:08:07.988 [any:ERRO] Parsing trust certificate: X509 – The CRT/CRL/CSR format is invalid, e.g. different type expected
    2023-11-13 09:08:07.988 [AIO:ERRO] tc trust certificates rejected by MBedTLS
    2023-11-13 09:08:07.988 [TCE:INFO] INFOS reconnect backoff 20s (retry 2)
    2023-11-13 09:08:27.990 [any:ERRO] Parsing trust certificate: X509 – The CRT/CRL/CSR format is invalid, e.g. different type expected
    2023-11-13 09:08:27.990 [AIO:ERRO] tc trust certificates rejected by MBedTLS
    2023-11-13 09:08:27.990 [TCE:INFO] INFOS reconnect backoff 30s (retry 3)
    2023-11-13 09:08:57.991 [any:ERRO] Parsing trust certificate: X509 – The CRT/CRL/CSR format is invalid, e.g. different type expected
    2023-11-13 09:08:57.992 [AIO:ERRO] tc trust certificates rejected by MBedTLS
    2023-11-13 09:08:57.992 [TCE:INFO] INFOS reconnect backoff 40s (retry 4)
    2023-11-13 09:09:37.993 [any:ERRO] Parsing trust certificate: X509 – The CRT/CRL/CSR format is invalid, e.g. different type expected
    2023-11-13 09:09:37.993 [AIO:ERRO] tc trust certificates rejected by MBedTLS
    2023-11-13 09:09:37.993 [TCE:INFO] INFOS reconnect backoff 50s (retry 5)

Leave a Reply to Craig Peacock Cancel reply

Your email address will not be published.


*