Interfacing on a Mac / Python / Web

Hi guys - I finally got me an Arduino Uno and loving it. I have made the obligatory blinky LED etc and all is going well. I am intending on building a few simple projects, one of which is an automatic dog feeder !

I am playing around with getting the computer to turn on and off the LED. I have a loop running on the Uno that is looking for serial input and switching the LED on or off. This works by simply issuing the appropriate command form the OSX terminal using Python and its serial class.

Now say I want to switch the LED on / off via a web browser. I thought that maybe I could do this using a webservices call, maybe using Python but I am just not sure. I am assuming that whatever I do, ie. CGI / SOAP etc, I need a function on the webserver to issue that serial command to the Arduino. Is this architecture appropriate ?

I had a look at Firmata but it does not look as though it is widely mentioned after about 2008, I have had a look on the arduino.cc site under the interfacing section and some of the methods there replace the loop() on the Arduino skecth and do all the processing on the computer.

I still want to run my own loop on the Arduino but I want to be able to send in a command and trigger a pin from either the computer or the web.

The end state is to be able to build some home automation devices that can run autonomously or via controls such as a hardware switch on a wall, from the computer, or from a command issued on the web.

Any pointers appreciated !

You might have a look at Bitlash. Bitlash is an interpreter that runs on the Arduino; you can send commands to it to control and read IO pins, and you can store small Bitlash programs in EEPROM to automate a whole application.

Download and doc at http://bitlash.net and good luck.

-br http://bitlash.net http://entropymouse.com

Great ! I will take a look now.

So I set up bitlash and that all works pretty well. I can turn a light on and off with a serial command. Now I need to know how to integrate that with a web form.

I can turn a light on and off with a serial command. Now I need to know how to integrate that with a web form.

You need to supply a lot more details about what you want to/know how to do.

A web form is served by a web server, and displayed by a browser. It includes some input controls and a “what do I do with this data” directive that defines what happens to the data when the submit button is pressed.

Are you running your own web server or can you put cgi/php/asp.net code on a web server somewhere to handle the “what do I do with this data” part of the form?

Can you connect your Arduino to the serial port on the web server?

What “what do I do with this data” scripting languages do you know/have available?

What OS is on your web server?

Do you need to get data from the Arduino, too.

I would suggest trying a CGI solution using Python in the first case as you've used Python, python cgi is well supported (I've set it up under Apache before, don't remember it being too hard). Caveat: that would have been on Ubuntu rather than MacOS.

Hi guys - thanks for the responses. I could quite easily run this from an Ubuntu server / LAMP stack. Python would be my preference for a server side language. Either CGI or writing a SOAP / web services wrapper around my Python functions instead of using CGI scripts. This is all just a learning project for me so I am open to all suggestions. I will probably write the stuff using CGI scripts first as suggested.

What I want to be able to do is: Turn an led on via a normal switch Turn an led on via a button on a web form Query the arduino to get the state of a digital pin and then change a graphic on a webpage to reflect this.

As I said, I am just trying to get the building blocks together to incorporate in a bigger project. Cheers

PHP on Linux (the P in LAMP) is able to read from and write to the serial port. If you are running your own web server (the A in LAMP), then this will be an easy thing to do, from your computer. Depending on how your computer connects to the internet (dynamic IP or static IP), you may, or may not, be able to access it from anywhere.

If I were to Internet connect this I can handle a dynamic ip address with dynamic dns etc, I would probably put in a reverse proxy if I were to Internet connect the whole thing. I mentioned LAMP as it is easy to install the whole stack on Ubuntu but I would rather write the cgi handler in python. Python is easy enough to get running under Apache.

Ok…so I have done a lot of playing around and I have started looking at the messenger library. I have now written some VERY simple Python CGI scripts that interact with my Arduino via a web interface and serial comms.

I am tearing my hair out trying to find a way to get ‘state’ values back into the web page. What I would like to do is tunr on and off, say an LED, and then change the colour of an image of a light on the web page. To do this I need to be able to send a pin read command via serial (which I can do successfully) but then I need to listen for the result… This is the bit I am struggling with now.

Arduino code:

#include <Messenger.h>

int redLEDpin = 9;
int greenLEDpin = 10;
int blueLEDpin = 11;



// Instantiate Messenger object with the message function and the default separator (the space character)
Messenger message = Messenger(); 

// Define messenger function
void messageCompleted() {

  if ( message.checkString("red") ) { // Red LED
      Serial.print("r ");
      //int pin = message.readInt();
      int mode = message.readInt();
      Serial.println(mode);
      digitalWrite(redLEDpin,mode);
  }
  
  if ( message.checkString("green") ) { // Red LED
      Serial.print("g ");
      //int pin = message.readInt();
      int mode = message.readInt();
      Serial.println(mode);
      digitalWrite(greenLEDpin,mode);
  }
 
   if ( message.checkString("blue") ) { // Red LED
      Serial.print("b ");
      //int pin = message.readInt();
      int mode = message.readInt();
      Serial.println(mode);
      digitalWrite(blueLEDpin,mode);
  }

if ( message.checkString("r") ) { // Red LED
      //Serial.print("Read ");
      //int pin = message.readInt();
      int pin = message.readInt();
      //Serial.print(pin);
      //Serial.print(" ");
      if(digitalRead(pin)== 1)
      {
        Serial.println("1");
      } else {Serial.println("O");}
  }  

}

void setup() {
  // Initiate Serial Communication
  Serial.begin(9600); 
  pinMode(redLEDpin,OUTPUT);
  pinMode(greenLEDpin,OUTPUT);
  pinMode(blueLEDpin,OUTPUT);
  message.attach(messageCompleted);
}

void loop() {
  // The following line is the most effective way of 
  // feeding the serial data to Messenger
  while ( Serial.available( ) ) message.process(Serial.read( ) );
}

Python CGI scripts:

red.py:

#!/usr/bin/python
import serial
print "Content-type: text/html"
print
print "<html><head>"
print ""
print "</head><body>"
print "Red"
print "</body></html>"
ser=serial.Serial('/dev/tty.usbmodemfa141',9600)
ser.open()
ser.write('red 1')
ser.write(chr(13))
ser.write('r 9')
ser.write(chr(13))
ser.close()

Off.py (the code to turn the LED off):

#!/usr/bin/python
import serial
print "Content-type: text/html"
print
print "<html><head>"
print ""
print "</head><body>"
print "Off"
print "</body></html>"
ser=serial.Serial('/dev/tty.usbmodemfa141',9600)
ser.open()
ser.write('red 0')
ser.write(chr(13))
ser.write('r 9')
ser.write(chr(13))
ser.close()

Each time I run this I can see the correct output in the serial monitor:

This YouTube video is a bit hard to see, but you can see my toggle code working and the output streaming to the serial monitor:

http://www.youtube.com/v/VtfTvuqKZqI

Now…if only I could read in that 0 or 1 and use it to change an tag in my html code. I just can’t see any way of getting that state back into my web page.

Also - why does the Arduino serial monitor have to be open to run this code ? If I close the monitor the Python CGI scripts don’t work at all.

Cheers guys.

You are setting pins 9, 10, & 11 as OUTPUT, and then trying to read from them.

You can only read from INPUT mode pins.

   if ( message.checkString("[glow]blue[/glow]") ) { // [glow]Red[/glow] LED

OK

ser=serial.Serial('/dev/tty.usbmodemfa141',9600)
ser.open()
ser.write('red 1')
ser.write(chr(13))
ser.write('r 9')
ser.write(chr(13))
ser.close()

A couple of observations. Unless you have modified your Arduino, the standard behavior is to reset the Arduino when a serial port is opened or closed. Then, there is a delay before the Arduino is ready to handle serial data. I don't see any kind of delay taking place, here.

Second, /dev/tty.usbmodemfa141 does not look right as the port name. Is this the name that shows up in the Tools + Serial port menu in the Arduino IDE?

Also - why does the Arduino serial monitor have to be open to run this code ? If I close the monitor the Python CGI scripts don't work at all.

This doesn't make sense. The Serial Monitor should have to be closed, since only one connection to the serial port (one each end) is possible at a given time. If the Serial Monitor is connected to the serial port that the Arduino is connected to, the Python script should not be able to connect to it. This presumes that the Python script is connecting to the correct serial port, which I have my doubts about.

First point - yes my code commenting is wrong there. Copy and paste error - should be:

if ( message.checkString("blue") ) { // Blue LED

Pins 9, 10 and 11 have to be set as output as they are controlling the LEDs. The reads of these pins work fine via he Messenger.h library - See video.

I will add a delay - not really affecting the functionality at present. See video, everything works fine.

/dev/tty.usbmodemfa141 is correct - again see video, I can communicate from my laptop to the Arduino.

This doesn't make sense. The Serial Monitor should have to be closed, since only one connection to the serial port (one each end) is possible at a given time. If the Serial Monitor is connected to the serial port that the Arduino is connected to, the Python script should not be able to connect to it. This presumes that the Python script is connecting to the correct serial port, which I have my doubts about.

Not sure if you are correct here, again, watch video - it all works. I am sending serial data in via the USB cable and watching the output of Serial.println in the monitor.

My question is more related to getting serial data back into the Python script, and not so much about commenting or serial port values !! I have that under control !

My question is more related to getting serial data back into the Python script, and not so much about commenting or serial port values

Your question is a Python question, not an Arduino question.

But, if the serial class has a write method(), it's a fairly safe assumption that it has a read() method, too. (I checked. It does.)

Well yes, it is a Python question. True. I want to know if someone else has already done this.

Once I send in the serial commands to send the pin HIGH:

ser.write('red 1')
ser.write(chr(13))

I want to be able to then read back the output from this serial write command:

ser.write('r 9')
ser.write(chr(13))

From the serial monitor I see the correct response - a '0' if it is off or a '1' if the pin is on. Does this sit in a buffer that can then be read, or once it is written to the serial port does it disappear ? I can't seem to be able to read it...

I'm not trying to leach info here, I am making a concerted effort to work this out myself.

I think the first think to work out is the issue with the Serial Monitor needing to be open in order for your script to work. This absolutely should not be the case. Your script should fail to open the serial port if it is already open by the Serial Monitor. At least, that's the case on windoze.

As I type this, though, I recall seeing other threads on the forum about the same issue. If I remember correctly, the issue was generally a permissions one. The script didn't have permission to open the /dev/tty stream. Once the Serial Monitor opened it, the script was able to hijack it. Since the issue only occurs on Linux, and I am stuck with windoze, I didn't pay a whole lot of attention.

There are other attributes of the serial port that you are not setting. Number of bits, stop bits, etc. Perhaps setting all the attributes is necessary, as perhaps some of the defaults aren't correct.

Just tossing out ideas here, as I really don't know what the problem is.

[edit]Have you seen this page: http://pyserial.sourceforge.net/ It has sample applications, etc., that might be useful[/edit]

Stop bits, baud rate are all set to defaults. I will say again, I have no problems talking to the Arduino via serial. This is not the question I am asking. I want to know how to read back a stream from the serial buffer so that I can change a state image on my web page.

I have no problems talking to the Arduino via serial.

I hear you saying this, but I also hear you saying this:

why does the Arduino serial monitor have to be open to run this code ? If I close the monitor the Python CGI scripts don't work at all.

So, I think that you DO have problems talking TO the Arduino. I also think that once you have resolved the issue of talking TO the Arduino (without needing to open the Serial Monitor first) that the issue of reading FROM the Arduino will take care of itself.

I dont have the code to read from the arduino - that is the problem. I will sort the serial monitor later. In the meantime I have worked out how to read a single byte character from the serial port, now I need to read a series of characters with delimiters, much like the messenger library but going the other way.

The read() function allows you to specify how many characters to read. If you are only getting one, it is because the Arduino is only sending one.

Have you changed the Arduino code to send more than a single character?

Nah - I dropped the output from my pin read function to just a single 1 or a 0 and it is working fine now. I would however like to read in something like 'dig 9 0' meaning digital pin 9 is off.