· Raspberry Pi· IoT· gateway· Linux· udev· systemd· watchdog· 4G· wM-Bus· installation
Raspberry Pi 4 som IoT gateway — Linux opsætning, udev og watchdog
Raspberry Pi 4 opsætning til IoT gateway: Raspberry Pi OS Lite 64-bit, udev regler til USB-dongle, systemd service, hardware watchdog, SD-kort optimering og 4G PPP.
Af M-Bus Gateway
M-Bus Gateway kører på Raspberry Pi 4 Model B 1GB. Her er den komplette Linux-opsætning fra frisk SD-kort til produktionsklar gateway.
OS og initial konfiguration
# 1. Skriv Raspberry Pi OS Lite 64-bit til SD-kort:
# rpi-imager → Raspberry Pi OS Lite (64-bit, Debian Trixie)
# Aktiver SSH i rpi-imager inden skrivning
# 2. Boot og SSH:
ssh pi@raspberrypi.local
# 3. Opdatér system:
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y git curl python3-pip python3-venv \
ufw fail2ban python3-dev build-essential
# 4. Opret mbus-bruger:
sudo useradd -m -s /bin/bash mbus
sudo usermod -aG dialout mbus # Adgang til /dev/ttyUSB* (USB-dongle)
sudo usermod -aG gpio mbus # Adgang til GPIO (LED, knap)
# 5. Deaktivér unødvendige services (reducér SD-slitage):
sudo systemctl disable bluetooth
sudo systemctl disable avahi-daemon
sudo systemctl disable triggerhappy
udev: Stabil USB-symlink til wM-Bus dongle
# Find USB VID:PID til Würth 2605056083001:
lsusb
# Bus 001 Device 003: ID 10c4:ea60 Silicon Laboratories CP210x UART Bridge
# Opret udev regel:
sudo tee /etc/udev/rules.d/99-wmbus.rules << 'EOF'
# Würth Elektronik 2605056083001 wM-Bus USB dongle
# VID=10c4 PID=ea60 = Silicon Labs CP210x (brugt i dongle)
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", \
SYMLINK+="wmbus", MODE="0660", GROUP="dialout", \
TAG+="systemd", ENV{SYSTEMD_WANTS}="mbus-gateway.service"
EOF
# Genindlæs udev:
sudo udevadm control --reload-rules
sudo udevadm trigger
# Test: Sæt dongle i USB — symlink skal opstå:
ls -la /dev/wmbus
# lrwxrwxrwx /dev/wmbus → ttyUSB0
systemd service: Auto-start med watchdog
# /etc/systemd/system/mbus-gateway.service
[Unit]
Description=M-Bus Gateway
After=network-online.target
Wants=network-online.target
# Start først når wmbus-enheden er tilgængelig:
BindsTo=dev-wmbus.device
After=dev-wmbus.device
[Service]
Type=notify
User=mbus
Group=mbus
WorkingDirectory=/opt/mbus-gateway
ExecStart=/opt/mbus-gateway/venv/bin/python -m gateway.src.main
ExecStop=/bin/kill -TERM $MAINPID
# Restart ved fejl:
Restart=on-failure
RestartSec=10s
StartLimitIntervalSec=300
StartLimitBurst=5
# Systemd watchdog: Genstart service hvis Python ikke pinger inden 120s:
WatchdogSec=120
# Python sender sd_notify("WATCHDOG=1") hvert 60s
# Environment:
EnvironmentFile=/etc/mbus-gateway/config.env
Environment=PYTHONPATH=/opt/mbus-gateway
# Ressourcegrænser:
MemoryMax=256M
CPUQuota=80%
[Install]
WantedBy=multi-user.target
Hardware watchdog: /dev/watchdog
# gateway/src/watchdog.py
# Hardware watchdog — reboots Pi ved kernel/Python-hæng uanset systemd
import fcntl
import os
import asyncio
import structlog
logger = structlog.get_logger()
WATCHDOG_PATH = "/dev/watchdog"
# BCM2835 hardware watchdog default timeout: 15 sekunder
# Feed hvert 10 sekunder = 5 sekunders margen
class HardwareWatchdog:
def __init__(self):
self._fd = None
def open(self):
"""Åbn watchdog device. Ingen close() = reboot efter timeout."""
try:
self._fd = open(WATCHDOG_PATH, "wb", buffering=0)
logger.info("watchdog_opened")
except PermissionError:
logger.warning("watchdog_no_permission", path=WATCHDOG_PATH)
def feed(self):
"""Reset watchdog timer. Skal ske inden timeout (15s)."""
if self._fd:
# IOCTL WDIOC_KEEPALIVE = 0x80045705
try:
fcntl.ioctl(self._fd, 0x80045705, 0)
except OSError:
self._fd.write(b"1") # Fallback: skriv byte
def close_safe(self):
"""Luk watchdog uden reboot (skriv 'V' magic byte)."""
if self._fd:
self._fd.write(b"V")
self._fd.close()
self._fd = None
async def watchdog_task(watchdog: HardwareWatchdog):
"""Kør som baggrundstask — feed watchdog hvert 10 sekunder."""
while True:
watchdog.feed()
await asyncio.sleep(10)
SD-kort optimering: Reducér skrivninger
# /etc/fstab — Montér tmpfs for log og tmp (undgå SD-slitage):
# Tilføj disse linjer:
tmpfs /tmp tmpfs defaults,noatime,nosuid,size=64m 0 0
tmpfs /var/tmp tmpfs defaults,noatime,nosuid,size=32m 0 0
tmpfs /var/log tmpfs defaults,noatime,nosuid,size=64m 0 0
tmpfs /var/run tmpfs defaults,noatime,nosuid,size=16m 0 0
# Disabél swap (SD-kort lever ikke af swap-skrivninger):
sudo dphys-swapfile swapoff
sudo systemctl disable dphys-swapfile
# noatime på root-partition:
# Redigér /etc/fstab — tilføj "noatime" til rootfs-linjen:
# PARTUUID=... / ext4 defaults,noatime 0 1
# Journald: Begrænse log-størrelse:
sudo mkdir -p /etc/systemd/journald.conf.d/
sudo tee /etc/systemd/journald.conf.d/size.conf << 'EOF'
[Journal]
Storage=volatile
RuntimeMaxUse=32M
EOF
4G PPP: SIM7080G HAT forbindelse
# /etc/ppp/peers/1nce — 1NCE IoT SIM konfiguration:
/dev/ttyS0 # SIM7080G UART (GPIO HAT)
115200
defaultroute # Brug 4G som default route ved opkobling
usepeerdns # Brug operatørens DNS
noauth # 1NCE kræver ikke PAP/CHAP
persist # Genopret forbindelsen automatisk ved tab
maxfail 0 # Prøv uendeligt mange gange
holdoff 30 # Vent 30 sek mellem forsøg
# APN:
connect "/usr/sbin/chat -v -f /etc/chatscripts/gprs APN iot.1nce.net"
# Test forbindelse:
sudo pon 1nce
ip route show
ping -c 4 8.8.8.8
Konklusion
Raspberry Pi 4 med Raspberry Pi OS Lite 64-bit er en stabil IoT gateway-platform. udev-symlinken /dev/wmbus sikrer stabil dongle-reference uanset USB-port. Systemd med BindsTo=dev-wmbus.device starter først ved tilgængelig dongle. Hardware watchdog + systemd watchdog giver 2-lags fejlgenopretning. tmpfs-montering forlænger SD-kortets levetid markant.