How to make /SX1302_LoRaWAN_Gateway_HAT working with ChirpStack

Viewed 5

Subject: Gateway "Never Seen" in ChirpStack v4 despite MQTT messages being received
Setup Description:

Hardware: Raspberry Pi 5.

OS: Debian Bookworm.

Gateway: Waveshare SX1302 LoRaWAN Gateway HAT.

Architecture: SX1302 HAL (Packet Forwarder) -> ChirpStack MQTT Forwarder (installed as service) -> Dockerized ChirpStack v4 Stack.

The Problem: My Mosquitto broker is successfully receiving messages from the gateway in the expected topics (eu868/gateway/0016c001f1054d5e/...). However, the ChirpStack Web UI still shows the gateway as "Never Seen".

Current Configurations:

  1. ChirpStack MQTT Forwarder (chirpstack-mqtt-forwarder.toml)
# Logging settings.
[logging]
  level="info"
  log_to_syslog=false

# MQTT settings.
[mqtt]
  # Prefixo da região (Obrigatório para o ChirpStack v4)
  topic_prefix="eu868"

  # JSON deve estar a FALSE (ChirpStack v4 usa binário)
  json=false

  # --- LINHA CRÍTICA ADICIONADA ---
  # Define explicitamente que a linguagem é Protobuf
  marshaler="protobuf"
  # --------------------------------

  # Endereço do Mosquitto (como está no Docker na mesma máquina, localhost serve)
  server="tcp://127.0.0.1:1883"

  # Deixar utilizador e password vazios se o Mosquitto permitir anónimos
  username=""
  password=""

  qos=0
  clean_session=false
  client_id=""
  keep_alive_interval="30s"
  ca_cert=""
  tls_cert=""
  tls_key=""
  reconnect_interval="30s"

# Backend configuration.
# Aqui definimos que vamos receber dados do Packet Forwarder "antigo" (UDP)
[backend]
  enabled="semtech_udp"

  [backend.filters]
    forward_crc_ok=true
    forward_crc_invalid=false
    forward_crc_missing=false
    dev_addr_prefixes=[]
    join_eui_prefixes=[]

  
  # Configuração da "Ponte" UDP
  [backend.semtech_udp]
    # Ouve na porta 1700 (onde o lora_pkt_fwd envia os dados)
    bind="0.0.0.0:1700"
    time_fallback_enabled=false

# Gateway metadata configuration.
[metadata]
  [metadata.static]
  [metadata.commands]

# Executable commands.
[commands]

# Callback commands.
[callbacks]
  on_mqtt_connected=[]
  on_mqtt_connection_error=[]
  1. Main ChirpStack Server (chirpstack.toml)
  [logging]
level = "info"

[postgresql]
dsn = "postgres://chirpstack:chirpstack@postgres/chirpstack?sslmode=disable"

[redis]
url = "redis://redis:6379"

[network]
net_id = "000000"

[api]
bind = "0.0.0.0:8080"
secret = "changeme"

[integration.mqtt]
server = "tcp://mosquitto:1883"
json = true

[[regions]]
name = "eu868"
common_name = "EU868"
config_file = "/etc/chirpstack/region_eu868.toml"

3. Region Configuration (region_eu868.toml)

# This file contains an example EU868 configuration.
[[regions]]

  # ID is an user-defined identifier for this region.
  id = "eu868"

  # Description is a short description for this region.
  description = "EU868"

  # Common-name refers to the common-name of this region as defined by
  # the LoRa Alliance.
  common_name = "EU868"

  # User-defined region information.
  #
  # This information will be displayed on top of the region page in then
  # ChirpStack web-interface. For example, it can contain information about
  # how users should connect their gateways when using this region (e.g. MQTT
  # end-point, MQTT topic prefix, TLS configuration etc). Markdown syntax can
  # be used for formatting.
  user_info = ""


  # Gateway configuration.
  [regions.gateway]

    # Force gateways as private.
    #
    # If enabled, gateways can only be used by devices under the same tenant.
    force_gws_private = false


    # Gateway backend configuration.
    [regions.gateway.backend]

      # The enabled backend type.
      enabled = "mqtt"

      # MQTT configuration.
      [regions.gateway.backend.mqtt]

        # Topic prefix.
        #
        # The topic prefix can be used to define the region of the gateway.
        # Note, there is no need to add a trailing '/' to the prefix. The trailing
        # '/' is automatically added to the prefix if it is configured.
        topic_prefix = "eu868"

        # Shared subscription name.
        #
        # In case there are multiple ChirpStack instances sharing the same
        # subscription name, then the MQTT broker will deliver a gateway event
        # only to one subscriber. In case you have a production and
        # test-environment connected to the same MQTT broker, make sure that
        # each environment has its own subscription name, for example:
        # chirpstack_prod and chirpstack_tst.
        share_name = "chirpstack"

        # MQTT server (e.g. scheme://host:port where scheme is tcp, ssl or ws)
        server = "tcp://mosquitto:1883"

        # Connect with the given username (optional)
        username = ""

        # Connect with the given password (optional)
        password = ""

        # Quality of service level
        #
        # 0: at most once
        # 1: at least once
        # 2: exactly once
        #
        # Note: an increase of this value will decrease the performance.
        # For more information: https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels
        qos = 0

        # Clean session
        #
        # Set the "clean session" flag in the connect message when this client
        # connects to an MQTT broker. By setting this flag you are indicating
        # that no messages saved by the broker for this client should be delivered.
        clean_session = false

        # Client ID
        #
        # Set the client id to be used by this client when connecting to the MQTT
        # broker. A client id must be no longer than 23 characters. If left blank,
        # a random id will be generated by ChirpStack.
        client_id = ""

        # Keep alive interval.
        #
        # This defines the maximum time that that should pass without communication
        # between the client and server.
        keep_alive_interval = "30s"

        # CA certificate file (optional)
        #
        # Use this when setting up a secure connection (when server uses ssl://...)
        # but the certificate used by the server is not trusted by any CA certificate
        # on the server (e.g. when self generated).
        ca_cert = ""

        # TLS certificate file (optional)
        tls_cert = ""

        # TLS key file (optional)
        tls_key = ""


    # Gateway channel configuration.
    #
    # Note: this configuration is only used in case the gateway is using the
    # ChirpStack Concentratord daemon. In any other case, this configuration
    # is ignored.
    [[regions.gateway.channels]]
      frequency = 868100000
      bandwidth = 125000
      modulation = "LORA"
      spreading_factors = [7, 8, 9, 10, 11, 12]

    [[regions.gateway.channels]]
      frequency = 868300000
      bandwidth = 125000
      modulation = "LORA"
      spreading_factors = [7, 8, 9, 10, 11, 12]

    [[regions.gateway.channels]]
      frequency = 868500000
      bandwidth = 125000
      modulation = "LORA"
      spreading_factors = [7, 8, 9, 10, 11, 12]

    [[regions.gateway.channels]]
      frequency = 867100000
      bandwidth = 125000
      modulation = "LORA"
      spreading_factors = [7, 8, 9, 10, 11, 12]

    [[regions.gateway.channels]]
      frequency = 867300000
      bandwidth = 125000
      modulation = "LORA"
      spreading_factors = [7, 8, 9, 10, 11, 12]

    [[regions.gateway.channels]]
      frequency = 867500000
      bandwidth = 125000
      modulation = "LORA"
      spreading_factors = [7, 8, 9, 10, 11, 12]

    [[regions.gateway.channels]]
      frequency = 867700000
      bandwidth = 125000
      modulation = "LORA"
      spreading_factors = [7, 8, 9, 10, 11, 12]

    [[regions.gateway.channels]]
      frequency = 867900000
      bandwidth = 125000
      modulation = "LORA"
      spreading_factors = [7, 8, 9, 10, 11, 12]

    [[regions.gateway.channels]]
      frequency = 868300000
      bandwidth = 250000
      modulation = "LORA"
      spreading_factors = [7]

    [[regions.gateway.channels]]
      frequency = 868800000
      bandwidth = 125000
      modulation = "FSK"
      datarate = 50000


  # Region specific network configuration.
  [regions.network]

    # Installation margin (dB) used by the ADR engine.
    #
    # A higher number means that the network-server will keep more margin,
    # resulting in a lower data-rate but decreasing the chance that the
    # device gets disconnected because it is unable to reach one of the
    # surrounded gateways.
    installation_margin = 10

    # RX window (Class-A).
    #
    # Set this to:
    # 0: RX1 / RX2
    # 1: RX1 only
    # 2: RX2 only
    rx_window = 0

    # RX1 delay (1 - 15 seconds).
    rx1_delay = 1

    # RX1 data-rate offset
    rx1_dr_offset = 0

    # RX2 data-rate
    rx2_dr = 0

    # RX2 frequency (Hz)
    rx2_frequency = 869525000

    # Prefer RX2 on RX1 data-rate less than.
    #
    # Prefer RX2 over RX1 based on the RX1 data-rate. When the RX1 data-rate
    # is smaller than the configured value, then the Network Server will
    # first try to schedule the downlink for RX2, failing that (e.g. the gateway
    # has already a payload scheduled at the RX2 timing) it will try RX1.
    rx2_prefer_on_rx1_dr_lt = 0

    # Prefer RX2 on link budget.
    #
    # When the link-budget is better for RX2 than for RX1, the Network Server will first
    # try to schedule the downlink in RX2, failing that it will try RX1.
    rx2_prefer_on_link_budget = false

    # Downlink TX Power (in dBm EIRP)
    #
    # When set to -1, the downlink TX Power from the configured band will
    # be used.
    #
    # Please consult the LoRaWAN Regional Parameters and local regulations
    # for valid and legal options. Note that the configured TX Power must be
    # supported by your gateway(s).
    downlink_tx_power = -1

    # ADR is disabled.
    adr_disabled = false

    # Minimum data-rate.
    min_dr = 0

    # Maximum data-rate.
    max_dr = 5


    # Rejoin-request configuration (LoRaWAN 1.1)
    [regions.network.rejoin_request]

      # Request devices to periodically send rejoin-requests.
      enabled = false

      # The device must send a rejoin-request type 0 at least every 2^(max_count_n + 4)
      # uplink messages. Valid values are 0 to 15.
      max_count_n = 0

      # The device must send a rejoin-request type 0 at least every 2^(max_time_n + 10)
      # seconds. Valid values are 0 to 15.
      #
      # 0  = roughly 17 minutes
      # 15 = about 1 year
      max_time_n = 0


    # Class-B configuration.
    [regions.network.class_b]

      # Ping-slot data-rate.
      ping_slot_dr = 3

      # Ping-slot frequency (Hz)
      #
      # set this to 0 to use the default frequency plan for the configured region
      # (which could be frequency hopping).
      ping_slot_frequency = 0


    # Below is the common set of extra channels. Please make sure that these
    # channels are also supported by the gateways.
    [[regions.network.extra_channels]]
      frequency = 867100000
      min_dr = 0
      max_dr = 5

    [[regions.network.extra_channels]]
      frequency = 867300000
      min_dr = 0
      max_dr = 5

    [[regions.network.extra_channels]]
      frequency = 867500000
      min_dr = 0
      max_dr = 5

    [[regions.network.extra_channels]]
      frequency = 867700000
      min_dr = 0
      max_dr = 5

    [[regions.network.extra_channels]]
      frequency = 867900000
      min_dr = 0
      max_dr = 5
  1. Mosquitto config
   persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
listener 1883
allow_anonymous true

5 - docker compose file - docker-compose.yml

version: "3.9"

services:
  chirpstack:
    image: chirpstack/chirpstack:4
    container_name: chirpstack
    command: -c /etc/chirpstack
    ports:
      - "8080:8080"
    restart: unless-stopped
    volumes:
      - ./config/chirpstack:/etc/chirpstack
    depends_on:
      - postgres
      - redis
      - mosquitto
    environment:
      - MQTT_BROKER_HOST=mosquitto
      - REDIS_HOST=redis
      - POSTGRESQL_HOST=postgres

  postgres:
    image: postgres:14-alpine
    container_name: chirpstack-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: chirpstack
      POSTGRES_USER: chirpstack
      POSTGRES_PASSWORD: chirpstack
    volumes:
      - agrosas_postgres_data:/var/lib/postgresql/data
      - ./config/postgresql/initdb:/docker-entrypoint-initdb.d
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U chirpstack"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: chirpstack-redis
    restart: unless-stopped
    volumes:
      - agrosas_redis_data:/data

  mosquitto:
    image: eclipse-mosquitto:2
    container_name: chirpstack-mosquitto
    restart: unless-stopped
    ports:
      - "1883:1883"
    volumes:
      - ./config/mosquitto:/mosquitto/config
      - agrosas_mosquitto_data:/mosquitto/data
      - agrosas_mosquitto_log:/mosquitto/log

volumes:
  agrosas_postgres_data:
  agrosas_redis_data:
  agrosas_mosquitto_data:
  agrosas_mosquitto_log:

Troubleshooting performed:

Verified that mosquitto_sub shows uplink traffic on eu868/gateway/0016c001f1054d5e/event/stats.

Confirmed that Gateway ID in the Web UI matches the MQTT topic exactly.

ChirpStack logs show Setting up gateway backends for the different regions but no errors regarding MQTT connection.

waveshare/sx1302_hal_rpi5-master/packet_forwarder
/test_config.json

{
    "SX130x_conf": {
        "com_type": "SPI",
        "com_path": "/dev/spidev0.0",
        "lorawan_public": true,
        "clksrc": 0,
        "antenna_gain": 0, /* antenna gain, in dBi */
        "full_duplex": false,
        "fine_timestamp": {
            "enable": false,
            "mode": "all_sf" /* high_capacity or all_sf */
        },
        "sx1261_conf": {
            "spi_path": "/dev/spidev0.1",
            "rssi_offset": 0, /* dB */
            "spectral_scan": {
                "enable": false,
                "freq_start": 867100000,
                "nb_chan": 8,
                "nb_scan": 2000,
                "pace_s": 10
            },
            "lbt": {
                "enable": false,
                "rssi_target": -70, /* dBm */
                "channels":[ /* 16 channels maximum */
                    { "freq_hz": 867100000, "bandwidth": 125000, "scan_time_us": 128,  "transmit_time_ms": 400 },
                    { "freq_hz": 867300000, "bandwidth": 125000, "scan_time_us": 128,  "transmit_time_ms": 400 },
                    { "freq_hz": 867500000, "bandwidth": 125000, "scan_time_us": 128,  "transmit_time_ms": 400 },
                    { "freq_hz": 867700000, "bandwidth": 125000, "scan_time_us": 128,  "transmit_time_ms": 400 },
                    { "freq_hz": 867900000, "bandwidth": 125000, "scan_time_us": 128,  "transmit_time_ms": 400 },
                    { "freq_hz": 868100000, "bandwidth": 125000, "scan_time_us": 128,  "transmit_time_ms": 400 },
                    { "freq_hz": 868300000, "bandwidth": 125000, "scan_time_us": 128,  "transmit_time_ms": 400 },
                    { "freq_hz": 868500000, "bandwidth": 125000, "scan_time_us": 128,  "transmit_time_ms": 400 },
                    { "freq_hz": 869525000, "bandwidth": 125000, "scan_time_us": 5000, "transmit_time_ms": 4000 },
                    { "freq_hz": 868300000, "bandwidth": 250000, "scan_time_us": 128,  "transmit_time_ms": 400 }
                ]
            }
        },
        "radio_0": {
            "enable": true,
            "type": "SX1250",
            "freq": 867500000,
            "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,
            "tx_freq_min": 863000000,
            "tx_freq_max": 870000000,
            "tx_gain_lut":[
                {"rf_power": 12, "pa_gain": 0, "pwr_idx": 15},
                {"rf_power": 13, "pa_gain": 0, "pwr_idx": 16},
                {"rf_power": 14, "pa_gain": 0, "pwr_idx": 17},
                {"rf_power": 15, "pa_gain": 0, "pwr_idx": 19},
                {"rf_power": 16, "pa_gain": 0, "pwr_idx": 20},
                {"rf_power": 17, "pa_gain": 0, "pwr_idx": 22},
                {"rf_power": 18, "pa_gain": 1, "pwr_idx": 1},
                {"rf_power": 19, "pa_gain": 1, "pwr_idx": 2},
                {"rf_power": 20, "pa_gain": 1, "pwr_idx": 3},
                {"rf_power": 21, "pa_gain": 1, "pwr_idx": 4},
                {"rf_power": 22, "pa_gain": 1, "pwr_idx": 5},
                {"rf_power": 23, "pa_gain": 1, "pwr_idx": 6},
                {"rf_power": 24, "pa_gain": 1, "pwr_idx": 7},
                {"rf_power": 25, "pa_gain": 1, "pwr_idx": 9},
                {"rf_power": 26, "pa_gain": 1, "pwr_idx": 11},
                {"rf_power": 27, "pa_gain": 1, "pwr_idx": 14}
            ]
        },
        "radio_1": {
            "enable": true,
            "type": "SX1250",
            "freq": 868500000,
            "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_All": {"spreading_factor_enable": [ 5, 6, 7, 8, 9, 10, 11, 12 ]},
        "chan_multiSF_0": {"enable": true, "radio": 1, "if": -400000},
        "chan_multiSF_1": {"enable": true, "radio": 1, "if": -200000},
        "chan_multiSF_2": {"enable": true, "radio": 1, "if":  0},
        "chan_multiSF_3": {"enable": true, "radio": 0, "if": -400000},
        "chan_multiSF_4": {"enable": true, "radio": 0, "if": -200000},
        "chan_multiSF_5": {"enable": true, "radio": 0, "if":  0},
        "chan_multiSF_6": {"enable": true, "radio": 0, "if":  200000},
        "chan_multiSF_7": {"enable": true, "radio": 0, "if":  400000},
        "chan_Lora_std":  {"enable": true, "radio": 1, "if": -200000, "bandwidth": 250000, "spread_factor": 7,
                           "implicit_hdr": false, "implicit_payload_length": 17, "implicit_crc_en": false, "implicit_coderate": 1},
        "chan_FSK":       {"enable": true, "radio": 1, "if":  300000, "bandwidth": 125000, "datarate": 50000}
    },

    "gateway_conf": {
        "gateway_ID": "0016c001f1054d5e",
        /* change with default server address/ports */
        "server_address": "127.0.0.1",
        "serv_port_up": 1700,
        "serv_port_down": 1700,
        /* adjust the following parameters for your network */
        "keepalive_interval": 10,
        "stat_interval": 30,
        "push_timeout_ms": 100,
        /* forward only valid packets */
        "forward_crc_valid": true,
        "forward_crc_error": false,
        "forward_crc_disabled": false,
        /* GPS configuration */
        "gps_tty_path": "/dev/ttyS0",
        /* GPS reference coordinates */
        "ref_latitude": 0.0,
        "ref_longitude": 0.0,
        "ref_altitude": 0,
        /* Beaconing parameters */
        "beacon_period": 0,
        "beacon_freq_hz": 869525000,
        "beacon_datarate": 9,
        "beacon_bw_hz": 125000,
        "beacon_power": 14,
        "beacon_infodesc": 0,
    "servers": [
    {
        "gateway_ID": "0016C001F1054D5e",
        "server_address": "127.0.0.1",
        "serv_port_up": 1700,
        "serv_port_down": 1700,
        "serv_enabled": true
    }
    ]

    },

    "debug_conf": {
        "ref_payload":[
            {"id": "0xCAFE1234"},
            {"id": "0xCAFE2345"}
        ],
        "log_file": "loragw_hal.log"
    }
}
0 Answers