Add Adafuit Macropad serial connection article
This commit is contained in:
parent
4345e877fa
commit
eff6e3b6e5
7 changed files with 627 additions and 0 deletions
|
@ -0,0 +1,47 @@
|
||||||
|
from adafruit_macropad import MacroPad
|
||||||
|
import usb_cdc
|
||||||
|
import time
|
||||||
|
|
||||||
|
macropad = MacroPad()
|
||||||
|
serial = usb_cdc.data
|
||||||
|
|
||||||
|
def exec_command (data):
|
||||||
|
global timer
|
||||||
|
try:
|
||||||
|
command,option = data.split()
|
||||||
|
except:
|
||||||
|
command = ""
|
||||||
|
option = ""
|
||||||
|
print("cmd: {} | opt: {}".format(command, option))
|
||||||
|
if command == 'time':
|
||||||
|
timer = float(option)
|
||||||
|
print("new timer: {}".format(timer))
|
||||||
|
response = "nouveau timer : {}\r\n".format(option)
|
||||||
|
buffer = bytearray(response)
|
||||||
|
serial.write(buffer)
|
||||||
|
|
||||||
|
def blink(led, light):
|
||||||
|
print('light: {}'.format(light))
|
||||||
|
if light:
|
||||||
|
macropad.pixels[led] = (33, 45, 230)
|
||||||
|
else:
|
||||||
|
macropad.pixels[led] = (0, 0, 0)
|
||||||
|
print('c: {}'.format(macropad.pixels[led]))
|
||||||
|
return False if light else True
|
||||||
|
|
||||||
|
timer=2
|
||||||
|
light=False
|
||||||
|
in_data=bytearray()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
light = blink(1, light)
|
||||||
|
time.sleep(timer)
|
||||||
|
|
||||||
|
if serial.in_waiting > 0:
|
||||||
|
while(serial.in_waiting>0):
|
||||||
|
byte = serial.read(1)
|
||||||
|
if byte == b'\r':
|
||||||
|
exec_command(in_data.decode("utf-8"))
|
||||||
|
in_data = bytearray()
|
||||||
|
else:
|
||||||
|
in_data += byte
|
|
@ -0,0 +1,5 @@
|
||||||
|
import usb_cdc
|
||||||
|
try:
|
||||||
|
usb_cdc.enable(console=True, data=True) # Enable console and data# Write your code here :-)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
|
@ -0,0 +1,44 @@
|
||||||
|
from adafruit_macropad import MacroPad
|
||||||
|
import usb_cdc
|
||||||
|
import time
|
||||||
|
|
||||||
|
macropad = MacroPad()
|
||||||
|
serial = usb_cdc.data
|
||||||
|
|
||||||
|
def exec_command (data):
|
||||||
|
global timer
|
||||||
|
try:
|
||||||
|
command,option = data.split()
|
||||||
|
except:
|
||||||
|
command = ""
|
||||||
|
option = ""
|
||||||
|
print("cmd: {} | opt: {}".format(command, option))
|
||||||
|
if command == 'time':
|
||||||
|
timer = float(option)
|
||||||
|
print("new timer: {}".format(timer))
|
||||||
|
|
||||||
|
def blink(led, light):
|
||||||
|
print('light: {}'.format(light))
|
||||||
|
if light:
|
||||||
|
macropad.pixels[led] = (33, 45, 230)
|
||||||
|
else:
|
||||||
|
macropad.pixels[led] = (0, 0, 0)
|
||||||
|
print('c: {}'.format(macropad.pixels[led]))
|
||||||
|
return False if light else True
|
||||||
|
|
||||||
|
timer=2
|
||||||
|
light=False
|
||||||
|
in_data=bytearray()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
light = blink(1, light)
|
||||||
|
time.sleep(timer)
|
||||||
|
|
||||||
|
if serial.in_waiting > 0:
|
||||||
|
while(serial.in_waiting>0):
|
||||||
|
byte = serial.read(1)
|
||||||
|
if byte == b'\r':
|
||||||
|
exec_command(in_data.decode("utf-8"))
|
||||||
|
in_data = bytearray()
|
||||||
|
else:
|
||||||
|
in_data += byte
|
|
@ -0,0 +1,45 @@
|
||||||
|
from adafruit_macropad import MacroPad
|
||||||
|
import usb_cdc
|
||||||
|
import time
|
||||||
|
|
||||||
|
macropad = MacroPad()
|
||||||
|
serial = usb_cdc.data
|
||||||
|
|
||||||
|
def exec_command (data):
|
||||||
|
global muted
|
||||||
|
try:
|
||||||
|
print(data)
|
||||||
|
command,option = data.split()
|
||||||
|
except:
|
||||||
|
command = ""
|
||||||
|
option = ""
|
||||||
|
print("cmd: {} | opt: {}".format(command, option))
|
||||||
|
if command == 'mute':
|
||||||
|
muted = True if option == 'yes' else False
|
||||||
|
print('muted: {}'.format(muted))
|
||||||
|
|
||||||
|
timer=2
|
||||||
|
in_data=bytearray()
|
||||||
|
muted=False
|
||||||
|
|
||||||
|
while True:
|
||||||
|
key_event = macropad.keys.events.get()
|
||||||
|
if muted:
|
||||||
|
macropad.pixels[1] = (255,0,0)
|
||||||
|
else:
|
||||||
|
macropad.pixels[1] = (0,255,0)
|
||||||
|
|
||||||
|
if key_event:
|
||||||
|
if key_event.pressed:
|
||||||
|
if key_event.key_number == 1:
|
||||||
|
print('get key 1')
|
||||||
|
serial.write(bytearray('mute\r\n'))
|
||||||
|
|
||||||
|
if serial.in_waiting > 0:
|
||||||
|
while(serial.in_waiting > 0):
|
||||||
|
byte = serial.read(1)
|
||||||
|
if byte == b'\r':
|
||||||
|
exec_command(in_data.decode("utf-8"))
|
||||||
|
in_data = bytearray()
|
||||||
|
else:
|
||||||
|
in_data += byte
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import serial
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
ser = serial.Serial(port='/dev/ttyACM1')
|
||||||
|
|
||||||
|
ser.flushInput()
|
||||||
|
print('Begin loop')
|
||||||
|
while True:
|
||||||
|
line = ser.readline()
|
||||||
|
try:
|
||||||
|
command = (line.decode()).split()
|
||||||
|
print('command received: {}'.format(command[0]))
|
||||||
|
except:
|
||||||
|
print('no valid command received')
|
||||||
|
command = ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
if command[0] == "mute":
|
||||||
|
# First subprocess for toggle mote the microphone
|
||||||
|
subprocess.run(
|
||||||
|
['pactl', 'set-source-mute', '@DEFAULT_SOURCE@', 'toggle'],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Second one for check the states of microphone
|
||||||
|
result = subprocess.run(
|
||||||
|
['pactl', 'get-source-mute', '@DEFAULT_SOURCE@'],
|
||||||
|
capture_output=True
|
||||||
|
)
|
||||||
|
message = "mute {}\r".format(result.stdout.split()[1].decode())
|
||||||
|
ser.write(message.encode())
|
||||||
|
print('command sent: {}'.format(message))
|
||||||
|
except Error as e:
|
||||||
|
print('Error in command: {}'.format(e))
|
Binary file not shown.
After Width: | Height: | Size: 169 KiB |
452
content/articles/2023/adafruit_macropad_conn_serie/index.md
Normal file
452
content/articles/2023/adafruit_macropad_conn_serie/index.md
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
Title: Jouer avec le Macropad Adafruit! mais en série
|
||||||
|
Category: linux
|
||||||
|
Tags: Adafruit, CircuitPython, Python
|
||||||
|
Date: 2023-02-26 18:10
|
||||||
|
status: hidden
|
||||||
|
|
||||||
|
Le Macropad Adafruit est un petit clavier de 12 touches rétroéclairées avec un
|
||||||
|
écran OLED et un sélecteur. Il est motorisé par un Raspberry Pi RP2040.
|
||||||
|
|
||||||
|
Dans cet article, nous allons voir comment utiliser ce clavier et communiquer
|
||||||
|
avec via l'utilisation du port série.
|
||||||
|
|
||||||
|
## Circuitpython
|
||||||
|
|
||||||
|
Comme beaucoup de carte électronique à base de micro controlleurs, ce clavier
|
||||||
|
est compatible avec l'écosystème Arduino, il est donc possible de le programmer
|
||||||
|
en C. Il existe aussi un firmware embarqant [CircuitPython][l_circuitp], couplé
|
||||||
|
aux diférentes bibliothèques [fournies par Adafuit][l_circuitp_ada], il est
|
||||||
|
possible d'utiliser *Python* pour le programmer. C'est **ce que nous allons
|
||||||
|
utiliser ici**.
|
||||||
|
|
||||||
|
La documentation sur l'installation du firmware *CyrcuitPython* pour le Macropad
|
||||||
|
est disponible sur le site [d'Adafuit][l_ada_macropad]
|
||||||
|
|
||||||
|
[l_circuitp]:https://circuitpython.org/
|
||||||
|
[l_circuitp_ada]:https://github.com/adafruit/Adafruit_CircuitPython_MacroPad
|
||||||
|
[l_ada_macropad]:https://learn.adafruit.com/adafruit-macropad-rp2040/circuitpython
|
||||||
|
|
||||||
|
## Préparer l'environnement
|
||||||
|
|
||||||
|
Sur notre ordinateur nous allons préparer un *environnement virtuel Python* pour
|
||||||
|
y installer `circup`, module Python permettant d'installer le nécessaire **sur
|
||||||
|
le Macropad**:
|
||||||
|
|
||||||
|
```
|
||||||
|
python -m venv ~/venv_circup
|
||||||
|
source ~/venv_circup/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
Puis après avoir branché le Macropad et monté l'espace de stockage :
|
||||||
|
|
||||||
|
```
|
||||||
|
circup install adafruit_macropad
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installer minicom
|
||||||
|
|
||||||
|
Nous allons maintenant prépare notre système pour tester la connexion série .
|
||||||
|
Tout d'abord installons un logiciel pour communiquer via le port série pour
|
||||||
|
Interagir avec le Macropad. Personnellement j'ai choisi [*minicom*][l_minicom]
|
||||||
|
disponible dans les dépôts Debian, Archlinux et sûrement d'autres distributions:
|
||||||
|
|
||||||
|
```
|
||||||
|
pacman -S minicom
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est aussi nécessaire d'ajouter votre utilisateur dans le groupe `uucp` en
|
||||||
|
utilisant la commande suivante (avec `root` ou `sudo`):
|
||||||
|
|
||||||
|
```
|
||||||
|
gpasswd -a ephase uucp
|
||||||
|
```
|
||||||
|
|
||||||
|
[l_minicom]:https://salsa.debian.org/minicom-team/minicom
|
||||||
|
|
||||||
|
## Initialiser un périphérique série sur la Macropad
|
||||||
|
|
||||||
|
Afin d'initialiser un périphérique série sur le Macropad, il est nécessaire de
|
||||||
|
créer un fichier `boot.py` à la racine de votre lecteur CIRCUITPY et d'y ajouter
|
||||||
|
le code suivant:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import usb_cdc
|
||||||
|
try:
|
||||||
|
"""
|
||||||
|
Initialisation du port série pour la console REPL mais
|
||||||
|
aussi pour un périphérique série, Sous Linux il sera
|
||||||
|
disponible dans /dev/ttyACM
|
||||||
|
"""
|
||||||
|
usb_cdc.enable(console=True, data=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
```
|
||||||
|
|
||||||
|
Lors de l'enregistrement du fichier, le Macropad devrait se relancer et prendre
|
||||||
|
en compte les modifications. Plus besoin de toucher à ce fichier, on le laissera
|
||||||
|
tranquille tout au long de cet article. Nous modifierons maintenant le fichier
|
||||||
|
`code.py` toujours à la racine de notre lecteur `CIRCUITPY`.
|
||||||
|
|
||||||
|
## Premier script, faire clignoter une DEL
|
||||||
|
|
||||||
|
Nous allons maintenant tester notre premier code. Celui-ci va simplement faire
|
||||||
|
clignoter une DEL sous une touche de notre clavier. Nous **pourrons changer la
|
||||||
|
fréquence en envoyant la commande `time` via une connexion série**. Voici le
|
||||||
|
code en question:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from adafruit_macropad import MacroPad
|
||||||
|
import usb_cdc
|
||||||
|
import time
|
||||||
|
|
||||||
|
macropad = MacroPad()
|
||||||
|
serial = usb_cdc.data
|
||||||
|
|
||||||
|
def exec_command (data):
|
||||||
|
global timer
|
||||||
|
command,option = data.split()
|
||||||
|
print("cmd: {} | opt: {}".format(command, option))
|
||||||
|
if command == 'time':
|
||||||
|
timer = float(option)
|
||||||
|
print("new timer: {}".format(timer))
|
||||||
|
|
||||||
|
def blink(led, light):
|
||||||
|
print('light: {}'.format(light))
|
||||||
|
if light:
|
||||||
|
macropad.pixels[led] = (33, 45, 230)
|
||||||
|
else:
|
||||||
|
macropad.pixels[led] = (0, 0, 0)
|
||||||
|
print('c: {}'.format(macropad.pixels[led]))
|
||||||
|
return False if light else True
|
||||||
|
|
||||||
|
timer=2
|
||||||
|
light=False
|
||||||
|
in_data=bytearray()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
light = blink(1, light)
|
||||||
|
time.sleep(timer)
|
||||||
|
|
||||||
|
if serial.in_waiting > 0:
|
||||||
|
while(serial.in_waiting>0):
|
||||||
|
byte = serial.read(1)
|
||||||
|
if byte == b'\r':
|
||||||
|
exec_command(in_data.decode("utf-8"))
|
||||||
|
in_data = bytearray()
|
||||||
|
else:
|
||||||
|
in_data += byte
|
||||||
|
```
|
||||||
|
|
||||||
|
Le code est plutôt simple, nous initialisons notre Macropad et la connexion
|
||||||
|
série avec le début de notre fichier:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from adafruit_macropad import MacroPad
|
||||||
|
import usb_cdc
|
||||||
|
import time
|
||||||
|
|
||||||
|
macropad = MacroPad()
|
||||||
|
serial = usb_cdc.data
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensuite nous définissons notre fonction `exec_command` chargée d'interpréter les
|
||||||
|
commandes envoyées depuis la connexion série puis notre fonction `blink` changer
|
||||||
|
de faire clignoter notre DEL.
|
||||||
|
|
||||||
|
Après avoir initialiser les variables `timer` `light` et `in_data` -- cette
|
||||||
|
dernière recevra les données de la connexion série le programme commence. La
|
||||||
|
partie la plus intéressante démarre avec `if serial.is_wainting`.
|
||||||
|
|
||||||
|
À ce moment, si des données sont en attente sur le port série, alors nous les
|
||||||
|
ajoutons à notre variable `in_data`. Lors de la réception d'un retour chariot
|
||||||
|
`\r`, alors nous passons les données reçues à notre fonction `exec_command`.
|
||||||
|
|
||||||
|
### Test de notre code
|
||||||
|
|
||||||
|
Le Test démarre une fois le fichier `code.py` écrit sur notre Macropad.
|
||||||
|
Vous devriez voir la DEL sous la touche 2 clignoter toute les deux secondes.
|
||||||
|
L'écran du Macropad affiche aussi les informations données par les instructions
|
||||||
|
`print` de notre code.
|
||||||
|
|
||||||
|
À partir de de moment nous allons pouvoir utiliser `minicon` pour se connecter à
|
||||||
|
la partie REPL du Macropad et ainsi visualiser aussi les `print`. Ici la console
|
||||||
|
REPL est accessible sous le périphérique `/dev/ttyACM0` :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ minicom -D /dev/ttyACM0
|
||||||
|
Welcome to minicom 2.8
|
||||||
|
|
||||||
|
OPTIONS: I18n
|
||||||
|
Compiled on Jan 9 2021, 12:42:45.
|
||||||
|
Port /dev/ttyACM0, 18:28:08
|
||||||
|
|
||||||
|
Press CTRL-A Z for help on special keys
|
||||||
|
|
||||||
|
light: False
|
||||||
|
c: (0, 0, 0)
|
||||||
|
light: True
|
||||||
|
c: (33, 45, 230)
|
||||||
|
```
|
||||||
|
|
||||||
|
La connexion série initiée par notre code est disponible sur le périphérique
|
||||||
|
`/dev/ttyACM1`. Pour modifier le timer, alors nous pouvons entrer la commande
|
||||||
|
suivante depuis un autre terminal:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
printf "time 10\r" > /dev/ttyACM1
|
||||||
|
```
|
||||||
|
|
||||||
|
Sur notre terminal de contrôle avec `minicom`, vous voyons apparaitre alors:
|
||||||
|
|
||||||
|
```
|
||||||
|
light: True
|
||||||
|
c: (33, 45, 230)
|
||||||
|
cmd: time | opt: 10
|
||||||
|
new timer: 10.0
|
||||||
|
light: False
|
||||||
|
c: (0, 0, 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
Notre timer est bien pris en compte et le clignotement se fait maintenant toutes
|
||||||
|
les dix secondes.
|
||||||
|
|
||||||
|
Ce code est bien rudimentaire : il n'y a aucun contrôle et un rien -- comme
|
||||||
|
juste envoyer `time toto` avec notre `printf` -- le fait planter. Pas de panique
|
||||||
|
: le Macropad redémarrera alors tout seul.
|
||||||
|
|
||||||
|
Autre problème, il faut attendre que notre instruction `time.sleep(timer)` soit
|
||||||
|
finie avant que la modification de notre `timer` soit prise en compte. Il est
|
||||||
|
possible d'utiliser la librairie `asyncio` pour contourner ce problème, mais
|
||||||
|
nous ne traiterons pas de ce cas dans cet article.
|
||||||
|
|
||||||
|
## Envoyer des données depuis le Macroad
|
||||||
|
|
||||||
|
Maintenant que nous avons réussi à envoyer des données depuis notre ordinateur
|
||||||
|
vers le Macropad, nous allons en envoyer en sens inverse. Nous allons modifier
|
||||||
|
le fichier `code.py`, plus précisément la fonction `exec_command` comme
|
||||||
|
ci-dessous:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# [...]
|
||||||
|
def exec_command (data):
|
||||||
|
global timer
|
||||||
|
try:
|
||||||
|
command,option = data.split()
|
||||||
|
except:
|
||||||
|
command = ""
|
||||||
|
option = ""
|
||||||
|
print("cmd: {} | opt: {}".format(command, option))
|
||||||
|
if command == 'time':
|
||||||
|
timer = float(option)
|
||||||
|
print("new timer: {}".format(timer))
|
||||||
|
response = "nouveau timer : {}\r\n".format(option)
|
||||||
|
buffer = bytearray(response)
|
||||||
|
serial.write(buffer)
|
||||||
|
# [...]
|
||||||
|
```
|
||||||
|
|
||||||
|
La modification est relativement simple et tient en 3 instructions. Pour tester
|
||||||
|
son fonctionnement, nous allons ouvrir deux terminaux avec `minicom` :
|
||||||
|
|
||||||
|
1. sur notre périphérique `/dev/ttyACM0` afin d'avoir un accès à la console du
|
||||||
|
Macropad;
|
||||||
|
2. sur `/dev/ttyACM1` afin d'interagir avec notre programme dans le Macropad;
|
||||||
|
|
||||||
|
Sur cette dernière fenêtre de terminal, nous allons lancer *minicom* avec la
|
||||||
|
commande `minicom -D /dev/ttyACM1 -c on` puis une fois lancé nous allons
|
||||||
|
activer l'affichage des commandes que l'on saisit avec `Ctrl + X` puis `E`. Cette
|
||||||
|
étape est facultative mais *il est plus agréable de voir ce que nous saisissons*.
|
||||||
|
|
||||||
|
À partir de là nous pouvons changer la fréquence de clignotement avec la
|
||||||
|
commande `time` saisie directement dans *minicom*, notre Macropad nous répond
|
||||||
|
alors directement en envoyant la confirmation via la connexion série:
|
||||||
|
|
||||||
|
```
|
||||||
|
Welcome to minicom 2.8
|
||||||
|
|
||||||
|
OPTIONS: I18n
|
||||||
|
Compiled on Jan 9 2021, 12:42:45
|
||||||
|
Port /dev/ttyACM1, 17:16:49
|
||||||
|
|
||||||
|
Press CTRL-A Z for help on special keys
|
||||||
|
|
||||||
|
|
||||||
|
time 1
|
||||||
|
nouveau timer : 1
|
||||||
|
time 2
|
||||||
|
nouveau timer : 2
|
||||||
|
time 4
|
||||||
|
nouveau timer : 4
|
||||||
|
time 1
|
||||||
|
nouveau timer : 1
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Vous devriez obtenir un fonctionnement similaire à ce que montre la capture
|
||||||
|
d'écran ci-dessus.
|
||||||
|
|
||||||
|
Nous avons maintenant obtenu une **communication série bidirectionnelle** entre
|
||||||
|
notre Macropad et notre ordinateur. Mais cet exemple est plutôt succinct, que
|
||||||
|
pouvons nous en faire **concrètement**?
|
||||||
|
|
||||||
|
## Un (début) d'exemple "réel"
|
||||||
|
|
||||||
|
Nous allons utiliser ce que nous avons vu jusqu'ici pour mettre en place un
|
||||||
|
bouton du clavier pour mettre en sourdine le microphone de notre ordinateur.
|
||||||
|
|
||||||
|
Nous allons programmer le bouton N°1 du Macropad pur envoyer une instruction
|
||||||
|
*mute*. Sa DEL sera rouge si le microphone est coupé et verte s'il est actif. Un
|
||||||
|
script *Python* sur notre ordinateur se chargera de recevoir les ordres les
|
||||||
|
exécutera et enverra l'état du microphone en retour.
|
||||||
|
|
||||||
|
### Sur le Macripad
|
||||||
|
|
||||||
|
Voici le code à mettre dans `code.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from adafruit_macropad import MacroPad
|
||||||
|
import usb_cdc
|
||||||
|
import time
|
||||||
|
|
||||||
|
macropad = MacroPad()
|
||||||
|
serial = usb_cdc.data
|
||||||
|
|
||||||
|
def exec_command (data):
|
||||||
|
global muted
|
||||||
|
try:
|
||||||
|
command,option = data.split()
|
||||||
|
except:
|
||||||
|
command = ""
|
||||||
|
option = ""
|
||||||
|
print("cmd: {} | opt: {}".format(command, option))
|
||||||
|
if command == 'mute':
|
||||||
|
muted = True if option == 'yes' else False
|
||||||
|
|
||||||
|
timer=2
|
||||||
|
in_data=bytearray()
|
||||||
|
muted=False
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Define muted button color
|
||||||
|
if muted:
|
||||||
|
macropad.pixels[1] = (255,0,0)
|
||||||
|
else:
|
||||||
|
macropad.pixels[1] = (0,255,0)
|
||||||
|
|
||||||
|
# Get key event
|
||||||
|
key_event = macropad.keys.events.get()
|
||||||
|
if key_event:
|
||||||
|
if key_event.pressed:
|
||||||
|
if key_event.key_number == 1:
|
||||||
|
serial.write(bytearray('mute\r\n'))
|
||||||
|
|
||||||
|
# Receive serial data
|
||||||
|
if serial.in_waiting > 0:
|
||||||
|
while(serial.in_waiting > 0):
|
||||||
|
byte = serial.read(1)
|
||||||
|
if byte == b'\r':
|
||||||
|
exec_command(in_data.decode("utf-8"))
|
||||||
|
in_data = bytearray()
|
||||||
|
else:
|
||||||
|
in_data += byte
|
||||||
|
```
|
||||||
|
|
||||||
|
Comme vous pouvez le constater nous utilisons largement le code présent dans les
|
||||||
|
deux premières parties.
|
||||||
|
|
||||||
|
### Le script Python sur notre ordinateur
|
||||||
|
|
||||||
|
Il utilise `pactl` pour piloter le micro et obtenir son état. Voici le code à
|
||||||
|
mettre dans le fichier `serial_daemon.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import serial
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
ser = serial.Serial(port='/dev/ttyACM1')
|
||||||
|
|
||||||
|
ser.flushInput()
|
||||||
|
print('Begin loop')
|
||||||
|
while True:
|
||||||
|
line = ser.readline()
|
||||||
|
try:
|
||||||
|
command = (line.decode()).split()
|
||||||
|
print('command received: {}'.format(command[0]))
|
||||||
|
except:
|
||||||
|
print('no valid command received')
|
||||||
|
command = ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
if command[0] == "mute":
|
||||||
|
# First subprocess for toggle mote the microphone
|
||||||
|
subprocess.run(
|
||||||
|
['pactl', 'set-source-mute', '@DEFAULT_SOURCE@', 'toggle'],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Second one for check the states of microphone
|
||||||
|
result = subprocess.run(
|
||||||
|
['pactl', 'get-source-mute', '@DEFAULT_SOURCE@'],
|
||||||
|
capture_output=True
|
||||||
|
)
|
||||||
|
message = "mute {}\r".format(result.stdout.split()[1].decode())
|
||||||
|
ser.write(message.encode())
|
||||||
|
print('command sent: {}'.format(message))
|
||||||
|
except Error as e:
|
||||||
|
print('Error in command: {}'.format(e))
|
||||||
|
```
|
||||||
|
|
||||||
|
Le script commence par initialiser le périphérique série, puis vide l'ensemble
|
||||||
|
des données présente dans le buffer du port série avec `ser.flushInput()` afin
|
||||||
|
de repartie de zéro. Commence ensuite une bouble infinie (notre script reste
|
||||||
|
résident en mémoire).
|
||||||
|
|
||||||
|
`line = ser.readline()` permet de mettre notre processus en attente passive tant
|
||||||
|
qu'une fin de ligne de type `\n\r` n'a pas été reçue. A partir de là le script
|
||||||
|
traite la linge reçue.
|
||||||
|
|
||||||
|
Le script lance la commande pour changer l'état du microphone puis la commande
|
||||||
|
pour en vérifier l'état. L'instruction `ser.write()` transmet l'état de ce
|
||||||
|
dernier au Macropad qui **agira en conséquence**.
|
||||||
|
|
||||||
|
Ici encore le script reste minimal, il suffit maintenant de le lancer et
|
||||||
|
d'observer les différents messages ainsi que l'état di microphone :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
chmod +x serial_daemon.py
|
||||||
|
./serial_daemon.py
|
||||||
|
```
|
||||||
|
|
||||||
|
En appuyant sur le bouton adéquat du clavier, notre script `serial_daemon`
|
||||||
|
devrait réagir comme ci-dessous dans la console:
|
||||||
|
|
||||||
|
```
|
||||||
|
Begin loop
|
||||||
|
command received: mute
|
||||||
|
command sent: mute yes
|
||||||
|
command received: mute
|
||||||
|
command sent: mute no
|
||||||
|
command received: mute
|
||||||
|
command sent: mute yes
|
||||||
|
```
|
||||||
|
|
||||||
|
Et la lumière sous la touche devrait changer de couleur en fonction de
|
||||||
|
l'activation de la sourdine.
|
||||||
|
|
||||||
|
## En conclusion
|
||||||
|
|
||||||
|
Nous avons donc vu comment utiliser les ports série -- que se soir pour la
|
||||||
|
connexion REPL ou pour les données -- sur notre *Macropad Adafruit*.
|
||||||
|
Personnellement j'adore ce petit périphérique qui permet une infinité de
|
||||||
|
possibilité et se programme relativement facilement grâce à *CircuitPython*.
|
||||||
|
|
||||||
|
Bien sût cet article n'a pas pour vocation d'aller en profondeur, que se soit
|
||||||
|
dans les paramétrages des connexions séries que dans les possibilités offertes.
|
||||||
|
Mais su le sujet vous intéresse une petite recherche sur les Internets vous
|
||||||
|
donnera de quoi faire. Je ne peux cependant que vous conseiller l'excellent article
|
||||||
|
de [Carlos Olmos] qui a utilisé le Macropad pour se créer un jukebox. Je m'en
|
||||||
|
suis inspiré pour l'écriture de cet article.
|
||||||
|
|
||||||
|
[Carlos Olmos]:https://carlosolmos.dev/posts/the-macropad-jukebox/
|
Loading…
Add table
Add a link
Reference in a new issue