Skip to content

Instantly share code, notes, and snippets.

@keyz182
Last active August 21, 2026 19:10
Show Gist options
  • Select an option

  • Save keyz182/96a901d5ba1bf5f4b9701f5eba8729ad to your computer and use it in GitHub Desktop.

Select an option

Save keyz182/96a901d5ba1bf5f4b9701f5eba8729ad to your computer and use it in GitHub Desktop.
UniFi U5G (UCG-Ultra-5G) — SMS send/receive via SSH

UniFi U5G — SMS via SSH

The UniFi UI exposes no SMS interface for the U5G's built-in 5G modem. This documents how SMS send/receive actually works under the hood, accessed over SSH.

Architecture

The U5G uses a Qualcomm MSM integrated modem. Communication happens over:

  • QRTR (Qualcomm IPC Router) — modem is at node qrtr://3
  • SMD (Shared Memory Driver) — AT command port at /dev/smd7
  • uiwwand — Ubiquiti's proprietary WWAN daemon that owns both interfaces

Daemons

/usr/bin/uiwwand          # main WWAN daemon; owns QMI + AT; exposes /var/run/uiwwand.sock
/usr/bin/uiwwand-agent    # companion agent
/usr/libexec/qmi-proxy    # libqmi proxy (abstract socket @qmi-proxy)
/bin/sh modem_watchdog.sh # watchdog loop

Config lives in /etc/mbbcfg/. Key file: /etc/mbbcfg/uiwwand_cfg.sh

QMI_IFACE="qrtr://3"
AT_IF="/dev/smd7"

Reading SMS

uiwwand stores received SMS in memory. Query via ubus:

ubus call uiwwand call '{"method":"get-sms","params":{}}'

Example response:

{
  "result": {
    "sms": [
      {
        "id": "<ICCID>-<hex_timestamp>-<seq>",
        "from": "SenderName",
        "text": "Message body here",
        "timestamp": 1783531498,
        "iccid": "<YOUR_ICCID>"
      }
    ]
  }
}

SMS are also logged to syslog on receipt:

logread | grep -i sms
# Wed Jul  8 16:24:58 2026 user.notice root: Received SMS SenderName: Message body here

Incoming SMS hook

On receipt, uiwwand calls /etc/mbbcfg/uiwwand_event.sh sms with JSON on stdin. That script fires a UniFi controller alert (EVT_MBB_SMS) visible in Network → Notifications. Relevant section of the script:

[ "$1" == "sms" ] && {
    sms="$(cat -)"
    json_init
    if json_load "$sms"; then
        json_get_var sms_id id
        json_get_var sms_from from
        json_get_var sms_text text
        json_get_var sms_timestamp timestamp
        json_get_var sms_iccid iccid

        mca-custom-alert.sh -k "event_string" -v "EVT_MBB_SMS" \
                            -k "id" -v "$sms_id" \
                            -k "from" -v "$sms_from" \
                            -k "text" -v "$escaped_sms_text" \
                            -k "timestamp" -v "$sms_timestamp" \
                            -k "iccid" -v "$sms_iccid" &

        logger "Received SMS $sms_from: $sms_text"
    fi
}

You can hook into this by modifying that script (it's on the read-write partition).


Sending SMS

ubus call uiwwand call '{"method":"send-sms","params":{"to":"+447700900000","text":"Hello from U5G"}}'
  • to — E.164 phone number (required)
  • text — message body (required; max length enforced by modem firmware)
  • iccid — optional; defaults to active SIM

A missing required param returns {"error": -1} immediately. A valid call attempts actual transmission (may time out if no network response within the ubus timeout window — the send itself still goes through).


AT Commands

The AT interface is /dev/smd7. Access via Ubiquiti's own chat tool:

uiwwand-chat -t <timeout_seconds> "AT+COMMAND"

Useful queries:

uiwwand-chat -t 5 "AT+CIMI"    # IMSI
uiwwand-chat -t 5 "AT+CEREG?"  # EPS (LTE) registration status
uiwwand-chat -t 5 "AT+CSQ"     # signal strength
uiwwand-chat -t 5 "AT+CSMS=0"  # SMS capability (+CSMS: 1,1,1 = send+receive supported)
uiwwand-chat -t 5 "AT+CSCA?"   # SMS service centre number
uiwwand-chat -t 5 "AT+CMGF=1"  # set text mode
uiwwand-chat -t 5 'AT+CMGL="ALL"'  # list stored SMS (ME storage)

Note: socat/microcom/nc are not installed. uiwwand-chat is the only AT interface tool available by default.


QMI Direct (read-only queries)

# IMEI
qmicli -d qrtr://3 --dms-get-ids

# UIM / SIM card status (slot, eSIM, ICCID, PIN state)
qmicli -d qrtr://3 --uim-get-card-status

# LTE registration + voice/IMS capability
qmicli -d qrtr://3 --nas-get-system-info

# Home network (MCC/MNC/carrier name)
qmicli -d qrtr://3 --nas-get-home-network

# WMS SMS routes
qmicli -d qrtr://3 --wms-get-routes

MSISDN query (--dms-get-msisdn) returns NotProvisioned — carriers often don't write the phone number to the SIM. See Phone Number below.


Phone Number

The MSISDN is not stored on the SIM (AT+CNUM errors, EF_MSISDN is empty, QMI DMS returns NotProvisioned). This is normal for eSIMs and many mobile broadband SIMs.

To find your number:

  1. Log into your carrier's account portal — it's in their system against your ICCID.
  2. Have another phone text the SIM; the number will show on their end.
  3. USSD query (AT+CUSD=1,"*#100#") — works on some carriers but may return no network service if USSD over IMS isn't supported.

Full uiwwand CTL API

All methods accessible via:

ubus call uiwwand call '{"method":"<method>","params":{...}}'
Method Description
get-sms List received SMS
send-sms Send SMS (to, text params)
get-sim-state SIM present/active, ICCID, EID, MCC/MNC, SPN, PIN state
get-device-info IMEI, modem firmware version
get-modem-state Modem availability
get-radio-status Current radio/band info
get-radio-cap Radio capabilities
get-radio-pref Radio preferences (band/mode)
set-radio-pref Set radio preferences
get-ip-settings WAN IP config
get-usage Data usage counters
get-home-network MCC/MNC/carrier
get-cell-tower-info Cell ID, TAC, signal
get-cell-tower-info-nrf NR (5G) cell info
get-network-scan Scan for available networks
get-loc-position GPS/location fix
get-loc-state Location service state
get-loc-config Location config
set-loc-config Set location config
get-operation-mode Modem operating mode
get-profile APN profile
get-default-profile Default APN
get-profile-default Profile defaults
add-profile Add APN profile
delete-profile Delete APN profile
get-sim SIM info
get-sim-config SIM configuration
add-sim Add SIM/eSIM
delete-sim Remove SIM/eSIM
get-thresholds Data/signal thresholds
get-state Overall state
get-config-info Config info
set-config-profile Set config profile
get-selected-config Selected PDC config
get-peak-speeds Peak speed caps
get-log-debug Debug log level
set-log-debug Set debug log level
get-best-available-position Best GPS fix
set-good / set-bad Modem health markers

Notes

  • All these calls work from the SSH session as the logged-in user; no sudo needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment