Showing posts with label home automation. Show all posts
Showing posts with label home automation. Show all posts

Friday, December 6, 2013

Posting data from Arduino to Xively using bash

I decided to check if it is possible to post a sensor data to xively.com (ex cosm.com ex pachube.com) using bash only without building a complicated system like the one I attempted to build here: My first attempt to build a home monitoring/control system. And, in fact, it turned out to be quite simple.



We are going to need an Arduino with a temperature sensor that is able to answer to a string request with a float number representing sensor value. In my case, Arduino is programmed to send temperature in degrees Celsius if it receives a string "Get" over UART. So, what we need to do is to write a bash script that sends the string "Get" to a comport, recieves data and posts it to xively.com.

We are going to use /dev/ttyUSB0 comport (you may have a different one, so check this first), so let's declare a variable:


SERIAL_DEVICE=/dev/ttyUSB0

Now we can send data to the comport by just doing echo


echo "Get" > $SERIAL_DEVICE

And read data back by just doing read

read TEMP < $SERIAL_DEVICE

Here may be a few problems. Like speed of the port is not matching the speed of Arduino. Or the number of data or stop bits not matching. Or pretty much anything else not matching, so we have to make sure that the comport operates with the same parameters Arduino does. So before sending and receiving data to and from the comport, set its parameters:


stty -F $SERIAL_DEVICE cs8 9600 clocal -crtscts -cstopb -parenb -hup -ixany \
 igncr -ixoff -ixon -isig iexten >/dev/null

I was at this point able to communicate with Arduino, but I still had a problem of the Arduino resetting every time I echo to it. I was not able to overcome this problem, although it seems simple. Options like -hup (or -hupcl) and clocal have to solve the problem of DTR going down every time. But they don't. So what I do, is:
  1. I open the port:
    exec 3<>$SERIAL_DEVICE
    
  2. I wait for 3 seconds whil Arduino reboots:
    sleep 3
    
  3. I do my echo and read
  4. And I close the comport:
    exec 3>&-
    

So now I have the data from the sensor as a string and I just need to send this data to xively.com. I simply do that with cURL:


curl -ssss \
 --request PUT \
 --header "X-ApiKey: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
 --data "$DATA_STRING" \
 https://api.xively.com/v2/feeds/XXXXXXXXX > /dev/null

where $DATA_STRING is the data in json format:


DATA_STRING='{"version":"1.0.0", "datastreams":[{"id":"TC", "current_value":"'"$TEMP"'"}]}'


Here I had another problem when putting the variable directly into the string. Arduino sends "\r\n" as the end of the line when you use Serial.println(). And that '\r' totally corrupts the line. But we need the '\n' to detect the end of data. To get rid of '\r', you can use stty option igncr. So, the full script now looks as:
#!/bin/bash

#serial
SERIAL_DEVICE=/dev/ttyUSB0

#port setting
stty -F $SERIAL_DEVICE cs8 9600 clocal -crtscts -cstopb -parenb -hup -ixany \
 igncr -ixoff -ixon -isig iexten >/dev/null

sleep 0.1

exec 3<>$SERIAL_DEVICE
sleep 3

echo "Get" > $SERIAL_DEVICE
read TEMP < $SERIAL_DEVICE

DATA_STRING='{"version":"1.0.0", "datastreams":[{"id":"TC", "current_value":"'"$TEMP"'"}]}'
#echo "$DATA_STRING"

exec 3>&-

curl -ssss \
 --request PUT \
 --header "X-ApiKey: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
 --data "$DATA_STRING" \
 https://api.xively.com/v2/feeds/XXXXXXXXXX > /dev/null

So now save your script (I save it as ~/bin/xively), make it executable (chmod +x ~/bin/xively) and add it to the scheduler to execute regularly by typing crontab -e and adding the following line to your crontab:

*/2 * * * * ~/bin/xively

And now your sensor data is in the cloud! Check this out: https://xively.com/feeds/337476649

Friday, December 28, 2012

My first attempt to build a home monitoring/control system

I've been playing with XBees for a while now and about two weeks ago I hit the wall - transparent UART mode has stopped being enough for my hobby. Sensors, devices to control, clocks to sync all aroung house. I had to move on - API mode, explicit addressing, frames parsing...

I, however, also spent some time recently studying some courses (mostly programming) on edx.org (this eats a lot of my time by the way). So I couldn't just get away with simple functional programming approach. I created many classes, I subclassed subclasses and have a pretty sofisticated class structure now in about 10 different python modules. Trying to get through all of this makes my head ake. However if you just look from a 'Main' program stand point, the whole thing is relatively easy and natural. Here how a blinking led example looks like:

def main():

    ## Create a coordinator. This is an XBee, connected to PC via comport
    ## 'COM4' is a comport to where XBee is connected
    ## 57600 is the comport speed
    ## "\x00\x13\xA2\x00\x40\x78\xFD\x76" is 64-bit address of the coordinator module
    ## 'coord' is a human-readable name
    coordinator = XBee24ZBCoordinator('COM4', 57600,
        "\x00\x13\xA2\x00\x40\x78\xFD\x76", 'coord')


    ##print "Hi, I'm Coordinator, my is hw #", coordinator.get_hwuid(),
    ##print 'and name is', coordinator.getName()

    ## Create a remote module. This is an XBee, hanging out somewhere in my house
    ## "\x00\x13\xA2\x00\x40\x78\xFD\x76" is 64-bit address of the module
    ## 'spalnya' is a human-readable name
    remote = XBee24ZBRemote('\x00\x13\xA2\x00\x40\x79\xB2\x71', 'spalnya')


    ##print "Hi, I'm a remote, my is hw #", remote.get_hwuid(),
    ##print 'and name is', remote.getName(), 'and address is', remote.getLongAddress()

    ## Now we are building the network topology
    ## We tell remote to connect to coordinator
    ## This tells remote where to send information and this
    ## also registers this remote with coordinator
    remote.connectToCoordinator(coordinator)

    ## Create a led
    led = LED()
    ## Connect led to remote, tell to which pin and in which mode
    ## remote.getPin('DO4') <- this is a pin on remote with name 'DO4'
    ## 'DO' is pin operation mode. Can be DO (digital out), DI (digital in),
    ## 'ADC' - analog input
    led.connectTo(remote.getPin('DO4'), 'DO')

    ## Tell led to turn on. Notice, after network topology is set (remote
    ## is connected to coordinator and the led is connected to a specific
    ## pin of the remote, we do not have to care about connections any more
    ## we just tell our led to switch on
    led.on()

    ## Digital input sensor (sempling LOW/HIGH level on an XBee pin)
    ## 'test' is a human readable name
    io = DI('test')

    ## connect this sensor to an XBee pin
    io.connectTo(remote.getPin('DI3'), 'DI')
    
    while True:
        ## Read pin
        io.read()
        try:
            ## switch on led
            led.on()
            sleep(2)
            ## switch off led
            led.off()
            sleep(2)
        except KeyboardInterrupt:
            break

    ## Halt XBee and close comport
    coordinator.halt()

Note, that we have to define topology first (like connectTo(coordinator)), but than I simply don't care HOW my led is connected to main server - via XBee, WiFi, TCP/IP, UART or else. I don't have to. I just tell the led to shine and it magically goes on. That's what I wanted to get and it seems I'll get that.

What I have now is a working prototype. I wouldn't been able to do even this without this great XBee library: http://code.google.com/p/python-xbee/