System beep do script Python rc.local-scheduled

2

Consegui criar um script Python para aceitar furtos de cartão magnético de um leitor baseado em USB. Parece funcionar como esperado. Parte da rotina é um comando curl para enviar os dados para outro servidor. Como o servidor Ubuntu não terá um monitor / teclado / mouse, minha única maneira de responder ao usuário é com o som do alto-falante do servidor.

Normalmente, o comando curl obtém uma resposta padrão 200 do outro servidor de aplicativos. Às vezes, no entanto, ele recebe uma resposta de 500 erros e eu preciso comunicar algo ao usuário para alertá-los de que "desta vez não funcionou, por favor, escaneie seu cartão novamente".

Um mecanismo simples é soar uma vez para o sucesso e nada para o fracasso. Como escrito e executado a partir de um terminal, funciona. Conforme agendado de rc.local , o bipe do sistema não soa.

...
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)

E eu tentei criar um script de shell simples beep.sh:

#!/bin/bash
echo "\a"

Como mencionado, as duas tentativas funcionam no terminal, mas não na raiz do controle rc.local . E eu sei que a API está sendo chamada desde que eu possa ver as entradas de log.

A linha em rc.local tem esta aparência:

python '/home/myuser/scancards.py'

Existe uma maneira de permitir que este comando - como executado dentro do processo init.d - seja capaz de emitir um sinal sonoro?

    
por Justin Case 12.10.2016 / 23:29

4 respostas

2

Instale o bipe com sudo apt install beep (use o apt-get em vez do apt para versões anteriores a 16.04)

Como o bipe suporta diferentes freqüências, você pode simplesmente beep -f "$r.statuscode" or beep once for yes beep -r1 and twice for no beep -r2 '.

Se por alguma razão desconhecida você não conseguir mais do que um bipe, você pode utilizar a chave -f para ajustar a freqüência para obter, por exemplo, um tom mais baixo para não e um tom mais alto para sim.

Exemplos:

Não: beep -f 250

Sim: beep -f 2500

Sim, sei que é uma resposta curta, mas às vezes é tudo o que é necessário.

mais pesquisas indicam que você terá que comentar a lista negra de pcspkr em /etc/modprobe.d/blacklist.conf para fazer isso funcionar. você também pode ter que configurar o bit suid no beep para que isso funcione (eu usei sudo chmod 4755 /usr/bin/beep porque eu não tenho dúvidas sobre os outros que tocam com beep neste sistema) você pode querer usar grupos para ajustar as permissões de modo que somente usuários dignos possam executar um bipe.

Nota: Como @JdeBP aponta em sua resposta, você pode ter que abrir um descritor de arquivo para um dispositivo de terminal

Fontes:   man beep

Preparando o alto-falante do PC para bip

link

    
por Elder Geek 12.10.2016 / 23:52
1
  

como executado dentro do processo init.d

Não existe um "processo init.d".

rc.local faz parte de um sistema rc que foi substituído três vezes. Esse sistema foi substituído por van Smoorenburg rc , upstart (há uma década) e (como na versão 15 do Ubuntu) systemd. O que você está usando é uma terceira correção de compatibilidade com versões anteriores.

Nos sistemas operacionais systemd, como as versões 15 e posteriores do Ubuntu, o shim é um serviço systemd, denominado rc-local.service . Você pode descobrir sua definição de serviço com

systemctl cat rc-local.service

Como você pode ver, não é definido como anexar o serviço a um dispositivo terminal. O processo de serviço não é executado com um terminal de controle e suas entradas e saídas padrão não estão conectadas a um terminal.

Esse código python e o script de shell não "apita o alto-falante do PC". Eles escrevem o caractere # 7 para suas saídas padrão. Isso acontece quando você os executa interativamente em sua sessão de login que o dispositivo que é sua saída padrão interpreta o caractere # 7 como uma instrução para fazer um ruído. Redirecione a saída padrão do comando interativo para /dev/null e observe como o código fica silencioso.

É por isso que o fato de o shim de compatibilidade com versões anteriores rc.local (very) não ter conexão com um dispositivo de terminal é importante.

Você pode resolver isso com o utilitário beep . Isso tenta (se invocado apropriadamente) abrir explicitamente um descritor de arquivo em um dispositivo terminal e enviar o caractere # 7 para (ou usar console ou evdev ioctl() s em) esse dispositivo, em vez de simplesmente assumir que a saída padrão é um dispositivo terminal.

Mas vale a pena pensar bastante em não usar rc.local também.

Leitura adicional

por JdeBP 14.10.2016 / 15:09
0

Para bipar o alto-falante do pc do script /etc/rc.local Python via console do Linux , você pode usar < href="http://man7.org/linux/man-pages/man4/console_ioctl.4.html"> console_ioctl(4) : KDMKTONE , KIOCSOUND :

#!/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

Veja beep.py . Funciona porque /etc/rc.local é executado por root . Você pode executá-lo como um usuário comum se você possui o terminal , por exemplo, em Ctrl + < kbd> Alt + F1 console virtual (pressione Alt + F7 para retornar ao gerenciador de janelas da GUI).

Certifique-se de que o módulo do kernel pcspkr não esteja na lista negra (comente o padrão):

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

Certifique-se de que pode ser carregado sem erros:

$ sudo modprobe pcspkr

Certifique-se de que /etc/rc.local seja executável:

$ sudo chmod +x /etc/rc.local

print('\a') (escrevendo U+0007 BELL* caractere para stdout) leva a diferentes coisas dependendo do seu ambiente .

Pode reproduzir bell.ogg da amostra carregada utilizando o comando pactl (para o servidor de som PulseAudio) :

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

É provável que o PulseAudio não use o alto-falante do PC para reproduzir o som.

No meu sistema Ubuntu 16.04, print('\a') de /etc/rc.local escreve #007 para /var/log/syslog e emite um bipe no alto-falante do PC ( systemctl cat rc-local.service mostra StandardOutput=journal+console , a saída vai para o arquivo de log e o console) .

    
por jfs 14.10.2016 / 21:53
0

Para bipar o alto-falante do PC de um script Python, você pode usar a API evdev do Linux :

#!/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)

Execute beep-evdev.py como raiz. /etc/rc.local está sendo executado pelo root e, portanto, o script deve funcionar como está.

Se o arquivo /dev/input/by-path/platform-pcspkr-event-spkr não existir, verifique se pcspkr module está carregado:

root# modprobe pcspkr

O script não possui outras dependências, exceto o python em si.

    
por jfs 05.11.2016 / 19:25