Gateway connection to TTN

This page explains how packet forwarders exchange data with TTN. You don’t need to understand all of this to make a gateway work, but if you’re curious of how packet forwarders work, this can help you!

The Things Network Router

Packet forwarders connect to The Things Network through the router component. This component is tasked with handling gateway data and status, and to transfer data to the rest of the network.

TTN Router

Protocols

Messages can be transmitted from a gateway to TTN through two protocols: the legacy Semtech UDP protocol, and our new Gateway Connector protocol.

Semtech UDP protocol

The Semtech UDP protocol is, historically, the first gateway protocol that was developed for LoRaWAN. It was built by Semtech, who still maintain it.

With this protocol, uplinks, statuses and downlinks are exchanged in a pseudo-JSON format, through UDP, between the gateway and the network server. Because of the simplicity of the messages and of the protocol, it is easy to reproduce this protocol, for testing purposes or for bootstrapping.

Because this protocol was implemented in the first packet forwarder publicly available, most gateways include a basic packet forwarder running this protocol.

Example

{
  "rxpk": {
    "tmst":20900514000,
    "chan":2,
    "rfch":0,
    "freq":866.349812,
    "stat":1,
    "modu":"LORA",
    "datr":"SF7BW125",
    "codr":"4/6",
    "rssi":-35,
    "lsnr":5,
    "size":23,
    "data":"AMy7qgAAAAAATYMmmnj6AADl6YP1Jrw"
  }
}

Excerpt of a Semtech UDP message, with an uplink message - for example, data holds the payload, tmst the gateway time of reception, rssi the RSSI value…

Drawbacks of the UDP protocol

However, this protocol lacks features for production-ready networks:

Gateway connector protocol

Because of the reasons above, we’ve developed a new protocol, solving these issues: the gateway connector protocol. With this protocol:

With the gateway connector protocol, messages can be exchanged through two network protocols:

Using the gateway connector protocol

Using the gateway connector protocol to send messages happens in two steps:

Example using gRPC

In this example built in the Go language, we’ll show two functions:

import (
  "github.com/TheThingsNetwork/go-account-lib/account"
  "github.com/TheThingsNetwork/api/discovery"
  "github.com/TheThingsNetwork/api/gateway"
  "github.com/TheThingsNetwork/api/protocol"
  "github.com/TheThingsNetwork/api/protocol/lorawan"
  "github.com/TheThingsNetwork/api/router"
)

const (
  gatewayID = "INSERT_GATEWAY_ID"
  gatewayKey = "INSERT_GATEWAY_KEY"

  accountServer = "https://account.thethingsnetwork.org"
  discoveryServer = "discovery.thethings.network:1900"
  routerID = "ttn-router-eu"
)

func createUplinkMessage(payload []byte) *router.UplinkMessage {
  // Creating a dummy uplink message, using the protocol buffer-generated types
  return &router.UplinkMessage{
    GatewayMetadata: &gateway.RxMetadata{
      Rssi: -35,
      Snr:  5,
    },
    Payload: payload,
    ProtocolMetadata: &protocol.RxMetadata{
      Protocol: &protocol.RxMetadata_Lorawan{
        Lorawan: &lorawan.Metadata{
          CodingRate: "4/5",
          DataRate:   "SF7BW125",
          Modulation: lorawan.Modulation_LORA,
        },
      },
    },
  }
}

func connectAndSendUplink(uplink *router.UplinkMessage) error {
  // Connecting to the TTN account server to fetch a token
  gwAccount := account.NewWithKey(accountServer, gatewayKey)
  gw, err := gwAccount.FindGateway(gatewayID)
  if err != nil {
    return err
  }
  token := gw.Token.AccessToken

  // Connecting to the TTN discovery server to get a connection to the router
  discoveryClient, err := 
discovery.NewClient(discoveryServer, 
&discovery.Announcement{Id: gatewayID}, func() 
string { return "" })
  if err != nil {
    return err
  }

  // Connecting to the router
  routerAccess, err := discoveryClient.Get("router", routerID)
  if err != nil {
    return err
  }

  routerConn := routerAccess.Dial()
  routerClient := router.NewRouterClientForGateway(router.NewRouterClient(c.routerConn), gatewayID, 
token)
  uplinkStream := router.NewMonitoredUplinkStream(routerClient)

  // Sending the uplink
  if err := uplinkStream.Send(uplink); err 
!= nil {
    return err
  }
  // Uplink sent successfully!
  return nil
}