Skip to content

Commit 076afc0

Browse files
authored
Merge pull request #38 from cnbhl/feature/docker-support
feat: Docker support for containerized deployment
2 parents 148dca4 + 6598cba commit 076afc0

File tree

9 files changed

+556
-26
lines changed

9 files changed

+556
-26
lines changed

.dockerignore

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Build artifacts
2+
build-*/
3+
build-local/
4+
5+
# Dependency cloned repos (will be fetched during build)
6+
deps/lgw/git-repo/
7+
deps/lgw/platform-*/
8+
deps/lgw1302/git-repo/
9+
deps/lgw1302/platform-*/
10+
deps/mbedtls/git-repo/
11+
deps/mbedtls/platform-*/
12+
deps/smtcpico/
13+
14+
# Credentials (never include in image)
15+
*.key
16+
*.trust
17+
*.crt
18+
cups.uri
19+
tc.uri
20+
examples/corecell/cups-ttn/station.conf
21+
examples/corecell/cups-ttn/board.conf
22+
23+
# Tests
24+
regr-tests/
25+
tests/
26+
27+
# Documentation
28+
docs/
29+
*.md
30+
!examples/corecell/cups-ttn/*.md
31+
32+
# Logs
33+
*.log
34+
35+
# Editor and IDE files
36+
*~
37+
*.swp
38+
.vscode/
39+
.idea/
40+
41+
# Git
42+
.git/
43+
.gitignore
44+
45+
# Docker files (no recursive build)
46+
docker-compose.yml

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22

33
## Unreleased
44

5+
## 2.0.6-cnbhl.1.6 - 2025-02-04
6+
7+
* feature: Docker support for containerized deployment
8+
- Multi-stage Dockerfile (builder compiles station + chip_id, runner is minimal Debian bookworm-slim)
9+
- `docker/entrypoint.sh` validates env vars, generates config, auto-detects Gateway EUI, starts station
10+
- `docker-compose.yml` with all environment variables documented
11+
- `.dockerignore` excludes build artifacts, credentials, tests
12+
- Support for all board types (WM1302, PG1302, LR1302, SX1302_WS, SEMTECH, custom GPIO)
13+
- Auto EUI detection from SX1302 chip via `chip_id`
14+
- GPS passthrough support
15+
- Custom SPI device path support
16+
- `EUI_ONLY=1` mode for detecting Gateway EUI before TTN registration
17+
* fix: Add python3, python3-jsonschema, python3-jinja2 to Docker builder (required by mbedtls 3.6.0)
18+
* fix: Clean up stale PID files before station start in Docker (prevents restart failures)
19+
* fix: Use station's built-in `stderr` log mode instead of `/dev/stderr` path for Docker log compatibility
520
* fix: Zero-initialize ifconf struct before JSON channel config parsing (cherry-pick from MultiTech `64f634f`)
621
* feature: mbedtls 3.x compatibility with TLS 1.3 support (cherry-pick from MultiTech)
722
- PSA crypto initialization for mbedtls 3.x
@@ -22,6 +37,10 @@
2237
- LNS can control GPS via `router_config` with `gps_enable` field
2338
- Advertises `gps-ctrl` feature flag to LNS
2439
* fix: Use correct TX command when checking nocca response (cherry-pick from MultiTech `5c54f11`)
40+
* feature: Fine timestamp support for SX1302/SX1303 with GPS PPS
41+
* feature: SF5/SF6 spreading factor support (LoRaWAN RP2 1.0.5)
42+
* fix: SX1302 LBT error handling (correct error constants for SX1302 vs SX1301)
43+
* fix: Exit on stuck concentrator (excessive clock drift detection)
2544

2645
## 2.0.6-cnbhl.1.0 - 2025-01-25
2746

CLAUDE.md

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ This is a fork of [lorabasics/basicstation](https://github.com/lorabasics/basics
1212
- Automatic Gateway EUI detection from SX1302/SX1303 chips
1313
- Systemd service configuration
1414
- Fine timestamp support for SX1302/SX1303 with GPS PPS
15+
- Docker support for containerized deployment
1516

1617
For upstream Basic Station documentation: https://doc.sm.tc/station
1718

@@ -481,6 +482,96 @@ sudo systemctl start basicstation.service
481482
sudo journalctl -u basicstation.service -f
482483
```
483484

485+
## Docker Support
486+
487+
Build and run the station as a Docker container on Raspberry Pi.
488+
489+
### Build
490+
491+
```bash
492+
docker build -t basicstation .
493+
# Debug variant:
494+
docker build -t basicstation --build-arg VARIANT=debug .
495+
```
496+
497+
### Detect EUI (new board)
498+
499+
```bash
500+
docker run --rm --privileged -e BOARD=WM1302 -e EUI_ONLY=1 basicstation
501+
```
502+
503+
Register the printed EUI on TTN Console, then start:
504+
505+
### Run
506+
507+
```bash
508+
# Using docker-compose (recommended)
509+
CUPS_KEY="NNSXS.xxx..." docker compose up -d
510+
docker logs -f basicstation
511+
512+
# Using docker run
513+
docker run -d --privileged --network host \
514+
--name basicstation --restart unless-stopped \
515+
-e BOARD=PG1302 -e REGION=eu1 \
516+
-e GATEWAY_EUI=auto \
517+
-e CUPS_KEY="NNSXS.xxx..." \
518+
basicstation
519+
```
520+
521+
### Environment Variables
522+
523+
| Variable | Required | Default | Description |
524+
|----------|----------|---------|-------------|
525+
| `BOARD` | Yes | -- | WM1302, PG1302, LR1302, SX1302_WS, SEMTECH, or `custom` |
526+
| `REGION` | Yes | -- | TTN region: eu1, nam1, au1 |
527+
| `GATEWAY_EUI` | Yes | -- | 16 hex chars or `auto` (chip detection) |
528+
| `CUPS_KEY` | Yes | -- | TTN CUPS API key (NNSXS.xxx...) |
529+
| `EUI_ONLY` | No | -- | Set to `1` to detect Gateway EUI and exit (only `BOARD` required) |
530+
| `GPS_DEV` | No | _(disabled)_ | GPS device path (e.g. `/dev/ttyS0`) or `none` |
531+
| `ANTENNA_GAIN` | No | `0` | Antenna gain in dBi (0-15) |
532+
| `SPI_DEV` | No | `/dev/spidev0.0` | SPI device path |
533+
| `LOG_LEVEL` | No | `DEBUG` | Station log level |
534+
| `SX1302_RESET_GPIO` | If custom | -- | BCM pin for SX1302 reset |
535+
| `POWER_EN_GPIO` | If custom | -- | BCM pin for power enable |
536+
| `SX1261_RESET_GPIO` | If custom | -- | BCM pin for SX1261 reset |
537+
538+
### Docker Files
539+
540+
- `Dockerfile` - Multi-stage build (builder compiles station + chip_id, runner is minimal)
541+
- `docker/entrypoint.sh` - Validates env vars, generates config, starts station
542+
- `docker-compose.yml` - Example compose file with all env vars documented
543+
- `.dockerignore` - Excludes build artifacts, credentials, tests from context
544+
545+
### Container Layout
546+
547+
```
548+
/app/
549+
├── bin/station # Station binary
550+
├── bin/chip_id # EUI detection tool
551+
├── scripts/
552+
│ ├── reset_lgw.sh # GPIO reset (SX1302 + SX1261 + Power EN)
553+
│ ├── rinit.sh # Radio init wrapper
554+
│ └── board.conf # Generated at runtime by entrypoint
555+
├── templates/
556+
│ ├── station.conf.template
557+
│ └── board.conf.template
558+
├── config/ # Station home dir (generated at runtime)
559+
│ ├── station.conf
560+
│ ├── cups.uri
561+
│ ├── cups.key
562+
│ └── cups.trust
563+
└── entrypoint.sh
564+
```
565+
566+
### Notes
567+
568+
- Requires `privileged: true` or sysfs GPIO access for concentrator reset
569+
- Requires `network_mode: host` for LoRaWAN packet reception
570+
- Logs go to stderr via station's built-in stderr mode (`log_file: "stderr"`) — visible via `docker logs`
571+
- Uses the same `station.conf.template` and `board.conf.template` as `setup-gateway.sh`
572+
- Builder stage requires `python3`, `python3-jsonschema`, `python3-jinja2` for mbedtls 3.6.0 PSA crypto wrapper generation
573+
- Stale PID files (`/var/tmp/station.pid`, `/tmp/station.pid`) are cleaned up before station start to prevent restart failures
574+
484575
## Build System Notes
485576

486577
Platform/variant configuration in `setup.gmk`:
@@ -578,7 +669,7 @@ Format: `2.0.6-cnbhl.X.Y` or `2.0.6-cnbhl.X.Ya`
578669
- **Tag**: No "v" prefix (e.g., `2.0.6-cnbhl.1.0`)
579670
- **Release title**: `Release 2.0.6-cnbhl.X.Y` (prefix with "Release ")
580671

581-
**Current version**: `2.0.6-cnbhl.1.5`
672+
**Current version**: `2.0.6-cnbhl.1.6`
582673

583674
**History**: Versions `2.0.6-cnbhl.1` through `2.0.6-cnbhl.5` used the old single-number scheme.
584675
Starting with `2.0.6-cnbhl.1.0`, we use the new X.Y format.

Dockerfile

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,76 @@
1-
FROM ubuntu:18.04
1+
# Multi-stage Dockerfile for cnbhl/basicstation-rpi64
2+
# Builds and runs Basic Station with SX1302/SX1303 corecell support
3+
#
4+
# Build: docker build -t basicstation .
5+
# Run: docker run -d --privileged --network host \
6+
# -e BOARD=PG1302 -e REGION=eu1 -e GATEWAY_EUI=auto \
7+
# -e CUPS_KEY="NNSXS.xxx..." basicstation
28

3-
ENV container=docker TERM=xterm LC_ALL=en_US LANGUAGE=en_US LANG=en_US.UTF-8
4-
ENV DEBIAN_FRONTEND=noninteractive
9+
ARG VARIANT=std
510

6-
# locale
7-
RUN apt-get update -q > /dev/null && \
8-
apt-get install --no-install-recommends -yq apt-utils locales language-pack-en dialog \
9-
> /dev/null && \
10-
locale-gen $LANGUAGE $LANG
11+
# =============================================================================
12+
# Stage 1: Builder
13+
# =============================================================================
14+
FROM debian:bookworm-slim AS builder
1115

12-
# sudo commmand
13-
RUN apt-get -yq install sudo > /dev/null
16+
ARG VARIANT=std
1417

15-
# non-privileged user
16-
RUN echo "nonprivuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
17-
RUN useradd --no-log-init --home-dir /home/nonprivuser --create-home --shell /bin/bash -u 1000 \
18-
nonprivuser && adduser nonprivuser sudo
19-
USER nonprivuser
20-
WORKDIR /home/nonprivuser
18+
RUN apt-get update && apt-get install -y --no-install-recommends \
19+
build-essential \
20+
git \
21+
curl \
22+
ca-certificates \
23+
python3 \
24+
python3-jsonschema \
25+
python3-jinja2 \
26+
&& rm -rf /var/lib/apt/lists/*
2127

22-
# system packages
23-
RUN sudo apt-get install --no-install-recommends -yq \
24-
git psmisc build-essential lcov curl netcat-openbsd \
25-
python3 python3-pip python3-setuptools python3-wheel \
26-
> /dev/null && \
27-
sudo apt-get clean -q && \
28-
sudo ln -s /usr/bin/python3 /usr/bin/python
28+
COPY . /build
29+
WORKDIR /build
2930

30-
RUN pip3 install aiohttp websockets
31+
# Build station binary (deps/*/prep.sh clone HAL and mbedtls via git)
32+
RUN make platform=corecell variant=${VARIANT}
3133

34+
# Build chip_id tool for EUI auto-detection
35+
RUN gcc -std=gnu11 -O2 \
36+
-I build-corecell-${VARIANT}/include/lgw \
37+
tools/chip_id/chip_id.c tools/chip_id/log_stub.c \
38+
-L build-corecell-${VARIANT}/lib -llgw1302 -lm -lpthread -lrt \
39+
-o build-corecell-${VARIANT}/bin/chip_id
3240

41+
# =============================================================================
42+
# Stage 2: Runner
43+
# =============================================================================
44+
FROM debian:bookworm-slim
45+
46+
ARG VARIANT=std
47+
48+
RUN apt-get update && apt-get install -y --no-install-recommends \
49+
ca-certificates \
50+
&& rm -rf /var/lib/apt/lists/*
51+
52+
# Create directory structure
53+
RUN mkdir -p /app/bin /app/scripts /app/templates /app/config
54+
55+
# Copy binaries from builder
56+
COPY --from=builder /build/build-corecell-${VARIANT}/bin/station /app/bin/station
57+
COPY --from=builder /build/build-corecell-${VARIANT}/bin/chip_id /app/bin/chip_id
58+
59+
# Copy runtime scripts
60+
COPY examples/corecell/cups-ttn/reset_lgw.sh /app/scripts/reset_lgw.sh
61+
COPY examples/corecell/cups-ttn/rinit.sh /app/scripts/rinit.sh
62+
63+
# Copy templates
64+
COPY examples/corecell/cups-ttn/station.conf.template /app/templates/station.conf.template
65+
COPY examples/corecell/cups-ttn/board.conf.template /app/templates/board.conf.template
66+
67+
# Copy entrypoint
68+
COPY docker/entrypoint.sh /app/entrypoint.sh
69+
70+
RUN chmod +x /app/bin/station /app/bin/chip_id \
71+
/app/scripts/reset_lgw.sh /app/scripts/rinit.sh \
72+
/app/entrypoint.sh
73+
74+
WORKDIR /app/config
75+
76+
ENTRYPOINT ["/app/entrypoint.sh"]

README.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,32 @@ Fork of [lorabasics/basicstation](https://github.com/lorabasics/basicstation) (v
88
- Automated TTN CUPS setup with `setup-gateway.sh`
99
- Automatic Gateway EUI detection from SX1302/SX1303
1010
- Systemd service configuration
11+
- **Docker support** for containerized deployment
1112

1213
See [docs/FEATURES.md](docs/FEATURES.md) for a complete list of features and fixes.
1314

1415
For upstream documentation: [doc.sm.tc/station](https://doc.sm.tc/station)
1516

17+
## Table of Contents
18+
19+
- [Quick Start](#quick-start)
20+
- [Options](#options)
21+
- [Non-Interactive Mode](#non-interactive-mode)
22+
- [Supported Boards](#supported-boards)
23+
- [Tested Platforms](#tested-platforms)
24+
- [Prerequisites](#prerequisites)
25+
- [Docker Deployment](#docker-deployment)
26+
- [Step 1: Detect Gateway EUI](#step-1-detect-gateway-eui)
27+
- [Step 2: Start the station](#step-2-start-the-station)
28+
- [Environment Variables](#environment-variables)
29+
- [Running](#running)
30+
- [Repository Structure](#repository-structure)
31+
- [Testing](#testing)
32+
- [Raspberry Pi GPIO Support](#raspberry-pi-gpio-support)
33+
- [Dependencies](#dependencies)
34+
- [Third-Party Components](#third-party-components)
35+
- [License](#license)
36+
1637
## Quick Start
1738

1839
```bash
@@ -103,6 +124,58 @@ Run `sudo raspi-config` → Interface Options:
103124

104125
Reboot after changes.
105126

127+
## Docker Deployment
128+
129+
Run the station as a Docker container — no build tools or dependencies needed on the host.
130+
131+
```bash
132+
docker build -t basicstation .
133+
```
134+
135+
### Step 1: Detect Gateway EUI
136+
137+
For a new board, detect the EUI first to register on TTN:
138+
139+
```bash
140+
docker run --rm --privileged -e BOARD=WM1302 -e EUI_ONLY=1 basicstation
141+
```
142+
143+
This prints the Gateway EUI and exits. Register the gateway at [TTN Console](https://console.cloud.thethings.network/) and generate a CUPS API key.
144+
145+
### Step 2: Start the station
146+
147+
```bash
148+
docker run -d --privileged --network host \
149+
--name basicstation --restart unless-stopped \
150+
-e BOARD=WM1302 -e REGION=eu1 \
151+
-e GATEWAY_EUI=auto \
152+
-e CUPS_KEY="NNSXS.xxx..." \
153+
basicstation
154+
```
155+
156+
Or with docker compose:
157+
158+
```bash
159+
CUPS_KEY="NNSXS.xxx..." docker compose up -d
160+
docker logs -f basicstation
161+
```
162+
163+
### Environment Variables
164+
165+
| Variable | Required | Default | Description |
166+
|----------|----------|---------|-------------|
167+
| `BOARD` | Yes | -- | WM1302, PG1302, LR1302, SX1302_WS, SEMTECH, or `custom` |
168+
| `REGION` | Yes | -- | TTN region: eu1, nam1, au1 |
169+
| `GATEWAY_EUI` | Yes | -- | 16 hex chars or `auto` (chip detection) |
170+
| `CUPS_KEY` | Yes | -- | TTN CUPS API key |
171+
| `EUI_ONLY` | No | -- | Set to `1` to detect EUI and exit (no CUPS_KEY needed) |
172+
| `GPS_DEV` | No | _(disabled)_ | GPS device path or `none` |
173+
| `ANTENNA_GAIN` | No | `0` | Antenna gain in dBi (0-15) |
174+
| `SPI_DEV` | No | `/dev/spidev0.0` | SPI device path |
175+
| `LOG_LEVEL` | No | `DEBUG` | Station log level |
176+
177+
For custom boards, set `BOARD=custom` and provide `SX1302_RESET_GPIO`, `POWER_EN_GPIO`, `SX1261_RESET_GPIO`.
178+
106179
## Running
107180

108181
**Via systemd** (if configured during setup):
@@ -123,6 +196,9 @@ cd examples/corecell/cups-ttn
123196
```
124197
basicstation/
125198
├── setup-gateway.sh # Main setup script
199+
├── Dockerfile # Multi-stage Docker build
200+
├── docker-compose.yml # Docker compose example
201+
├── docker/entrypoint.sh # Container entrypoint
126202
├── lib/ # Modular shell libraries
127203
│ ├── common.sh # Output, logging, dependency checks
128204
│ ├── validation.sh # Input validation

VERSION.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.0.6-cnbhl.1.0
1+
2.0.6-cnbhl.1.6

0 commit comments

Comments
 (0)