Skip to main content

Advanced Configuration

Session Key Filter (SKF)

A Session Key Filter (SKF) is a device address (devAddr) and network session key (NwkSKey) pair stored on a route. When a Hotspot reports an uplink on a devAddr that has one or more SKFs, the Helium Packet Router verifies the packet's Message Integrity Code (MIC) against the stored keys before buying it. Packets that fail the check are dropped before purchase, so they never reach the LNS and incur no Data Credit cost.

SKFs ensure that a route purchases and forwards only the payloads its operator intends to receive. Device addresses are not globally unique: every LoRaWAN network assigns devAddrs from the same 32-bit space, so a device on an unrelated network can transmit on a devAddr that falls within a Helium route. Without SKFs, the Packet Router cannot verify these packets, and the OUI pays for payloads that may not correlate to any device the operator intends to receive data from.

SKF Behavior

Two settings determine how the Packet Router treats an uplink: whether the packet's devAddr has any SKFs on the route, and the route's ignore_empty_skf flag. SKFs are added per devAddr; ignore_empty_skf is a single flag set for the entire route.

devAddr on the routeignore_empty_skf: falseignore_empty_skf: true
Has one or more SKFsDelivered only if the MIC matches a stored keySame; the flag has no effect when SKFs exist
Has no SKFsDelivered without any MIC checkDropped

A devAddr can hold multiple SKFs, and the Packet Router checks the MIC against each of them. This supports LNS platforms such as ChirpStack that assign the same devAddr to multiple devices.

Join requests are not filtered by SKFs. They are matched by DevEUI/AppEUI pair and carry no devAddr, which is why a device with a missing or stale SKF can join successfully while its uplinks are dropped.

Keep SKFs up to date

OTAA devices derive a new NwkSKey on every join. Once a device rejoins, its existing SKF no longer matches and its uplinks are dropped, which is the symptom described in Device Able to Join but Not Uplink. In practice, SKFs are kept in sync programmatically by the LNS, typically using one of the tools in Automated EUI and SKF Route Updates.

Any SKF updater implementation should remove old session keys, not just add new ones. Stale SKFs accumulate on the route, and the Packet Router keeps buying uplinks that match an old key, such as from a device that was deleted from the LNS but is still transmitting.

Managing SKFs

The commands below use the Config Service CLI with an owner or delegate keypair configured, as described in Config Service Interaction. As with other route commands, omitting --commit performs a dry run that prints the change without applying it.

List the SKFs on a route:

helium-config-service-cli route skfs list --route-id <route-id>

Add an SKF. The devAddr is eight hex characters with no 0x prefix, and the session key is the device's hex-encoded NwkSKey (in ChirpStack, found in the device's Activation tab):

helium-config-service-cli route skfs add --route-id <route-id> --devaddr <devaddr> --session-key <nwkskey> --commit

An SKF can also carry a per-device max copies value via --max-copies. When the flag is omitted, the SKF is created with max_copies set to 1. A value of 0 falls back to the route-level setting. See Max Copies for how the SKF-level value overrides the route-level setting.

Remove an SKF:

helium-config-service-cli route skfs remove --route-id <route-id> --devaddr <devaddr> --session-key <nwkskey> --commit

For bulk changes, route skfs update --route-id <route-id> --update-file <file> --commit applies a JSON file of add and remove actions, limited to 100 updates per request.

Enforcing SKFs

By default (ignore_empty_skf: false), a devAddr with no SKFs accepts all traffic unchecked. Enabling the route's ignore_empty_skf flag closes this gap: the Packet Router drops all traffic on any devAddr that has no SKFs, so only devices with registered session keys get through.

Check the current value by looking for the ignore_empty_skf field in the output of:

helium-config-service-cli route get --route-id <route-id>

Enable enforcement:

helium-config-service-cli route update ignore-empty-skf --route-id <route-id> --ignore --commit

To disable it, run the same command without --ignore. The flag sets the value by its presence; there is no --ignore true or --ignore false form.

Automated EUI and SKF Route Updates

As the ecosystem of LNS operators grows, an increasing number of developers have open-sourced their tooling for running a Helium-enabled LNS. These tools enable functionality such as EUI and SKF automation to per-tenant Data Credit accounting.

A selection of the tools are outlined below. All of them run alongside a ChirpStack deployment.

ToolCapabilitiesDocumentation
Helium Route UpdaterAutomates adding and removing EUIs, and enables and maintains SKFs for your devicesChirpStack Docker Compose setup
Disk91 Helium ChirpstackEUI management and per-tenant Data Credit accountingRepository readme
Chirpstack-hpr by BonesEUI and SKF managementGetting started guide

Max Copies

Given that LoRaWAN devices openly broadcast uplinks, it's common for multiple Hotspots to capture the same device uplink within the Helium Network. LNS operators can customize the number of duplicate uplinks they wish to receive and pay for by setting a max copies amount, also known as "multibuy." Configuring the max_copies setting offers several significant advantages:

  • Better downlink performance: If the max copies setting is 10, the LNS will receive up to 10 copies of the same uplink, and the downlink will be sent by the Hotspot with the best RSSI of those 10, per the selection mechanism of the LNS.
    Helium reports Hotspots' responses in chronological order, which can be challenging for scheduling downlinks because the first Hotspot to report may not necessarily be the closest or have the strongest RSSI/SNR attributes. This is important for downlink scenarios such as Class-C devices, ADR, confirmed uplinks, or standard downlinks on Class-A devices. Leveraging multibuy ensures that there is a strong Hotspot available to deliver the downlink message.
  • Geolocation: It is possible to leverage Hotspot metadata to estimate the sensor location without GPS or Wi-Fi.
  • Multilateration: For devices that do not have internal location-solving abilities (GPS), the metadata of the packet report and Helium Network can be leveraged to solve for a device location.

The Helium Network charges for each response for a given payload. Each Hotspot that reports a payload from a given device is eligible to be rewarded. The LNS operator can choose how many reports they would like to buy. For instance, for a multibuy value of 10 on a device that only receives 8 reports, the OUI would be charged 8 DC ($0.00008 USD). This assumes the payload was less than 24 bytes.

There are two levels of granularity for the max copies setting:

  1. Route level: Applies to all devices registered under the route.
  2. SKF level: Applies only to the device with the specified network session key (NwkSKey). This configuration overrides the route-level max copies setting.

As an example, if the LNS operator has a route that contains devices A and B, and configures a route-level max copies setting of 2 and an SKF-level max copies setting of 5 for device B, then device A will inherit the route-level max copies setting of 2, and device B will use its SKF-level max copies setting of 5.

Improve Join Performance

Since Over-the-Air Activation (OTAA) devices require a network joining process before they start transmitting valuable sensor data, it is beneficial to ensure the network joining process is as effective as possible.

Join performance can be improved by increasing the number of copies of the same join request the LNS receives, because then the join accept will be delivered by the Hotspot with the best RSSI, increasing the possibility of a successful delivery.

Join requests are free on the Helium Network. LNS operators can leverage max copies to improve the join performance without additional cost overhead.

As an example, the LNS operator can define a route-level max copies setting of 20 and an SKF-level max copies setting of 1 for all devices. This will have the effect of allowing up to 20 copies of join requests and 1 copy of each uplink. This way, the devices will have a much better chance to join, without consuming extra DC from the uplinks once joined.

Config Service Interaction

The Config Service can be used to manage an OUI and devAddr. There are two ways to interact with the Config Service:

  1. Using the Command-Line Interface (CLI).
  2. Alternatively, you can write scripts to interact with the Config Service directly through gRPC APIs for a more programmatic approach.

Hotspot Location Data

Hotspot location data can be requested from the Config Service using either the CLI or gRPC APIs.

EUI Pair Wildcard

In some applications, deployers may have many DevEUIs all associated under the same AppEUI, and it might be inconvenient to provision all those EUI pairs individually. If the LNS operator would like to receive Join Requests for all devices under a certain AppEUI, simply input 0000000000000000 for the DevEUI when adding an EUI pair.

Add and Remove Delegate Keys

Note that only the owner key can perform the actions below. OUI owners can add delegate keys by running:

helium-config-service-cli org update delegate-add --pubkey <public key of the delegate key pair you are trying to add> --keypair <relative path of your **owner** keypair path> --commit

OUI owners can remove delegate keys by running:

helium-config-service-cli org update delegate-remove --pubkey <public key of the delegate key pair you are trying to remove> --keypair <relative path of your **owner** keypair path> --commit

Set up NGINX for ChirpStack Docker

NGINX can be used for web serving, reverse proxying, caching, load balancing, SSL, and more. To set it up on ChirpStack Docker, add the following section to docker-compose.yml:

nginx:
image: nginx:latest
container_name: chirpstack_nginx
restart: always
volumes:
- './logs/nginx:/var/log/nginx'
- './configuration/nginx.conf:/etc/nginx/conf.d/default.conf'
ports:
- 80:80
- 443:443
depends_on:
- chirpstack
networks:
- iot-network

and then create a new file called nginx.conf under the configuration directory, with the following content:

upstream chirpstack_upstream {
server chirpstack:8080;
}

server {
listen 80;
server_name _;

location ^~ /api {
grpc_pass grpc://chirpstack_upstream;
}

location / {
proxy_pass http://chirpstack_upstream;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
}
}