feat: add basic app that consumes mqtt uplinks from chirpstack
This commit is contained in:
parent
87ffc9cad7
commit
31a1c14831
10 changed files with 570 additions and 0 deletions
6
app/Dockerfile
Normal file
6
app/Dockerfile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
FROM python:3.13-slim
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY main.py .
|
||||
CMD ["python", "main.py"]
|
||||
30
app/main.py
Normal file
30
app/main.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import paho.mqtt.client as mqtt
|
||||
import logging
|
||||
import sys
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||||
datefmt="%Y-%m-%dT%H:%M:%S",
|
||||
stream=sys.stdout, # Docker lit stdout par défaut
|
||||
force=True
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def on_connect(client, userdata, flags, reason_code, properties):
|
||||
log.info(f"Connected with result code {reason_code}")
|
||||
client.subscribe("application/+/device/+/event/up")
|
||||
|
||||
def on_message(client, userdata, msg):
|
||||
log.info(msg.topic+" "+str(msg.payload))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
||||
mqttc.on_connect = on_connect
|
||||
mqttc.on_message = on_message
|
||||
|
||||
mqttc.connect("mosquitto", 1883, 60)
|
||||
mqttc.loop_forever()
|
||||
1
app/requirements.txt
Normal file
1
app/requirements.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
paho-mqtt==v2.1.0
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
[integration.mqtt.auth.generic]
|
||||
servers=["tcp://mosquitto:1883"]
|
||||
username=""
|
||||
password=""
|
||||
|
||||
[integration.mqtt]
|
||||
event_topic_template="eu868/gateway/{{ .GatewayID }}/event/{{ .EventType }}"
|
||||
state_topic_template="eu868/gateway/{{ .GatewayID }}/state/{{ .StateType }}"
|
||||
command_topic_template="eu868/gateway/{{ .GatewayID }}/command/#"
|
||||
|
||||
[backend]
|
||||
type="basic_station"
|
||||
|
||||
[backend.basic_station]
|
||||
bind=":3001"
|
||||
tls_cert=""
|
||||
tls_key=""
|
||||
ca_cert=""
|
||||
|
||||
region="EU868"
|
||||
frequency_min=863000000
|
||||
frequency_max=870000000
|
||||
|
||||
|
||||
[[backend.basic_station.concentrators]]
|
||||
|
||||
[backend.basic_station.concentrators.multi_sf]
|
||||
frequencies=[
|
||||
868100000,
|
||||
868300000,
|
||||
868500000,
|
||||
867100000,
|
||||
867300000,
|
||||
867500000,
|
||||
867700000,
|
||||
867900000,
|
||||
]
|
||||
|
||||
[backend.basic_station.concentrators.lora_std]
|
||||
frequency=868300000
|
||||
bandwidth=250000
|
||||
spreading_factor=7
|
||||
|
||||
[backend.basic_station.concentrators.fsk]
|
||||
frequency=868800000
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# See https://www.chirpstack.io/gateway-bridge/install/config/ for a full
|
||||
# configuration example and documentation.
|
||||
|
||||
[integration.mqtt.auth.generic]
|
||||
servers=["tcp://mosquitto:1883"]
|
||||
username=""
|
||||
password=""
|
||||
105
configuration/chirpstack/chirpstack.toml
Normal file
105
configuration/chirpstack/chirpstack.toml
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# Logging.
|
||||
[logging]
|
||||
|
||||
# Log level.
|
||||
#
|
||||
# Options are: trace, debug, info, warn error.
|
||||
level="info"
|
||||
|
||||
|
||||
# PostgreSQL configuration.
|
||||
[postgresql]
|
||||
|
||||
# PostgreSQL DSN.
|
||||
#
|
||||
# Format example: postgres://<USERNAME>:<PASSWORD>@<HOSTNAME>/<DATABASE>?sslmode=<SSLMODE>.
|
||||
#
|
||||
# SSL mode options:
|
||||
# * disable - Do not use TLS
|
||||
# * prefer - Attempt to connect with TLS but allow sessions without
|
||||
# * require - Require the use of TLS
|
||||
dsn="postgres://chirpstack:chirpstack@$POSTGRESQL_HOST/chirpstack?sslmode=disable"
|
||||
|
||||
# Max open connections.
|
||||
#
|
||||
# This sets the max. number of open connections that are allowed in the
|
||||
# PostgreSQL connection pool.
|
||||
max_open_connections=10
|
||||
|
||||
# Min idle connections.
|
||||
#
|
||||
# This sets the min. number of idle connections in the PostgreSQL connection
|
||||
# pool (0 = equal to max_open_connections).
|
||||
min_idle_connections=0
|
||||
|
||||
|
||||
# Redis configuration.
|
||||
[redis]
|
||||
|
||||
# Server address or addresses.
|
||||
#
|
||||
# Set multiple addresses when connecting to a cluster.
|
||||
servers=[
|
||||
"redis://$REDIS_HOST/",
|
||||
]
|
||||
|
||||
# TLS enabled.
|
||||
tls_enabled=false
|
||||
|
||||
# Redis Cluster.
|
||||
#
|
||||
# Set this to true when the provided URLs are pointing to a Redis Cluster
|
||||
# instance.
|
||||
cluster=false
|
||||
|
||||
|
||||
# Network related configuration.
|
||||
[network]
|
||||
|
||||
# Network identifier (NetID, 3 bytes) encoded as HEX (e.g. 010203).
|
||||
net_id="000000"
|
||||
|
||||
# Enabled regions.
|
||||
#
|
||||
# Multiple regions can be enabled simultaneously. Each region must match
|
||||
# the 'name' parameter of the region configuration in '[[regions]]'.
|
||||
enabled_regions=[
|
||||
"as923",
|
||||
"as923_2",
|
||||
"as923_3",
|
||||
"as923_4",
|
||||
"au915_0",
|
||||
"cn470_10",
|
||||
"cn779",
|
||||
"eu433",
|
||||
"eu868",
|
||||
"in865",
|
||||
"ism2400",
|
||||
"kr920",
|
||||
"ru864",
|
||||
"us915_0",
|
||||
"us915_1",
|
||||
]
|
||||
|
||||
|
||||
# API interface configuration.
|
||||
[api]
|
||||
|
||||
# interface:port to bind the API interface to.
|
||||
bind="0.0.0.0:8080"
|
||||
|
||||
# Secret.
|
||||
#
|
||||
# This secret is used for generating login and API tokens, make sure this
|
||||
# is never exposed. Changing this secret will invalidate all login and API
|
||||
# tokens. The following command can be used to generate a random secret:
|
||||
# openssl rand -base64 32
|
||||
secret="you-must-replace-this"
|
||||
|
||||
|
||||
[integration]
|
||||
enabled=["mqtt"]
|
||||
|
||||
[integration.mqtt]
|
||||
server="tcp://$MQTT_BROKER_HOST:1883/"
|
||||
json=true
|
||||
280
configuration/chirpstack/region_eu868.toml
Normal file
280
configuration/chirpstack/region_eu868.toml
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
# 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"
|
||||
|
||||
|
||||
# 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"
|
||||
|
||||
# MQTT server (e.g. scheme://host:port where scheme is tcp, ssl or ws)
|
||||
server="tcp://$MQTT_BROKER_HOST: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 (dBm)
|
||||
#
|
||||
# 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
|
||||
2
configuration/mosquitto/config/mosquitto.conf
Normal file
2
configuration/mosquitto/config/mosquitto.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
listener 1883
|
||||
allow_anonymous true
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname="$POSTGRES_DB" <<-EOSQL
|
||||
create extension pg_trgm;
|
||||
create extension hstore;
|
||||
EOSQL
|
||||
87
docker-compose.yml
Normal file
87
docker-compose.yml
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
services:
|
||||
chirpstack:
|
||||
image: chirpstack/chirpstack:4
|
||||
command: -c /etc/chirpstack
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./configuration/chirpstack:/etc/chirpstack
|
||||
depends_on:
|
||||
- postgres
|
||||
- mosquitto
|
||||
- redis
|
||||
environment:
|
||||
- MQTT_BROKER_HOST=mosquitto
|
||||
- REDIS_HOST=redis
|
||||
- POSTGRESQL_HOST=postgres
|
||||
ports:
|
||||
- "8080:8080"
|
||||
|
||||
chirpstack-gateway-bridge:
|
||||
image: chirpstack/chirpstack-gateway-bridge:4
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "1700:1700/udp"
|
||||
volumes:
|
||||
- ./configuration/chirpstack-gateway-bridge:/etc/chirpstack-gateway-bridge
|
||||
environment:
|
||||
- INTEGRATION__MQTT__EVENT_TOPIC_TEMPLATE=eu868/gateway/{{ .GatewayID }}/event/{{ .EventType }}
|
||||
- INTEGRATION__MQTT__STATE_TOPIC_TEMPLATE=eu868/gateway/{{ .GatewayID }}/state/{{ .StateType }}
|
||||
- INTEGRATION__MQTT__COMMAND_TOPIC_TEMPLATE=eu868/gateway/{{ .GatewayID }}/command/#
|
||||
depends_on:
|
||||
- mosquitto
|
||||
|
||||
chirpstack-gateway-bridge-basicstation:
|
||||
image: chirpstack/chirpstack-gateway-bridge:4
|
||||
restart: unless-stopped
|
||||
command: -c /etc/chirpstack-gateway-bridge/chirpstack-gateway-bridge-basicstation-eu868.toml
|
||||
ports:
|
||||
- "3001:3001"
|
||||
volumes:
|
||||
- ./configuration/chirpstack-gateway-bridge:/etc/chirpstack-gateway-bridge
|
||||
depends_on:
|
||||
- mosquitto
|
||||
|
||||
chirpstack-rest-api:
|
||||
image: chirpstack/chirpstack-rest-api:4
|
||||
restart: unless-stopped
|
||||
command: --server chirpstack:8080 --bind 0.0.0.0:8090 --insecure
|
||||
ports:
|
||||
- "8090:8090"
|
||||
depends_on:
|
||||
- chirpstack
|
||||
|
||||
postgres:
|
||||
image: postgres:14-alpine
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./configuration/postgresql/initdb:/docker-entrypoint-initdb.d
|
||||
- postgresqldata:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_USER=chirpstack
|
||||
- POSTGRES_PASSWORD=chirpstack
|
||||
- POSTGRES_DB=chirpstack
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
command: redis-server --save 300 1 --save 60 100 --appendonly no
|
||||
volumes:
|
||||
- redisdata:/data
|
||||
|
||||
mosquitto:
|
||||
image: eclipse-mosquitto:2
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "1883:1883"
|
||||
volumes:
|
||||
- ./configuration/mosquitto/config/:/mosquitto/config/
|
||||
|
||||
application:
|
||||
build: ./app
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- mosquitto
|
||||
|
||||
volumes:
|
||||
postgresqldata:
|
||||
redisdata:
|
||||
Loading…
Add table
Add a link
Reference in a new issue