进一步阅读

进一步阅读

我设法创建了一个 Python 脚本来接受来自 USB 读卡器的磁卡刷卡。它似乎按预期工作。该例程的一部分是卷曲命令将数据推送到另一台服务器。由于 Ubuntu 服务器没有显示器/键盘/鼠标,因此我响应用户的唯一方式是使用服务器扬声器的声音。

通常情况下,卷曲命令从其他应用服务器获得标准 200 响应。但有时它会获得 500 错误响应,我需要向用户传达一些信息以提醒他们“这次没有成功,请再次扫描您的卡”。

一个简单的机制是成功时发出一次哔哔声,失败时不发出任何声音。按照编写并从终端运行,它可以工作。按照计划从rc.本地,系统提示音不响。

...
args = 'card=' + trackone.group(2)
r = requests.get('http://apiserver/api/', args)
if r.status_code == 200:
    # First attempt which doesn't work from rc.local
    # print("\a")
    # Second attempt, wrap the beep in a shell script
    os.system("sh /home/myuser/beep.sh")
else
    print(r.status_code)

我尝试创建一个简单的 shell 脚本 beep.sh:

#!/bin/bash
echo "\a"

如上所述,两次尝试都可以从终端运行,但不能从 root 运行rc.本地控制。而且我知道 API 正在被调用,因为我可以看到日志条目。

rc.local 中的行如下所示:

python '/home/myuser/scancards.py'

有没有办法让这个命令(在 init.d 进程中运行)能够使扬声器发出蜂鸣声?

答案1

安装 beep sudo apt install beep(对于 16.04 之前的版本,请使用 apt-get 而不是 apt)

由于 beep 支持不同的频率,您可以简单地beep -f "$r.statuscode" or beep once for yesbeep -r1 and twice for nobeep -r2`。

如果由于某些未知原因您无法获得多于一声哔声,您可以利用 -f 开关来调整频率,例如,获得表示“否”的较低音调和表示“是”的较高音调。

例子:

不:beep -f 250

是的:beep -f 2500

是的,我知道这是一个简短的回答,但有时这就是所需要的全部。

进一步的研究表明,您必须在 /etc/modprobe.d/blacklist.conf 中注释掉黑名单 pcspkr 才能使其工作。您可能还必须在 beep 上设置 suid 位才能使其工作(我曾经这样做过,sudo chmod 4755 /usr/bin/beep因为我不担心其他人在这个系统上使用 beep),您可能希望使用组来调整权限,以便只有有资格的用户才能执行 beep。

注意:正如@JdeBP在他的回答中指出的那样,你可能必须打开文件描述符到终端设备

资料来源: man beep

让电脑扬声器发出蜂鸣声

http://pubs.opengroup.org/onlinepubs/9699919799/

答案2

在 init.d 进程中运行

不存在“init.d 进程”这样的东西。

rc.localrc是已被取代三次的系统的一部分。该系统已被 van Smoorenburg rc、upstart(十年前)和(自 Ubuntu 版本 15 起)systemd 取代。您使用的是第三代向后兼容垫片。

在 systemd 操作系统(例如 Ubuntu 15 及更高版本)上,shim 是一个名为 的 systemd 服务rc-local.service。您可以使用以下命令查找其服务定义

systemctl cat rc-local.service

可以看出,它没有定义为将服务附加到终端设备。服务进程不是通过控制终端运行的,其标准输入和输出也没有连接到终端。

该 Python 代码和 Shell 脚本不要“使 PC 扬声器发出哔哔声”。它们将字符 #7 写入其标准输出。它正好当您在登录会话中以交互方式运行它们时作为其标准输出的设备将字符 #7 解释为发出噪音的指令。将交互式命令的标准输出重定向到,/dev/null并观察代码变得多么安静。

rc.local这就是为什么(非常)向后兼容的垫片与终端设备没有连接这一事实很重要。

您可以使用beep实用程序解决此问题。该实用程序尝试(如果正确调用)显式打开终端设备的文件描述符,并将字符 #7 发送到ioctl()该设备(或在该设备上使用 console 或 evdev ),而不是简单地假设标准输出是终端设备。

但同样值得我们认真思考是否不使用rc.local

进一步阅读

答案3

/etc/rc.local通过 Python 脚本让 PC 扬声器发出蜂鸣声Linux 控制台,你可以使用console_ioctl(4)KDMKTONEKIOCSOUND

#!/usr/bin/env python
import os    
from fcntl import ioctl

CLOCK_TICK_RATE = 1193180 # magic https://github.com/johnath/beep/blob/0d790fa45777896749a885c3b93b2c1476d59f20/beep.c#L31-L49
KDMKTONE = 0x4B30   # generate tone include/uapi/linux/kd.h#L25

def beep(console_fd, frequency=440, length_millis=200):
    period = CLOCK_TICK_RATE // frequency
    ioctl(console_fd, KDMKTONE, (length_millis << 16) | period) # start beeping
    # return immediately

beep(console_fd=os.open('/dev/tty0', os.O_RDONLY | os.O_NOCTTY)) # I'm [G]root

beep.py。它之所以有效是因为/etc/rc.local由 执行root。你可以以普通用户身份运行它如果你拥有终端例如,在Ctrl++Alt虚拟F1控制台中(按Alt+F7切换回您的 GUI 窗口管理器)。

确保pcspkr内核模块没有被列入黑名单(注释掉默认值):

$ sudo sed -i 's/^blacklist pcspkr/#blacklist pcspkr/' /etc/modprobe.d/blacklist.conf

确保它可以无错误地加载:

$ sudo modprobe pcspkr

确保/etc/rc.local可执行:

$ sudo chmod +x /etc/rc.local

print('\a')(将U+0007 BELL*字符写入标准输出)导致取决于你的环境

它可以播放bell.ogg使用pactl命令(用于 PulseAudio 声音服务器)

$ pactl upload-sample /usr/share/sounds/ubuntu/stereo/bell.ogg bell.ogg

PulseAudio 很可能不使用电脑扬声器播放声音。


在我的 Ubuntu 16.04 系统上,print('\a')/etc/rc.local写入并#007发出/var/log/syslog蜂鸣声到电脑扬声器(systemctl cat rc-local.service显示StandardOutput=journal+console即输出到日志文件和控制台)。

答案4

要通过 Python 脚本让 PC 扬声器发出蜂鸣声,你可以使用Linux evdev API

#!/usr/bin/env python
import ctypes
import math
import os
import time


EV_SND = 0x12  # linux/input-event-codes.h
SND_TONE = 0x2  # ditto
time_t = suseconds_t = ctypes.c_long

class Timeval(ctypes.Structure):
    _fields_ = [('tv_sec', time_t),       # seconds
                ('tv_usec', suseconds_t)] # microseconds

class InputEvent(ctypes.Structure):
    _fields_ = [('time', Timeval),
                ('type', ctypes.c_uint16),
                ('code', ctypes.c_uint16),
                ('value', ctypes.c_int32)]


frequency = 440  # Hz, A440 in ISO 16
device = "/dev/input/by-path/platform-pcspkr-event-spkr"
pcspkr_fd = os.open(device, os.O_WRONLY)  # root! + modprobe pcspkr
fsec, sec = math.modf(time.time())  # current time
ev = InputEvent(time=Timeval(tv_sec=int(sec), tv_usec=int(fsec * 1000000)),
                type=EV_SND,
                code=SND_TONE,
                value=frequency)
os.write(pcspkr_fd, ev)  # start beep
try:
    time.sleep(0.2)  # 200 milliseconds
finally:
    ev.value = 0  # stop
    os.write(pcspkr_fd, ev)

跑步beep-evdev.py/etc/rc.local以 root 身份运行。 因此脚本应该按原样工作。

如果文件/dev/input/by-path/platform-pcspkr-event-spkr不存在,请确保pcspkr模块已加载:

root# modprobe pcspkr

该脚本除了其自身之外没有其他依赖项python

相关内容