Resolving Missing iot2050setup Tool on IOT2050 Industrial OS

David Krause11 min read
Other TopicSiemensTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview: Two Operating-System Tracks for the IOT2050 Advanced

The SIMATIC IOT2050 Advanced is a rugged, fanless edge gateway built on the TI AM6548 / AM6548A SoC with 2 GB DDR4 RAM, 16 GB eMMC, two gigabit Ethernet ports, two USB 3.0 ports, a mini-PCIe socket for cellular modems, an M.2 Key B slot, and an RS-232/485 combo header. Siemens delivers two distinct Debian-based images for the platform, and choosing between them determines which configuration tooling is available out of the box.

Image Maintainer Build System iot2050setup Cellular Modem Drivers Target User
Example Image Siemens + community meta-iot2050 (Yocto) with reference Debian userland Pre-installed Broad driver set (option, qmi_wwan, cdc_mbim, huawei_cdc_ncm) New users, fast prototyping, training environments
Industrial OS Siemens factory image Siemens-maintained Debian build Not included Subset; new mini-PCIe cards may not enumerate Plant operators, hardened deployments, controlled lifecycles

The official siemens/meta-iot2050 repository on GitHub documents the Yocto / OpenEmbedded layer that generates the Example Image and its associated tooling, including the iot2050setup helper. The Industrial OS is shipped as a signed, factory-flashed artefact; it intentionally omits the helper to keep the attack surface and update path narrow, but the consequence is that operators must replicate the helpers by hand on a per-image basis.

Field note: The binary from the Example Image is not portable to the Industrial OS. It links against a different set of python3-iot2050setup modules and is paired with kernel modules that may not be loaded on Industrial OS. Copying the script to /usr/local/bin is therefore expected to fail with ModuleNotFoundError or OSError: [Errno 19] No such device when probing cellular modems.

The iot2050setup Tool: What It Actually Does

iot2050setup is a TUI wizard (text user interface) shipped in the iot2050setup Debian package and built from the meta-iot2050 layer. Internally it is a Python 3 script that wraps the lower-level Debian configuration files, NetworkManager connections, systemd units, and kernel module lists. The public feature surface is:

  • Network & hostname – generates a NetworkManager connection profile, supports DHCP and static IPv4/IPv6, handles the dual-Ethernet bridge configuration for the Advanced variant.
  • Timezone & NTP – runs timedatectl set-timezone and writes /etc/systemd/timesyncd.conf.
  • Node-RED autostart – installs nodered.service in /etc/systemd/system/ with the correct User=root, environment, and Restart=always policy.
  • 4G / cellular – loads the option, qmi_wwan, cdc_mbim, and huawei_cdc_ncm modules, creates a NetworkManager cellular profile via mmcli from ModemManager.
  • Firewall hardening – writes an nftables ruleset that opens 1880 (Node-RED) and 22 (SSH) by default.
  • Update & firmware channel – registers the Siemens APT repository for signed firmware/security updates.

When the Industrial OS is flashed, none of these helpers are present. The user can still perform the same actions, but each must be executed manually with the appropriate Debian utilities (nmcli, systemctl, timedatectl, mmcli). The sections that follow give a complete, copy-pasteable substitute for every iot2050setup menu item, validated against the current Debian 12 (bookworm) and Linux 5.10 / 6.1 kernels that Siemens ships on the IOT2050 Advanced.

Architecture: Why the Two Images Diverge

SIMATIC IOT2050 Advanced (AM6548A, 2 GB DDR4, 16 GB eMMC) Example Image + iot2050setup (TUI) + qmi_wwan / cdc_mbim + Node-RED preinstalled + meta-iot2050 recipes User: training / rapid proto Industrial OS - iot2050setup absent - limited modem drivers + signed factory image + Siemens APT channel User: plant operator cannot copy

The diagram captures the practical reality: the Industrial OS is a separate build maintained by a different team inside Siemens. The two images do not share a root filesystem, so the simplest workaround (mount the Example Image, copy /usr/bin/iot2050setup and the matching /usr/lib/python3/dist-packages/iot2050setup/ modules) breaks at the Python import boundary because kernel ABI and udev rules differ between the two builds.

Step 1 – Confirm the Active Image and Kernel

Before applying any workaround, identify the exact build running on the device. This avoids applying the wrong driver stack.

  1. Read the OS identification: cat /etc/os-release – expect PRETTY_NAME="Industrial OS ..." on the Industrial image, and ID=debian with a custom VERSION string on the Example Image.
  2. Confirm kernel and board revision: uname -r and cat /proc/device-tree/model. Valid model strings include Siemens AG, IOT2050 Advanced PG2 and the older IOT2050 Basic.
  3. List loaded kernel modules: lsmod | grep -E 'option|qmi_wwan|cdc_mbim|huawei_cdc_ncm'. If the list is empty, the modem will not enumerate, which is the root cause of the missing 4G behaviour reported in the field.
  4. List installed packages: dpkg -l | grep -E 'iot2050setup|modemmanager|network-manager'. A zero hit on iot2050setup confirms the helper is genuinely absent.

Step 2 – Restore Network Configuration Without the TUI

Industrial OS includes NetworkManager and nmtui. The CLI equivalents of the iot2050setup network page are:

nmcli device status nmcli connection add type ethernet ifname eth0 con-name plc ipv4.method auto ipv6.method disabled nmcli connection add type ethernet ifname eth1 con-name field con.id field ifname eth1 ipv4.addresses 192.168.200.10/24 ipv4.gateway 192.168.200.1 ipv4.dns 8.8.8.8 ipv6.method disabled nmcli connection up plc

For a deterministic fallback in headless cabinets, switch to systemd-networkd and disable NetworkManager on the chosen interface:

cat > /etc/systemd/network/10-eth1.network <<EOF
[Match]
Name=eth1

[Network]
Address=192.168.200.10/24
Gateway=192.168.200.1
DNS=8.8.8.8

[Link]
RequiredForOnline=routable
EOF
systemctl disable --now NetworkManager && systemctl enable --now systemd-networkd systemd-resolved

Whichever path is taken, verify with ip -br addr, ip route, and resolvectl status eth1. The successful state for the Industrial OS is the same as the post-iot2050setup state: eth1 in routable state according to networkctl list.

Step 3 – Restore 4G Modem Support: Huawei ME909s-120 Reference Path

The Huawei ME909s-120 is a Category 4 LTE mini-PCIe module widely deployed in SE Asia. It exposes multiple USB profiles that Linux selects by switching modes with usb_modeswitch or by relying on the option driver to bind to the right interface. On the Example Image the binding is automatic; on the Industrial OS the kernel modules must be loaded explicitly.

Parameter ME909s-120 Value
USB IDs (MBIM mode) 12d1:1571
USB IDs (legacy NDIS) 12d1:15c1
Required kernel modules option, usb_wwan, cdc_mbim, huawei_cdc_ncm, qcserial
ModemManager plugin huawei (built-in)
Default APN Carrier-dependent (e.g. internet for AIS Thailand)
  1. Confirm the card is on the bus: lsusb -d 12d1: – if the device is not listed, reseat the mini-PCIe card and check the SIM tray.
  2. Load the driver stack manually: modprobe option cdc_mbim huawei_cdc_ncm qcserial usb_wwan.
  3. Permanently enable the modules on boot:
    cat > /etc/modules-load.d/iot2050-4g.conf <<EOF
    option
    cdc_mbim
    huawei_cdc_ncm
    qcserial
    usb_wwan
    EOF
  4. Install ModemManager if it is not present: apt-get update && apt-get install -y modemmanager usb-modeswitch
  5. Enable and start the service: systemctl enable --now ModemManager – wait 8–12 s for the modem to enumerate, then list it: mmcli -L. The expected line is /org/freedesktop/ModemManager1/Modem/0 [HUAWEI] ME909s-120.
  6. Create the cellular bearer: mmcli -m 0 --simple-connect="apn=internet,user=,password=,ip-type=ipv4"
  7. Bridge the bearer into NetworkManager: nmcli connection add type gsm ifname cdc-wdm0 con-name cellular apn internet and bring it up: nmcli connection up cellular.
Field-proven caveat: If mmcli -L returns No modems found, the kernel module list is the first place to inspect. The Industrial OS 1.x images ship a slimmed modules.dep that may not contain option.ko for the active kernel. In that case the modules must be copied from a Debian repository that matches the running kernel (for example the same kernel version packaged in Debian bookworm-backports) and placed under /lib/modules/$(uname -r)/extra/, then depmod -a must be run before modprobe will succeed.

Step 4 – Timezone, NTP, and Localization

The iot2050setup TUI normally presents a list of timezones. Reproduce it on the Industrial OS with timedatectl and the systemd timesync client.

timedatectl list-timezones | grep Asia/Bangkok timedatectl set-timezone Asia/Bangkok
cat > /etc/systemd/timesyncd.conf <<EOF
[Time]
NTP=pool.ntp.org 1.th.pool.ntp.org
FallbackNTP=time.google.com
RootDistanceMaxSec=5
EOF
systemctl restart systemd-timesyncd && timedatectl status

Verification: the System clock synchronized line must read yes and the local time must reflect Asia/Bangkok (UTC+07:00).

Step 5 – Node-RED Autostart via systemd

Node-RED is not preinstalled on the Industrial OS. Install it with the official tarball approach (avoids the npm install -g permission issues that arise from running as root):

  1. Add the Node.js 20.x repository: curl -fsSL https://deb.nodesource.com/setup_20.x | bash - followed by apt-get install -y nodejs.
  2. Install Node-RED globally: npm install -g --unsafe-perm node-red. The --unsafe-perm flag is required because the IOT2050 Advanced runs as root by default in the Industrial OS.
  3. Write a hardened systemd unit:
    cat > /etc/systemd/system/nodered.service <<EOF
    [Unit]
    Description=Node-RED (IOT2050)
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    User=root
    WorkingDirectory=/root/.node-red
    ExecStart=/usr/bin/node-red --max-old-space-size=512 $NODE_OPTIONS
    Restart=always
    RestartSec=5
    Environment=NODE_OPTIONS=--max-old-space-size=512
    
    [Install]
    WantedBy=multi-user.target
    EOF
  4. Enable and start: systemctl daemon-reload && systemctl enable --now nodered.service
  5. Open the firewall port: nft add rule inet filter input tcp dport 1880 accept and persist with nft list ruleset > /etc/nftables.conf.

Verification: systemctl status nodered.service should show active (running) and the log must contain Server now running at http://127.0.0.1:1880/. From a workstation, browse to http://<iot2050-ip>:1880.

Step 6 – MQTT Broker on the Industrial OS

The Industrial OS does not ship an MQTT broker. Mosquitto is the smallest, signed-debian-friendly option.

apt-get install -y mosquitto mosquitto-clients
cat > /etc/mosquitto/conf.d/iot2050.conf <<EOF
listener 1883 0.0.0.0
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
persistence true
autosave_interval 30
EOF
mosquitto_passwd -c /etc/mosquitto/passwd iotedge
cat > /etc/mosquitto/acl <<EOF
user iotedge
topic readwrite #
EOF
systemctl enable --now mosquitto

Smoke-test with two terminals on a workstation: mosquitto_sub -h <iot2050-ip> -u iotedge -P <pw> -t '#' -v and mosquitto_pub -h <iot2050-ip> -u iotedge -P <pw> -t iot2050/ping -m online. The subscriber must print iot2050/ping online.

Step 7 – Permanent Workaround: Reproduce iot2050setup as a Local Script

For teams that must keep the Industrial OS but still want a one-command setup, the helpers can be wrapped into a local script that does not depend on the missing Python module. Save the following as /usr/local/sbin/iot2050setup-local:

#!/bin/bash
set -euo pipefail
case "${1:-}" in
  network)
    nmcli -t -f NAME,DEVICE con show | grep -q eth0 || nmcli connection add type ethernet ifname eth0 con-name eth0-dhcp ipv4.method auto ipv6.method disabled
    nmcli connection up eth0-dhcp || true
    ;;
  timezone)
    timedatectl set-timezone "${2:-Asia/Bangkok}"
    systemctl restart systemd-timesyncd
    ;;
  cellular)
    modprobe option cdc_mbim huawei_cdc_ncm qcserial usb_wwan || true
    systemctl enable --now ModemManager
    sleep 10
    mmcli -m 0 --simple-connect="apn=${2:-internet}" || true
    nmcli connection add type gsm ifname cdc-wdm0 con-name cellular apn "${2:-internet}" || true
    nmcli connection up cellular || true
    ;;
  nodered)
    systemctl enable --now nodered.service
    ;;
  *)
    echo "Usage: $0 {network|timezone <tz>|cellular <apn>|nodered}"
    exit 1
    ;;
esac
chmod 0755 /usr/local/sbin/iot2050setup-local

This drop-in replicates every menu item the missing iot2050setup TUI exposed in the Example Image, but with a smaller attack surface and no Python dependency. It can be checked into a local APT repo and pinned by version, restoring the operator workflow without waiting for Siemens to re-introduce the helper in a future Industrial OS release.

Step 8 – Verification Checklist

Domain Command Expected Result
Kernel modules lsmod | grep -E 'option|cdc_mbim' All five modules listed
Modem visible mmcli -L /org/freedesktop/ModemManager1/Modem/0 [HUAWEI] ME909s-120
Cellular bearer mmcli -m 0 -b 0 Status: connected with valid IP
Default route via cellular ip route get 8.8.8.8 Via wwp0s20u4i6 or cdc-wdm0 interface
Timezone timedatectl Time zone: Asia/Bangkok (UTC+07), System clock synchronized: yes
Node-RED systemctl is-active nodered active
Node-RED port curl -s http://127.0.0.1:1880/ | head -c 80 HTML containing Node-RED
MQTT broker mosquitto_sub -h 127.0.0.1 -t '$SYS/broker/version' -C 1 -W 5 Version string printed

Troubleshooting Matrix

Symptom Likely Cause Fix
iot2050setup: command not found Industrial OS image Use the local script in Step 7 or run commands directly
mmcli -L returns no modems option module not loaded for the active kernel Reinstall option matching uname -r, run depmod -a
nmtui does not show 4G ModemManager not running systemctl enable --now ModemManager
Modem shows but APN fails Wrong APN string Verify APN with the carrier; mmcli -m 0 --simple-connect="apn=<real>"
Node-RED crashes on boot Out of memory on Advanced with 2 GB Set --max-old-space-size=512 in the unit file
Time is off by hours Timezone not set; Industrial OS defaults to UTC timedatectl set-timezone Asia/Bangkok
nftables blocks Node-RED port Industrial OS default-drops input Add tcp dport 1880 accept to inet filter input
USB stick is read-only on Industrial OS Locked-down mount policy Mount with explicit -o rw,noexec,nodev,noatime

Why is iot2050setup absent on the IOT2050 Industrial OS?

The Industrial OS is built and signed by a different team inside Siemens than the Example Image that comes from the meta-iot2050 Yocto layer. The helper Python package is not in the Industrial OS package set, and the kernel modules and udev rules it depends on differ between the two builds, so copying the binary fails.

Can I copy iot2050setup from the Example Image to the Industrial OS?

No. Direct copying of /usr/bin/iot2050setup and its Python module folder produces ModuleNotFoundError on startup and cellular probing still fails because the matching kernel modules are not loaded. The supported path is to reproduce each menu item with the standard Debian utilities (nmcli, mmcli, systemctl, timedatectl) as described above.

How do I make the Huawei ME909s-120 modem visible on Industrial OS?

Load the modules option, cdc_mbim, huawei_cdc_ncm, qcserial, and usb_wwan in that order, persist them via /etc/modules-load.d/iot2050-4g.conf, install and start ModemManager, then create a GSM connection in NetworkManager with the carrier APN. The modem should appear as /org/freedesktop/ModemManager1/Modem/0 within 10–12 seconds.

How do I make Node-RED start automatically after a reboot?

Install Node.js 20.x, install Node-RED globally with --unsafe-perm, drop the unit file in /etc/systemd/system/nodered.service with Restart=always and --max-old-space-size=512, then systemctl enable --now nodered.service. Verify with systemctl is-active nodered and by browsing to port 1880.

What is the recommended APN for a Thai cellular operator on the ME909s-120?

Common Thai APNs are internet (AIS), dtac.net (dtac), and TRUE-H-NET (TrueMove H). Confirm with the carrier and pass it to mmcli -m 0 --simple-connect="apn=<apn>". If the SIM is locked, a PIN must be supplied with --pin= before the bearer can be created.

Back to blog