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

:

Aucun commentaire:

Enregistrer un commentaire