00 ModemManager mimarisi — D-Bus, udev, daemon
ModemManager, Linux'ta USB/seri/PCIe modemleri yöneten birleşik bir D-Bus daemon'ıdır. AT, QMI ve MBIM protokollerini soyutlar.
Uygulama (nmcli, mmcli, Python GDBus)
↓ org.freedesktop.ModemManager1 (D-Bus)
ModemManager daemon (modemmanager.service)
├── udev kuralları → modem cihaz tespiti
├── AT port yönetimi (/dev/ttyUSBx)
├── QMI port yönetimi (/dev/cdc-wdmx)
└── MBIM port yönetimi
↓
Modem donanımı (EC25, RM500Q, SIM7600)
├── /dev/ttyUSB2 (AT komutları)
├── /dev/cdc-wdm0 (QMI/MBIM kontrol)
└── /dev/wwan0 (data arayüzü)
Kurulum
# Debian / Ubuntu
apt-get install modemmanager libqmi-utils libmbim-utils
# Yocto — meta-oe katmanı gerekli
# IMAGE_INSTALL += "modemmanager"
# Buildroot
# BR2_PACKAGE_MODEMMANAGER=y
# Servis durumunu kontrol et
systemctl status ModemManager
# ● ModemManager.service - Modem Manager
# Active: active (running) since ...
# Main PID: 1234 (ModemManager)
# Servis başlat ve etkinleştir
systemctl enable --now ModemManager
# Versiyon
mmcli --version
# mmcli 1.20.6
# Debug log (sorun giderme)
ModemManager --debug 2>&1 | tee /tmp/mm-debug.log
ModemManager çalışırken aynı anda AT portuna (/dev/ttyUSB2) doğrudan yazmayın. ModemManager portu kilitler ve çakışma yaşanır. Modem kontrolü için mmcli veya D-Bus API kullanın.
01 mmcli — modem listele, durum, etkinleştir
mmcli (ModemManager CLI), ModemManager'ın tüm işlevlerine komut satırından erişim sağlar.
# Tespit edilen modemleri listele
mmcli -L
# /org/freedesktop/ModemManager1/Modem/0 [Quectel] EC25
# Modem detaylı bilgisi (index 0)
mmcli -m 0
# ----------------------------------
# General | dbus path: /org/.../Modem/0
# | device id: abc123...
# ----------------------------------
# Hardware | manufacturer: Quectel
# | model: EC25
# | firmware revision: EC25EFAR06A12M4G
# | supported: gsm-umts, lte
# | current: lte
# ----------------------------------
# Status | state: registered
# | power state: on
# | signal quality: 71% (recent)
# ----------------------------------
# Modes | supported: allowed: any; preferred: none
# ----------------------------------
# Bands | supported: utran-1, eutran-3, eutran-7,...
# ----------------------------------
# IP | supported methods: ipv4, ipv6, ipv4v6
# Modemi etkinleştir
mmcli -m 0 --enable
# successfully enabled the modem
# Modemi devre dışı bırak
mmcli -m 0 --disable
# Modemi sıfırla (reset)
mmcli -m 0 --reset
# SIM bilgisi
mmcli -m 0 --sim-status
mmcli -i 0
# -----------------------
# SIM | dbus path: /org/.../SIM/0
# | iccid: 8990101234567890
# | imsi: 286011234567890
# | operator code: 28601
# | operator name: Turkcell
JSON çıktısı (script entegrasyonu)
# JSON formatında çıktı al
mmcli -m 0 -J | jq '.'
# Sadece sinyal kalitesini al
mmcli -m 0 -J | jq '.modem.generic["signal-quality"].value'
# 71
# Modem durumunu al
mmcli -m 0 -J | jq -r '.modem.generic.state'
# connected
# IP adresini al
mmcli -m 0 --bearer=0 -J | \
jq -r '.bearer.ipv4config.address'
# 100.65.45.123
02 mmcli — bağlan ve bağlantıyı kes
mmcli ile data bağlantısı kurma, bearer (taşıyıcı) yönetimi ve bağlantı kesme işlemleri.
# Basit bağlantı (APN ile)
mmcli -m 0 --simple-connect="apn=internet"
# successfully connected the modem
# IPv4+IPv6 bağlantısı
mmcli -m 0 --simple-connect="apn=internet,ip-type=ipv4v6"
# PIN ile birlikte bağlantı
mmcli -m 0 --simple-connect="apn=internet,pin=1234"
# Bağlantıyı kes
mmcli -m 0 --simple-disconnect
# successfully disconnected all bearers in the modem
# Bearer (taşıyıcı) listesi
mmcli -m 0 --list-bearers
# /org/freedesktop/ModemManager1/Bearer/0
# Bearer detayları
mmcli -m 0 --bearer=0
# ----------------------------------------
# General | dbus path: /org/.../Bearer/0
# ----------------------------------------
# Status | connected: yes
# | disconnecting: no
# | interface: wwan0
# | ip timeout: 20
# ----------------------------------------
# Properties | apn: internet
# | roaming: allowed
# | ip type: ipv4
# ----------------------------------------
# IPv4 config| method: dhcp
# | address: 100.65.45.123
# | prefix: 30
# | gateway: 100.65.45.124
# | dns: 8.8.8.8, 8.8.4.4
# Bağlantı sonrası DHCP (dhclient veya udhcpc)
udhcpc -i wwan0 -n -q
ip addr show wwan0
# 2: wwan0: ... inet 100.65.45.123/30 ...
# Default route ekle
ip route add default via 100.65.45.124 dev wwan0
03 Connection profile oluşturma ve kalıcı bağlantı
NetworkManager ile kalıcı bağlantı profilleri oluşturma — sistem yeniden başladığında otomatik bağlanmak için.
# Mevcut bağlantıları listele
nmcli connection show
# NAME UUID TYPE DEVICE
# Eth0 abc-123... eth eth0
# GSM (LTE) bağlantı profili oluştur
nmcli connection add \
type gsm \
con-name "4G-LTE" \
ifname "*" \
gsm.apn "internet" \
gsm.number "*99#" \
gsm.pin "1234" \
connection.autoconnect yes
# Profili düzenle (APN değiştir)
nmcli connection modify "4G-LTE" gsm.apn "super"
# PIN kaldır (embedded cihazda PIN olmadan)
nmcli connection modify "4G-LTE" gsm.pin ""
# Bağlantıyı başlat
nmcli connection up "4G-LTE"
# Connection successfully activated
# Bağlantıyı durdur
nmcli connection down "4G-LTE"
# Bağlantı durumu
nmcli device status
# DEVICE TYPE STATE CONNECTION
# wwan0 gsm connected 4G-LTE
# eth0 ethernet connected Eth0
04 NetworkManager entegrasyonu — nmcli ile modem
NetworkManager ve ModemManager birlikte çalışır. NM, MM'nin D-Bus API'sini kullanarak modem bağlantılarını yönetir.
# NetworkManager'ın modem cihazını görmesi
nmcli device
# DEVICE TYPE STATE CONNECTION
# wwan0 gsm disconnected --
# Modem detayları NM üzerinden
nmcli device show wwan0
# GENERAL.DEVICE: wwan0
# GENERAL.TYPE: gsm
# GENERAL.HWADDR: (unknown)
# GENERAL.MTU: 1500
# GENERAL.STATE: 30 (disconnected)
# GENERAL.UDI: /sys/devices/.../usb1/.../net/wwan0
# Bağlantı kur
nmcli device connect wwan0
# WiFi ve 4G birlikte — 4G'yi yedek olarak ayarla
nmcli connection modify "4G-LTE" \
connection.autoconnect-priority -100
# NetworkManager dispatcher — bağlantı olayında script
# /etc/NetworkManager/dispatcher.d/99-lte-up
cat /etc/NetworkManager/dispatcher.d/99-lte-up
# #!/bin/bash
# IFACE=$1
# ACTION=$2
# if [ "$IFACE" = "wwan0" ] && [ "$ACTION" = "up" ]; then
# logger "4G bağlantısı kuruldu: $IFACE"
# # DNS ayarla
# echo "nameserver 8.8.8.8" > /etc/resolv.conf
# fi
chmod +x /etc/NetworkManager/dispatcher.d/99-lte-up
# NM yeniden başlat (config değişikliği sonrası)
systemctl restart NetworkManager
05 D-Bus API ile Python GDBus programatik kontrol
Python'dan ModemManager D-Bus API'sine doğrudan erişim — mmcli olmadan modem yönetimi, bağlantı izleme ve otomasyon.
#!/usr/bin/env python3
"""
ModemManager D-Bus API ile Python kontrolü.
Gereksinimler: pip install PyGObject pydbus
"""
from pydbus import SystemBus
from gi.repository import GLib
import time
BUS_NAME = 'org.freedesktop.ModemManager1'
OBJ_PATH = '/org/freedesktop/ModemManager1'
def get_modems(bus):
"""Mevcut modemleri döndür."""
mm = bus.get(BUS_NAME, OBJ_PATH)
manager = bus.get(BUS_NAME, OBJ_PATH)[
'org.freedesktop.DBus.ObjectManager'
]
objects = manager.GetManagedObjects()
modems = []
for path, ifaces in objects.items():
if 'org.freedesktop.ModemManager1.Modem' in ifaces:
modems.append(path)
return modems
def get_modem_info(bus, modem_path):
"""Modem bilgilerini al."""
modem = bus.get(BUS_NAME, modem_path)
iface = modem['org.freedesktop.ModemManager1.Modem']
return {
'manufacturer': iface.Manufacturer,
'model': iface.Model,
'revision': iface.Revision,
'imei': iface.EquipmentIdentifier,
'state': iface.State,
'signal': iface.SignalQuality,
}
def get_sim_info(bus, modem_path):
"""SIM bilgisini al."""
modem = bus.get(BUS_NAME, modem_path)
iface = modem['org.freedesktop.ModemManager1.Modem']
sim_path = iface.Sim
if not sim_path or sim_path == '/':
return None
sim = bus.get(BUS_NAME, sim_path)
sim_iface = sim['org.freedesktop.ModemManager1.Sim']
return {
'imsi': sim_iface.Imsi,
'iccid': sim_iface.SimIdentifier,
'operator_name': sim_iface.OperatorName,
'operator_id': sim_iface.OperatorIdentifier,
}
def simple_connect(bus, modem_path, apn='internet'):
"""Basit data bağlantısı kur."""
modem = bus.get(BUS_NAME, modem_path)
simple = modem['org.freedesktop.ModemManager1.Modem.Simple']
props = {
'apn': GLib.Variant('s', apn),
'ip-type': GLib.Variant('u', 1), # 1=ipv4
}
bearer_path = simple.Connect(props)
return bearer_path
def get_bearer_info(bus, bearer_path):
"""Bearer IP bilgisini al."""
bearer = bus.get(BUS_NAME, bearer_path)
b = bearer['org.freedesktop.ModemManager1.Bearer']
return {
'connected': b.Connected,
'interface': b.Interface,
'ipv4': dict(b.Ip4Config),
}
def monitor_signal(bus, modem_path, interval=10, count=5):
"""Sinyal kalitesini periyodik olarak ölç."""
modem = bus.get(BUS_NAME, modem_path)
sig_iface = modem['org.freedesktop.ModemManager1.Modem.Signal']
# Sinyal raporlama aralığını ayarla (saniye)
sig_iface.Setup(interval)
print(f"Sinyal izleniyor ({count}x, her {interval}s)...")
for _ in range(count):
time.sleep(interval)
try:
lte = dict(sig_iface.Lte)
print(f" RSSI={lte.get('rssi','?')} dBm, "
f"RSRP={lte.get('rsrp','?')} dBm, "
f"RSRQ={lte.get('rsrq','?')} dB, "
f"SINR={lte.get('sinr','?')} dB")
except Exception as e:
print(f" Sinyal okunamadı: {e}")
def main():
bus = SystemBus()
modems = get_modems(bus)
if not modems:
print("Modem bulunamadı! ModemManager çalışıyor mu?")
return
modem_path = modems[0]
print(f"Modem yolu: {modem_path}")
info = get_modem_info(bus, modem_path)
print(f"Üretici : {info['manufacturer']}")
print(f"Model : {info['model']}")
print(f"IMEI : {info['imei']}")
print(f"Durum : {info['state']}")
print(f"Sinyal : {info['signal'][0]}%")
sim = get_sim_info(bus, modem_path)
if sim:
print(f"IMSI : {sim['imsi']}")
print(f"Operatör: {sim['operator_name']}")
print("\nBağlantı kuruluyor...")
try:
bearer_path = simple_connect(bus, modem_path, apn='internet')
binfo = get_bearer_info(bus, bearer_path)
print(f"Arayüz : {binfo['interface']}")
print(f"IPv4 : {binfo['ipv4']}")
except Exception as e:
print(f"Bağlantı hatası: {e}")
if __name__ == '__main__':
main()
06 Sinyal kalitesi izleme — RSSI/RSRP/RSRQ/SINR
LTE sinyal metrikleri: RSSI (toplam güç), RSRP (referans sinyal gücü), RSRQ (kalite), SINR (sinyal/gürültü oranı). Her biri farklı bilgi taşır.
# mmcli sinyal kalitesi raporu
mmcli -m 0 --signal-get
# -------------------------
# Signal | lte rssi: -71 dBm
# | lte rsrq: -10 dB
# | lte rsrp: -93 dBm
# | lte snr: 12.8 dB
# Sinyal izlemeyi aktifleştir (10 saniyede bir)
mmcli -m 0 --signal-setup=10
# Serving cell bilgisi (AT+QENG Quectel)
mmcli -m 0 --command='AT+QENG="servingcell"'
# AT+QCSQ — Quectel sinyal detayları
mmcli -m 0 --command='AT+QCSQ'
# +QCSQ: "LTE",-71,-93,23,-10
# Format: rat, rssi, rsrp, sinr, rsrq
# SIM7600 sinyal detayları
mmcli -m 0 --command='AT+CPSI?'
# +CPSI: LTE,Online,286-01,0xB13,33623809,231,
# EUTRAN-BAND3,1750,3,3,-121,-1190,-930,13
# Sürekli izleme script'i
watch -n 5 "mmcli -m 0 --signal-get 2>&1"
Python sinyal logger
#!/usr/bin/env python3
"""mmcli sinyal değerlerini CSV'ye kaydet."""
import subprocess, json, time, csv, sys
from datetime import datetime
def get_signal():
r = subprocess.run(
['mmcli', '-m', '0', '--signal-get', '-J'],
capture_output=True, text=True, timeout=10
)
if r.returncode != 0:
return None
data = json.loads(r.stdout)
lte = data.get('modem', {}).get('signal', {}).get('lte', {})
return {
'ts': datetime.now().isoformat(),
'rssi': lte.get('rssi', ''),
'rsrp': lte.get('rsrp', ''),
'rsrq': lte.get('rsrq', ''),
'sinr': lte.get('snr', ''),
}
# Sinyal izlemeyi aktifleştir
subprocess.run(['mmcli', '-m', '0', '--signal-setup=10'])
outfile = '/tmp/lte_signal.csv'
with open(outfile, 'w', newline='') as f:
w = csv.DictWriter(f, fieldnames=['ts','rssi','rsrp','rsrq','sinr'])
w.writeheader()
print(f"Sinyal loglanıyor → {outfile} (Ctrl+C ile dur)")
try:
while True:
sig = get_signal()
if sig:
w.writerow(sig)
f.flush()
print(f"[{sig['ts']}] "
f"RSSI={sig['rssi']} RSRP={sig['rsrp']} "
f"RSRQ={sig['rsrq']} SINR={sig['sinr']}")
time.sleep(10)
except KeyboardInterrupt:
print("\nDurduruldu.")
07 SMS via ModemManager
ModemManager üzerinden SMS gönderme ve alma — AT port çakışması olmadan güvenli mesajlaşma.
# SMS oluştur ve gönder
mmcli -m 0 --messaging-create-sms="number='+905001234567',text='Alarm: Sicaklik yuksek!'"
# Successfully created new SMS:
# /org/freedesktop/ModemManager1/SMS/0
# SMS'i gönder
mmcli -m 0 --sms=0 --send
# Successfully sent the SMS
# Gelen SMS'leri listele
mmcli -m 0 --messaging-list-sms
# /org/freedesktop/ModemManager1/SMS/1 (received)
# SMS içeriğini oku
mmcli -m 0 --sms=1
# ---------------------------
# Content | number: +905009876543
# | text: Test mesaji
# ---------------------------
# Properties | pdu type: deliver
# | state: received
# | timestamp: 2026-01-15T10:30:00+03
# SMS sil
mmcli -m 0 --messaging-delete-sms=1
# Yeni SMS bildirimi — D-Bus sinyal izle
dbus-monitor --system \
"type='signal',interface='org.freedesktop.ModemManager1.Modem.Messaging'"
08 Practical — systemd ile boot'ta otomatik 4G bağlantısı
Sistem açıldığında ModemManager'ın modemleri tespit etmesini ve NetworkManager'ın otomatik bağlanmasını sağlayan tam systemd kurulumu.
# 1. NetworkManager için 4G profil oluştur
nmcli connection add \
type gsm \
con-name "4G-IoT" \
ifname "*" \
gsm.apn "internet" \
gsm.pin "" \
connection.autoconnect yes \
connection.autoconnect-priority 100 \
ipv4.method auto \
ipv6.method ignore
# 2. Modem udev kuralı — cihaz gelince MM'yi tetikle
cat /etc/udev/rules.d/99-quectel.rules
# SUBSYSTEM=="usb", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125",
# ACTION=="add", RUN+="/bin/systemctl restart ModemManager"
# 3. ModemManager servis dropin — bağlantı sonrası routing
mkdir -p /etc/systemd/system/ModemManager.service.d
cat > /etc/systemd/system/ModemManager.service.d/override.conf <<'EOF'
[Service]
Environment=MM_LOGGING_LEVEL=INFO
ExecStartPost=/bin/sleep 3
EOF
#!/bin/bash
# 4G bağlantısını güvenli şekilde kur ve doğrula
set -e
LOG="logger -t 4g-connect"
$LOG "4G bağlantı scripti başlıyor..."
# ModemManager başlayana kadar bekle
for i in $(seq 1 30); do
if mmcli -L 2>/dev/null | grep -q Modem; then
$LOG "Modem tespit edildi"
break
fi
sleep 2
done
MODEM_IDX=$(mmcli -L 2>/dev/null | grep -oP '/Modem/\K\d+' | head -1)
if [ -z "$MODEM_IDX" ]; then
$LOG "HATA: Modem bulunamadı"
exit 1
fi
# LTE kaydı bekle (maksimum 120s)
for i in $(seq 1 60); do
STATE=$(mmcli -m "$MODEM_IDX" -J 2>/dev/null | \
python3 -c "import sys,json; \
d=json.load(sys.stdin); \
print(d['modem']['generic']['state'])" 2>/dev/null)
if [ "$STATE" = "registered" ] || [ "$STATE" = "connected" ]; then
$LOG "LTE kayıt OK (durum: $STATE)"
break
fi
$LOG "Bekleniyor: $STATE ($i/60)"
sleep 2
done
# Bağlı değilse bağlan
if [ "$STATE" != "connected" ]; then
$LOG "Bağlantı kuruluyor..."
mmcli -m "$MODEM_IDX" --simple-connect="apn=internet"
sleep 5
fi
# DHCP
IFACE=$(mmcli -m "$MODEM_IDX" --bearer=0 -J 2>/dev/null | \
python3 -c "import sys,json; \
d=json.load(sys.stdin); \
print(d['bearer']['status']['interface'])" 2>/dev/null)
if [ -n "$IFACE" ]; then
$LOG "DHCP: $IFACE"
udhcpc -i "$IFACE" -n -q -t 10
IP=$(ip -4 addr show "$IFACE" | grep -oP '(?<=inet )\S+')
$LOG "IP: $IP"
fi
$LOG "4G bağlantısı hazır"
[Unit]
Description=4G LTE Otomatik Bağlantı
After=ModemManager.service network.target
Wants=ModemManager.service
# Bağlantı kesintisinde yeniden dene
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/4g-connect.sh
Restart=on-failure
RestartSec=30
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
# Script'i çalıştırılabilir yap
chmod +x /usr/local/bin/4g-connect.sh
# Servisi etkinleştir
systemctl enable --now 4g-connect.service
# Log izle
journalctl -fu 4g-connect.service
# Bağlantı durumunu kontrol et
mmcli -m 0 -J | python3 -c "
import sys, json
d = json.load(sys.stdin)
m = d['modem']
print('Durum :', m['generic']['state'])
print('Sinyal:', m['generic']['signal-quality']['value'], '%')
"
# İnternet testi
ping -c 3 -I wwan0 8.8.8.8
NetworkManager olmayan minimal Yocto/Buildroot sistemlerde yukarıdaki script tek başına yeterlidir. ModemManager + mmcli + udhcpc kombinasyonu, NetworkManager'ın %80 işlevselliğini sadece birkaç MB ile sağlar.