Skip to content

Instantly share code, notes, and snippets.

@hogliux
Last active August 30, 2023 10:22
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hogliux/e7c7f356c59f8711708de8d0ee3c20cd to your computer and use it in GitHub Desktop.
Save hogliux/e7c7f356c59f8711708de8d0ee3c20cd to your computer and use it in GitHub Desktop.
Notes on sms forwarding with huawei E8372h-320 on debian bullseye raspberry pi OS

These notes are based on ethaniel's excellent guide. Please read that guide first and then consult these notes on some changes/tweeks I needed to do to get this running on the newest raspberyr pi OS (January 2023) with a Huawei E8372h-320 (2020 model).

Setup SMS forwarding with gammu on debian bullseye on a rasp pi B+ with the HUAWEI E8372h-320 (2020 model)

First and foremost we need to get the huawei into the correct mode. Unfortunately, usb modeswitch did not do this out-of-the-box for me.

Ensuring that the huawei stick does not switch into an incompatible mode automatically

Blacklist cdc_ether by creating a file /etc/modprobe.d/blacklist-huawei-cdc-usb-net.conf with the following contents:

blacklist cdc_ether

This is not strictly necessary but ensures that no usb0 network interface is created which we will not be using anyway.

For me usb modeswitch had a race condition where, sometimes, just after boot, the huawei stick would automatically switch to a different, incompatible mode, before usb modeswitch had a chance to switch it to the desired target mode (product id 155e). Sometimes the stick would switch first automatically and sometimes usb modeswitch was faster. Once the stick had switched automatically there was no way to switch out of the incompatible state. After some online re-search, it turns out that the huawei stick can detect a linux OS on the way it uses SCSI LUNs (whatever that is?!?) when trying to access the mass storage device. When the huawei detects a linux OS, it will switch to the undesired mode. To work around this race condition, we need to tell linux to ignore the mass storage device altogether. We do this by editing /boot/cmdline.txt and adding the following boot parameters:

usb-storage.quirks=12d1:1f01:i

the 12d1:1f01 are the initial vendor/product ids (when the huawei is still in USB mass storage mode). The i tells linux to ignore the device.

Unfortunately, this is not enough as the default debian installation of usb modeswitch does not correctly switch the huawei stick for me. It switches it yet to another incompatible mode. So, let's first ensure that the stick is not switched to any other mode and just stays in mass storage mode. Do this by disabling automatic running of usb modeswitch by editing /etc/usb_modeswitch.conf and changing:

DisableSwitching=1

Even with the above, systemd also installs a udev rule which will automatically run usb modeswitch. Ensure that this does not happen by deleting the following file sudo rm /usr/lib/udev/rules.d/40-usb_modeswitch.rules.

Reboot!

With the above change, the huawei stick now stays in mass storage mode (i.e. 12d1:1f01) so that we have time to switch it to the desired mode. Check lsusb that the device is indeed in the usb mass storage mode, i.e. vendor/device ids are 12d1:1f01. If not, the rest of the guide will likely not work for you.

Switching to the correct mode

Now that the OS and/or the device does not switch the huawei stick into an incompatible mode, we can now add udev rules to switch it to the correct mode. Create the following udev rule /etc/udev/rules.d/20-huawei-modeswitch.rules with the following contents:

ACTION=="bind", SUBSYSTEM=="usb", ATTR{idVendor}=="12d1", ATTR{idProduct}=="1f01", RUN+="/usr/sbin/usb_modeswitch -v 12d1 -p 1f01 -V 12d1 -P 155e -X"

Now, usb modeswitch will switch the huawei stick into the correct mode. You can test this by either rebooting or by retriggering udev with the following commands:

sudo udevadm control --reload-rules && sudo udevadm trigger

Check lsusb is in the correct mode by checking that the vendor/product id is indeed 12d1:155e. By default, raspberry pi OS contains all the correct drivers (cdc_* and option1 kernel modules) to access the device's serial ports. Double check this by checking that the /dev/ttyUSB0 port is now available. If it is not available then there is something wrong and the rest of the guide will likely not work for you.

Installing and setting up gammu

Let's install gammu. Add the following to /etc/apt/sources.list:

deb http://deb.debian.org/debian bullseye-backports main contrib non-free

Then:

sudo apt update
sudo apt install gammu-smsd

By default, systemd will start the gammu daemon during the boot process. However, the huawei stick will not be in the correct mode yet when gammu starts. So we want to stop and disable gammu for now while we ensure that gammu is only started when the huawei stick is in the correct mode. Disable and stop gammu:

sudo systemctl stop gammu-smsd
sudo systemctl disable gammu-smsd

To ensure that gammu is only started when the huawei stick is in the correct mode, add the following rule in /etc/udev/rules.d/21-huawei-start-gammu.rules to inform systemd about the new device.

ACTION=="bind", DRIVER=="option1", SUBSYSTEM=="usb-serial", GROUP="dialout", TAG+="systemd"

Reboot your device as I could not get the above rule to work by just triggering udev.

As the above udev rule informs systemd about the new device, we can now add systemd dependencies (i.e. services like gammu) to the device (i.e. the /dev/ttyUSB0 device file). This way systemd will automatically start/stop gammu when the device tty appears/disappears respectively. Unfortunately, the device names, that systemd uses, are long and complicated and hard to predict. So we need to find the systemd device name for the /dev/ttyUSB0 port. To figure this out execute the following command:

systemctl list-units --type=device

There will be two entries for each ttyUSB*, use the shorter one. For me it was:

sys-devices-platform-soc-3f980000.usb-usb1-1\x2d1-1\x2d1.2-1\x2d1.2:1.0-ttyUSB0.device

Now edit the gammu systemd file in /usr/lib/systemd/system/gammu-smsd.service and modify the WantedBy= under [Install]. Change it to the above device, for example:

WantedBy=sys-devices-platform-soc-3f980000.usb-usb1-1\x2d1-1\x2d1.2-1\x2d1.2:1.0-ttyUSB0.device

this ensures that gammu is only loaded when the ttyUSB0 device is available.

By default, debian runs the gammu daemon with root permissions. This is a risk, as gammu is no longer actively maintained and contains many bugs. So I also ensured that gammu runs under the gammu user by modifying the [Service] section as follows:

[Service]
RuntimeDirectory=gammu
EnvironmentFile=-/etc/default/gammu-smsd
User=gammu
Group=gammu
ExecStart=/usr/bin/gammu-smsd --pid=/run/gammu/gammu-smsd.pid --daemon
ExecReload=/bin/kill -HUP $MAINPID
ExecStopPost=/bin/rm -f /run/gammu/gammu-smsd.pid
Type=forking
PIDFile=/run/gammu/gammu-smsd.pid

Note: this is why GROUP="dialout" is included in the udev rule quoted further above. Without this, the /dev/ttyUSB0 file will not yet have the correct permissions when gammu starts as a non-root user. Interestingly, systemd will set the group to dialout even without GROUP="dialout", but systemd seems to do this too late, i.e. after starting the gammu service.

We also need to ensure that the spool directory has the correct permissions too:

sudo chown -R gammu:gammu /var/spool/gammu

Then replace /etc/gammu-smsdrc with:

# Configuration file for Gammu SMS Daemon

# Gammu library configuration, see gammurc(5)
[gammu]
port = /dev/ttyUSB0
connection = at
atgen_setCNMI=1,2

# SMSD configuration, see gammu-smsdrc(5)
[smsd]
service = files
logfile = syslog
CheckSecurity = 0
MultipartTimeout=20
debuglevel=0
HangupCalls=1


RunOnReceive=/usr/libexec/smsgateway/gammu.sh

# Paths where messages are stored
inboxpath = /var/spool/gammu/inbox/
outboxpath = /var/spool/gammu/outbox/
sentsmspath = /var/spool/gammu/sent/
errorsmspath = /var/spool/gammu/error

Note that the above atgen_setCNMI=1,2 is super important. Without this line the Huawei E8372h-320 did not work for me. It took me ages to figure this out. Now create the gammu smsgateway script. First create the directory:

sudo mkdir -p /usr/libexec/smsgateway

Then add the gammu.sh file:

#!/bin/bash

TOKEN="<YOUR-TELEGRAM-TOKEN>" # you get this from the @BotFather after creating your bot
CHAT_ID="<YOUR-CHAT-ID>" # you get this from @get_id_bot

# no need to change anything below.

URL="https://api.telegram.org/bot${TOKEN}/sendMessage"

CONTENT=`cat "/var/spool/gammu/inbox/${1}"`
eval "curl -s -X POST $URL -d chat_id=\"${CHAT_ID}\" -d text=\"${CONTENT}\""

and adjust permissions:

chown -R root:gammu /usr/libexec/smsgateway
chmod g+x /usr/libexec/smsgateway/gammu.sh
chmod u+x /usr/libexec/smsgateway/gammu.sh

Now reload systemd

sudo systemctl daemon-reload
sudo systemctl enable gammu-smsd

and reboot (or alternatively reload udev with):

sudo udevadm control --reload-rules && sudo udevadm trigger

gammu should now be running and receiving sms.

Important Note: For me, after every gammu launch, it takes up to 10 minutes for the first text message to arrive after sending it. Subsequent text messages arrived almost instantaneously but the first one seems to take time. This makes debugging issues extremely frustrating and time consuming. Be warned!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment