dimanche 15 septembre 2013

Read a one-wire temperature device with a USB adapter DS9490, and feed a Xively Feed

This tutorial explain how install a DS9490 device and read a One-wire device. The last step is updating a xively feed with the temperature sensor.

1) Installing the DS9490 on Raspberry
2) Read the temperature
3) Update a Xively Feed

This main tutorial is from the xively web site : https://xively.com/dev/tutorials/pi/
the difference is that instead of lop cpu value, we will get the value from the sensor:

change the read_loadavg() function with the following:

def read_temperature():
    if DEBUG:
      print "Reading Read Temperature Sensor"
    return subprocess.check_output(["cat /mnt/1wire/28.4543737898/temperature"],shell=True)

 Of course, change the device ID (28.4543737898) with your personal device.

in the main loop, change the update interval to your need :
time.sleep(10) # 10 seconds update interval

and don't forget to change the read_loadavg() name to read_temperature() evrywhere and update the FEED_ID and the API_KEY depending on your Xively account.

A full application will be :

#!/usr/bin/env python

import os
import xively
import subprocess
import time
import datetime
import requests

# extract feed_id and api_key from environment variables
FEED_ID = os.environ["FEED_ID"]
API_KEY = os.environ["API_KEY"]
DEBUG = os.environ["DEBUG"] or false

# initialize api client
api = xively.XivelyAPIClient(API_KEY)

# function to read 1 minute load average from system uptime command
def read_temperature():
  if DEBUG:
    print "Reading Temperature"
  return subprocess.check_output(["cat /mnt/1wire/28.45566778/temperature"], shell=True)

# function to return a datastream object. This either creates a new datastream,
# or returns an existing one
def get_datastream(feed):
  try:
    datastream = feed.datastreams.get("temperature")
    if DEBUG:
      print "Found existing datastream"
    return datastream
  except:
    if DEBUG:
      print "Creating new datastream"
    datastream = feed.datastreams.create("temperature", tags="sensor_01")
    return datastream

# main program entry point - runs continuously updating our datastream with the
# current 1 minute load average
def run():
  print "Starting Xively tutorial script"

  feed = api.feeds.get(FEED_ID)

  datastream = get_datastream(feed)
  datastream.max_value = None
  datastream.min_value = None

  while True:
    temperature = read_temperature()

    if DEBUG:
      print "Updating Xively feed with value: %s" % temperature

    datastream.current_value = temperature
    datastream.at = datetime.datetime.utcnow()
    try:
      datastream.update()
    except requests.HTTPError as e:
      print "HTTPError({0}): {1}".format(e.errno, e.strerror) 
 
    # 60 s update interval
    time.sleep(60)

run()

4) Create a daemon to update the xively feed

create a script "logger.py" like his below (configure it correctly for your needs).
type :  sudo python logger.py start

logger.py
#!/usr/bin/env python

import os
import xively
import subprocess
import time
import datetime
import requests
import commands
import logging
import sys

from daemon import runner

# on cree leséventuels répertoires non disponibles
os.system('mkdir -p /var/run/logger-daemon')

logger = logging.getLogger("DaemonLog")
logger.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler = logging.FileHandler("/var/log/logger-daemon.log")
handler.setFormatter(formatter)
logger.addHandler(handler)

FEED_ID = "YOUR FEED_ID"
API_KEY = "YOUR_
API_KEY"

# initialize api client
api = xively.XivelyAPIClient(API_KEY)

# function to read the temperature from ds18b20 temperature sensor on i2c
def read_temperature():  
   try:
      output = subprocess.check_output("cat /mnt/1wire/28.43BE25020000/temperature", shell=True)
      temperature = round(float(output),1)
      return temperature
   except:
      logger.error("Unexpected error: %s", sys.exc_info()[0])

# function to return a datastream object. This either creates a new datastream,
# or returns an existing one
def get_datastream(feed):
  try:
    datastream = feed.datastreams.get("temperature")
    return datastream
  except:
    datastream = feed.datastreams.create("temperature", tags="temperature")
    return datastream

class App():
 
    def __init__(self):
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/null'
        self.stderr_path = '/dev/null'
        self.pidfile_path =  '/var/run/logger-daemon/logger-daemon.pid'
        self.pidfile_timeout = 5
         
    def run(self):
        feed = api.feeds.get(FEED_ID)
        datastream = get_datastream(feed)
        datastream.max_value = None
        datastream.min_value = None
        while True:
            try:
               degreesCelcius = read_temperature()
            except Exception as e:
               logger.error("Exception({0}): {1}".format(e.errno, e.strerror))
            datastream.current_value = degreesCelcius
            datastream.at = datetime.datetime.utcnow()
            try:
               datastream.update()
            except requests.HTTPError as e:
               logger.error("HTTPError({0}): {1}".format(e.errno, e.strerror))
            logger.info("Upload to Xiverly Temperature : %s " % degreesCelcius)
            #logger.debug("Debug message")
            #logger.info("Info message")
            #logger.warn("Warning message")
            #logger.error("Error message")
            time.sleep(60)

app = App()


daemon_runner = runner.DaemonRunner(app)
#This ensures that the logger file handle does not get closed during daemonization
daemon_runner.daemon_context.files_preserve=[handler.stream]
daemon_runner.do_action()





5) install your daemon to start at boot


create a file 'logger-daemon' in /etc/init.d
and make "sudo chmod a+x logger-daemon"
"sudo update-rc.d logger-daemon defaults"

in the script below, takes cares to configure correctly the HOM directory which contains the script logger-daemon.py


logger-daemon
#! /bin/sh
### BEGIN INIT INFO
# Provides: logger-daemon
# Required-Start:    $remote_fs $syslog $network
# Required-Stop:     $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: logger-daemon at boot
# Description: start logger-daemon at boot
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Logger-Daemon"
NAME=logger-daemon
HOME=/home/pi/temperature
DAEMON=/usr/bin/python2.7
DAEMON_ARGS="-m logger-daemon"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
VERBOSE=yes

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
    chdir $HOME
    $DAEMON $DAEMON_ARGS start
}

#
# Function that stops the daemon/service
#
do_stop()
{
    chdir $HOME
    $DAEMON $DAEMON_ARGS stop
}

case "$1" in
  start)
    [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
    do_start
    ;;
  stop)
    [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
    do_stop
    ;;
  status)
    status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
    ;;
  *)
    echo "Usage: $SCRIPTNAME {start|stop|status}" >&2
    exit 3
    ;;
esac

:

samedi 14 septembre 2013

Create a daemon on Ubuntu

This tutorial is only valid if you have installed UPSTART
By default Raspbian distribution use SysVInit not UPSTART so this tutorial is not valid ...

1) Install python-daemon and python-lockfile
   sudo apt-get install python-daemon python-lockfile

2) create a python script

mydaemon.py:

#!/usr/bin/env python

import os

import subprocess
import time
import datetime
import requests
import commands
import logging

from daemon import runner

class App():
  
    def __init__(self):
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/tty'
        self.stderr_path = '/dev/tty'
        self.pidfile_path =  '/var/run/mydaemon/mydaemon.pid'
        self.pidfile_timeout = 5
          
    def run(self):

        while True:
            logger.debug("Debug message")
            logger.info("Info message")
            logger.warn("Warning message")
            logger.error("Error message")
            time.sleep(60)

app = App()
logger = logging.getLogger("DaemonLog")
logger.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler = logging.FileHandler("/var/log/mydaemon/mydaemon.log")
handler.setFormatter(formatter)
logger.addHandler(handler)


daemon_runner = runner.DaemonRunner(app)
#This ensures that the logger file handle does not get closed during daemonization
daemon_runner.daemon_context.files_preserve=[handler.stream]
daemon_runner.do_action()


3) Start/Stop

 > python mydaemon.py
usage: mydaemon.py start|stop|restart
> python mydaemon.py start
started with pid 8699
> python mydaemon.py stop
Terminating on signal 15

4)  Create a startup configuration

create a file name "mydaemon.conf" in /etc/init

description "MyDaemon Service"
author "you"
start on runlevel [234]
stop on runlevel [0156]
chdir /mydirectory
exec /mydirectory/mydaemon.py
respawn

then reload configuration:
sudo initctl reload-configuration

now you can start daemon with :
sudo start mydaemon

and stop it with
sudo stop mydaemon

and the daemon will be launched at startup and kill at shutdown !

5) Troubleshoot

If you've got an error with (ImportError: cannot import name runner), check that the 'daemon' if the right one:

root@raspberrypi ~/ $ python
Python 2.7.3 (default, Jan 13 2013, 11:20:46)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import daemon
>>> print daemon.__file__
/usr/lib/pymodules/python2.7/daemon/__init__.pyc

if you have not the __init__.pyc, may be you've installed a module that is also named daemon (like with a commande 'pip install daemon')


samedi 24 août 2013

Control a 12v relay with Arduino & Raspberry Outputs

To control a 12v relay from an output of a microcontroller, you just need a resistor, a NPN transistor and a diode ... and a relay of course !

Here's a sample :


The R1 value is generally 1K but it should be adapted to the microcontroller (output current/voltage) and the transistor.
The 2N2222 is a general purpose transistor and a lot of NPN transistor can be used.
The D1 diode is very important : it avoid current feedback on switching, don't forget it or you can damage the microcontroller !
The relay (K1) should be a 12V coil, but the switching load should be adapted to your need ! if you need to switch a 1A lamp, it is not the same as a 20A heater !

The 12v can be different depending on your need, it can vary from 5V to 24V,  but i don't recommand to go over 24V with this schematic (and especially with the 2N2222 which as a Vce max of 30V)... at higher voltage a optocoupler is prefered ... but it depends on the switching speed you need !