两个 IoT 应用程序能否同时访问蜂窝调制解调器,这样我就不必终止 ModemManager 并失去互联网连接?

Can two IoT applications access a cellular modem at the same time so I don't have to kill ModemManager and lose my internet connection?

我无法始终从我的调制解调器获取 GPS 数据。通常我可以使用以下代码在 Python 中获取 GPS:

import time
from serial import Serial

# If a "port" is given, then the port will be opened immediately.
ser = Serial(port="/dev/ttyUSB3", timeout=2, write_timeout=2)

# The following prints as "True"
print(ser.is_open)

def read_until_timeout(ser, timeout=5):
    """Turn GPS on and read until either we find the line we want, 
    or the timeout occurs
    """

    # Turn GPS on
    ser.write(b"AT+CGPS=1,1\r\n")

    # Request GPS
    ser.write(b"AT+CGPSINFO=1\r\n")

    # Start the loop
    time_start = time.time()
    while ((time.time() - time_start) < timeout):        
        print("Trying ser.readline().decode('ascii', errors='replace')...")
        try:
            # Read from the serial port
            line = ser.readline().decode('ascii', errors='replace')
        except serial.serialutil.SerialException as err:
            print(f"Problem reading data: {err}")

        if "+CGPSINFO:" in line:
            print(f"Found '+CGPSINFO:' in line: {line}")
            break

在工作网关上,最后的打印语句将 return 一行,如下所示,其中包含 GPS 纬度和经度:

print(read_until_timeout(ser, timeout=5))
>>> '+CGPSINFO: 5100.506298,N,11404.432885,W,031120,234519.0,1080.1,0.0,204.6\r\n'

有时 运行 此函数的输出如下,我认为这只是意味着 GPS 无法获得“修复”:

print(read_until_timeout(ser, timeout=5))
>>> Found '+CGPSINFO:' in line: +CGPSINFO: ,,,,,,,,

但有时它说它“忙”如下:

print(read_until_timeout(ser, timeout=5))
>>> Problem reading data: read failed: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

以上是因为两个以上的应用不能同时访问串口吗?

如果我尝试从 Linux Bash 向调制解调器发送 AT 消息,它说调制解调器“忙”...

$ echo 'AT+CGPSINFO=1' | socat - /dev/ttyUSB3,crnl
>>> 2020/11/20 19:18:24 socat[3251] E open("/dev/ttyUSB3", 02002, 0666): Device or resource busy

所以我检查哪些设备正在使用调制解调器:

$ sudo lsof /dev/ttyUSB3
>>> COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ModemMana  800 root   12u   CHR  188,3      0t0  449 /dev/ttyUSB3
python    1706 root    3u   CHR  188,3      0t0  449 /dev/ttyUSB3

但是,如果我用 sudo kill 800 关闭 ModemManager,蜂窝互联网连接就会中断,我不能这样做,因为这些是远离荒野的远程物联网设备(我有大约 50 个他们在北美各地开展业务)。

有没有办法 与 ModemManager 共享 调制解调器,这样我就可以从 Python 或 shell,在使用移动互联网连接时?

这个问题是相关的,所以我也悬赏一下: https://superuser.com/questions/1455327/trying-to-read-a-serial-port-device-or-resource-busy

2020 年 11 月 22 日更新:

@GitFront 很有帮助 直接使用 ModemManager。很好的建议。 gi 库也很巧妙。

来自 Ubuntu Bash,这是我尝试直接从 ModemManager 获取 GPS 时得到的结果:

user@user-Default-string:~$ mmcli -m 0 --location-status

/org/freedesktop/ModemManager1/Modem/0
  ----------------------------
  Location |   capabilities: '3gpp-lac-ci'
           |        enabled: '3gpp-lac-ci'
           |        signals: 'no'

请注意,在定位功能下,由于某种原因没有 gps-raw, gps-nmea, agps 出现,只有 3gpp-lac-ci,但我知道这个 gateway/SIMCom 7600 调制解调器具有 GPS/GNSS 功能,而且它是正确连接了无源天线。

有谁知道为什么 gps-raw, gps-nmea, agps 没有显示为能力?

我办公室中完全相同的 gateway/modem/antenna 组合确实具有 gps-raw, gps-nmea, agps 功能,并且一切都非常适合它...唯一的区别是 SIM 卡,这应该无关紧要。相比之下,我办公室的网关报告了以下功能:

user@ax1000008:~$ mmcli -m 0 --location-status
  ------------------------
  Location | capabilities: 3gpp-lac-ci, gps-raw, gps-nmea, agps
           |      enabled: 3gpp-lac-ci
           |      signals: no
  ------------------------
  GPS      | refresh rate: 30 seconds

我请求启用 gps-raw, gps-nmea

user@ax1000008:~$ sudo mmcli -m 0 --location-enable-gps-raw --location-enable-gps-nmea
successfully setup location gathering

然后我成功地请求了 GPS(在我办公室的 gateway/modem 上...):

user@ax1000008:~$ sudo mmcli -m 0 --location-get
  --------------------------
  3GPP |      operator code: 302
       |      operator name: 220
       | location area code: 2BC4
       | tracking area code: 0000
       |            cell id: 04B68931
  --------------------------
  GPS  |               nmea:
       |                     $GPGGA,183553.00,5100.511216,N,11404.429721,W,1,06,1.7,1078.0,M,-16.0,M,,*6C
       |                     $GPRMC,183552.00,A,5100.511138,N,11404.429729,W,0.0,341.3,221120,15.4,E,A*10
       |                     $GPGSA,A,2,01,03,21,22,31,32,,,,,,,2.0,1.7,0.9*3C
       |                     $GPGSV,4,1,15,01,45,295,34,03,11,291,29,10,31,109,20,11,,,36*4F
       |                     $GPGSV,4,2,15,12,08,056,19,21,53,258,35,22,33,292,32,23,02,111,15*79
       |                     $GPGSV,4,3,15,25,06,092,22,31,33,163,23,32,70,066,33,08,02,236,*7C
       |                     $GPGSV,4,4,15,17,04,344,,20,,,,24,,,*48
       |                     $GPVTG,341.3,T,325.9,M,0.0,N,0.0,K,A*2B
       |                     $PQXFI,183553.0,5100.511216,N,11404.429721,W,1078.0,9.61,5.64,0.13*4E
       |                utc: 183553.00
       |          longitude: -114.073829
       |           latitude: 51.008520
       |           altitude: 1078.000000

在现场的非工作网关上,这是我尝试启用 gps-rawgps-nmea 时得到的结果:

user@user-Default-string:~$ sudo mmcli -m 0 --location-enable-gps-raw --location-enable-gps-nmea
error: couldn't setup location gathering: 'GDBus.Error:org.freedesktop.ModemManager1.Error.Core.Unsupported: Cannot enable unsupported location sources: 'gps-raw, gps-nmea''

您应该能够利用 ModemManager 获取 GPS 位置,而不是直接获取。这样你就可以避免使用来自两个服务的同一个串口。

有关如何使用 ModemManager 联机帮助页中的 mmcli 工具从命令行执行此操作的文档: https://www.freedesktop.org/software/ModemManager/man/1.0.0/mmcli.8.html#lbBC

还有一个 libmm-glib 库,您应该可以通过 GObject Introspection 从 Python 使用它,而无需 运行 命令行工具。

import gi
gi.require_version('ModemManager', '1.0')
from gi.repository import ModemManager

请记住,您的设备可能无法在数据会话处于活动状态时提供位置 (from the documentation):

The Location interface allows devices to provide location information to client applications. Not all devices can provide this information, or even if they do, they may not be able to provide it while a data session is active.

我想我现在基本上已经弄明白了,而不必终止 ModemManager(这有可能终止 IoT 远程网关上的互联网连接)。

主要的答案是我根本没有得到 GPS 定位(除了权限问题)。

我的 Python 代码没有做错任何事情,有时 ModemManager 使用我发送命令的 AT 端口(/dev/ttyUSB2/dev/ttyUSB3)。 . 将 ModemManager 升级到 v1.10.0 也可能有效,但我不愿意在现场工作的实时网关上这样做。

@rm5248 建议在像我这样的 SIMCom 7600 上使用位于 /dev/ttyUSB1 的专用 NMEA 端口,我认为他是对的。

我使用这个 documentation 安装了 GPSD (GPSDaemon) 和它的各种客户端(例如 cgps 和 gpsmon)。如果 GPS 有修复,GPSD 及其客户端非常适合获取 GPS 信息。

如何测试GPSD软件: https://gpsd.gitlab.io/gpsd/installation.html#_how_to_test_the_software

# Start GPSD on /dev/ttyUSB1 with debug level 5, 
# -N (don't daemonize), and -n (don't wait for 
# client to connect to poll GPS)

# no daemon, for debugging
$ sudo gpsd -D 5 -N -n /dev/ttyUSB1

# daemonized to run in background
$ sudo gpsd -D 5 -n /dev/ttyUSB1

然后 运行 以下两个客户端之一并观察 /dev/ttyUSB1 上的专用 NMEA 端口,而不是 /dev/ttyUSB2/dev/ttyUSB3 上的“AT”端口:

$ cgps
$ gpsmon /dev/ttyUSB1

在正常工作的网关上 cgps 是这样工作的:

gpsmon /dev/ttyUSB1 是这样工作的:

但在非工作网关上 cgps 看起来像这样,显示 NO FIX