En ésta ocasión vamos a ver como comunicarnos desde el pc con arduino utilizando Python.
Para ello utilizamos el USB como puerto serie.
En el ejemplo utilizamos un sensor PIR, aunque una vez realizada la comunicación entre dispositivos es posible trabajar con todo el potencial de arduino.
Esquema de conexión Arduino

Si quieres saber más del sensor PIR puedes ver aquí un ejemplo sencillo del mismo.
Código Arduino
const int pinPIR = 2; // pin de entrada del PIR
const int pinLED = 13; // pin del LED que indica estado del sensor
int estadoPIR = 0; // estado del pin, inicia a 0
int estadoLED = LOW; // estado del LED
String sensorNAME= "living room";
String smsg="";
void setup() {
// SENSOR PIR
pinMode(pinLED, OUTPUT); // selecciona pin de salida, en este caso el pin 13 activa led integrado en placa
pinMode(pinPIR, INPUT);
Serial.begin(115200);
Serial.setTimeout(1);
digitalWrite(pinLED, LOW); // apaga el led
}
void loop() {
estadoPIR = digitalRead(pinPIR);
if (estadoPIR == HIGH) { // si detecta movimiento enciende el led
if (estadoLED == LOW) { // si previamente estaba apagado lo enciende
estadoLED=HIGH;
digitalWrite(pinLED, HIGH); // enciende el led
smsg=sensorNAME;
Serial.print(smsg);
delay(2000); // waits for a second
estadoLED=LOW;
digitalWrite(pinLED, LOW); // apaga el led
}
} else { // si no se detecta movimiento
if (estadoLED == HIGH) { // si previamente estaba encendido lo apaga
estadoLED=LOW;
digitalWrite(pinLED, LOW); // apaga el led
}
}
delay(1000); // waits for a second
}
El código es simple, si se detecta algo por el sensor PIR enciende el led 2 segundos y escribe mensaje, por puerto serie.
Código Python
from datetime import datetime, timedelta
import time
import os
import sys
import serial
import time
def write_read(arduino):
time.sleep(0.05)
data=None
INTERVAL=60000*10
nextmillisMSG=int(round(time.time() * 1000))+INTERVAL
while not data:
currentmillis = int(round(time.time() * 1000))
data = arduino.readline()
if(currentmillis>nextmillisMSG):
nextmillisMSG=currentmillis+INTERVAL
return "TIMEOUT##"
#
return data.decode("utf-8") # se pasa de bytes a string
def main():
nparam=len(sys.argv)
sport="/dev/ttyACM1" # por defecto
for i in range(1,nparam):
stmp=sys.argv[i]
if stmp=="-port":
nport=sys.argv[i+1] # ACM0, ACM1, ...
sport="/dev/tty{}".format(nport)
arduino = serial.Serial(port=sport, baudrate=115200, timeout=.1)
INTERVAL=60000
nextmillisMSG=0
lastmillis=0
ncount=0
sValue=""
while True:
smsg=""
value = write_read(arduino)
currentmillis = int(round(time.time() * 1000))
stmp="{}: {}...".format(datetime.fromtimestamp(float(currentmillis)/1000).strftime('%Y-%m-%d %H:%M:%S'), value)
#print(stmp)
strtstampup = datetime.fromtimestamp(float(currentmillis)/1000).strftime('%Y-%m-%d %H:%M:%S')
if value=="TIMEOUT##":
strtstampini = datetime.fromtimestamp(float(firsttime)/1000).strftime('%Y-%m-%d %H:%M:%S')
strtstamplast = datetime.fromtimestamp(float(lastmillis)/1000).strftime('%Y-%m-%d %H:%M:%S')
if ncount>0:
smsg="END {} {} to {}: {}, count:{}".format(sValue, strtstampini, strtstamplast, value, ncount)
sValue=""
ncount=0
else:
lastmillis=currentmillis
if ncount==0:
sValue=value
firsttime=currentmillis
smsg="INIT {}: {}".format(strtstampup, value)
ncount+=1
if smsg!="":
# en lugar de por pantalla, el smsg puede enviarse via webservice o telegram
print(smsg)
main()
El programa espera datos en el puerto serie, cuando recibe algo guarda el sello de tiempo y sigue escuchando.
Con el fin de no estar continuamente escribiendo por pantalla, una vez detectado movimiento continua escuchando, si no vuelve a detectar nada en 10 min (INTERVAL 60000*10) Da por finalizada la alerta, escribe datos de inicio y fin de la alarma y se mantiene a la escucha, esperando nueva señal de arduino.
Si durante en ese intervalo de 10min detecta de nuevo movimiento, incrementa el contador y resetea el intervalo otros 10min.
Puerto Serie
Generalmente el puerto serie será /dev/ttyACM0 o /dev/ttyACM1, el por defecto en código es /dev/ttyACM1, si bien por parámetros se puede pasar el puerto con «-port <PUERTO>», por ejemplo para ACM2: «-port ACM2.
Testeado en Raspberry Pi OS y Ubuntu.
Espero sea de utilidad, cualquier duda o aportación en comentarios!
Gracias y Feliz dia! 😉