A Simple Python to Arduino Alert Scheme

My friend asked me the following yesterday:
“Is it possible to make the build script at my company flash some lights when it fails?”
I gave her some suggestions which involved the usual suspects – Python and Arduino. Now it’s all up to you, I said. But soon, I started fidgeting, and I can’t help it. I need to try this myself. 😉
This is what I came up with:
- Run a Python program that communicates with an Arduino via serial port.
- Arduino is connected to some lights. (LEDs, for proof of concept.)
- When build script fails, it communicates with the Python program, and it sends some data via
serial port, which the Arduino reads, and flashes some lights.
The only challenge here is the mechanism for a script on the build machine to communicate with our Python program. I am sure there are many sophisticated ways of doing this, but being a simpleton, I chose a very simple way – use a status file.
The build script writes ‘OK’ or ‘BAD’ (or whatever) to a file called status.txt
, and the python code checks this file and sends some data to Arduino, which takes appropriate action.
The Python code sits in a loop, and every 2 seconds, reads the status file. If it reads ‘OK’, it sends a ‘1’ via serial port. If it reads anything else, it sends a ‘0’. When it quits, it sends a ‘2’, and this is used by the Arduino to cleanup.
Here is the Python code:
""" ardu_alert.py Alert Arduino via serial port when an event happens on the host computer. Author: Mahesh Venkitachalam Website: electronut.in """ import sys, serial import time import argparse # main() function def main(): print 'starting ardu_alert...' # create parser parser = argparse.ArgumentParser(description="ardu_alert...") # add expected arguments parser.add_argument('--port', dest='strPort', required=True) # parse args args = parser.parse_args() # open serial port ser = serial.Serial(args.strPort, 9600) # loop while True: try: strData = "" # read try: # open file f = open('status.txt') # read line, strip whitespace, convert to upper case val = f.readline().strip().upper() # prepare serial data if val == 'OK': strData = "1" else: strData = "0" # close file f.close() except: print 'Could not open status.txt' # send data to Arduino ser.write(strData) ser.flush() # wait for 2 seconds time.sleep(2) except KeyboardInterrupt: print 'Exiting!' # turn off leds ser.write("2") # close serial ser.flush() ser.close() break # call main if __name__ == '__main__': main()
At the Arduno end, it turns a Green LED on if it reads a ‘1’ via serial, and a Red LED when it reads a ‘0’. If it reads anything else, it turns both LEDs off. (This is important for cleanup – when the python script exits, we turn the LEDs off.)
Here is the code at the Arduino end:
// ardu_alert.ino // // read serial port and turn leds on/off // // Mahesh Venkitachalam // electronut.in #include "Arduino.h" // LED pin numbers (digital) int pinRed = 4; int pinGreen = 2; void setup() { // initialize serial comms Serial.begin(9600); // set pins pinMode(pinRed, OUTPUT); pinMode(pinGreen, OUTPUT); } void loop() { while(Serial.available() > 0) { int c = Serial.read(); if (c == '1') { digitalWrite(pinRed, LOW); digitalWrite(pinGreen, HIGH); } else if (c == '0') { digitalWrite(pinRed, HIGH); digitalWrite(pinGreen, LOW); } else { digitalWrite(pinRed, LOW); digitalWrite(pinGreen, LOW); } } // wait delay(100); }
Here is how I run it:
$ python ardu_alert.py --port /dev/tty.usbmodem411
To change the status I do:
$echo OK > status.txt $echo BAD > status.txt
It works quite well, as you can see below.
Instead of LEDs, you can hook up anything at the other end, provided you do some extra work. For example, use a MOSFET/transistor and a Relay to control lights, or maybe even hack a toy to do something silly.
That was fun. 😀