• Home
  • Help
  • Search
  • Login
  • Register
Pages: [1]
Author Topic: Is there a python guru`s out there?  (Read 3301 times)
peter a
Full Member
***

Karma: 0
Posts: 132


View Profile
« on: April 03, 2010, 01:47:10 AM »

Is there a python guru`s out there?
Hi, I`m trying to daemonise a python script, I found a demo script for this, but don`t know where to end my part of the code.

My code is basically two parts:-

1/ Set things up like the USB ports which should be only done once at the start.
2/ a endless while loop , looking at a buffer and acting on it

This is the code I`ve found for Daemonising , which works , but without any payload program added.
Thanks in advance Peter
Code:
#! /usr/bin/python

import sys, os, time, atexit
from signal import SIGTERM

class Daemon:
"""
A generic daemon class.

Usage: subclass the Daemon class and override the run() method
"""
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.pidfile = pidfile

def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)

# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)

# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)

# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
se = file(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())

# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+').write("%s\n" % pid)

def delpid(self):
os.remove(self.pidfile)

def start(self):
"""
Start the daemon
"""
# Check for a pidfile to see if the daemon already runs
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None

if pid:
message = "pidfile %s already exist. Daemon already running?\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1)

# Start the daemon
self.daemonize()
self.run()

def stop(self):
"""
Stop the daemon
"""
# Get the pid from the pidfile
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None

if not pid:
message = "pidfile %s does not exist. Daemon not running?\n"
sys.stderr.write(message % self.pidfile)
return # not an error in a restart

# Try killing the daemon process
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print str(err)
sys.exit(1)

def restart(self):
"""
Restart the daemon
"""
self.stop()
self.start()

def run(self):
"""
You should override this method when you subclass Daemon. It will be called after the process has been
daemonized by start() or restart().
"""
 

class MyDaemon(Daemon):
def run(self):
while True:
time.sleep(1)

if __name__ == "__main__":
daemon = MyDaemon('/tmp/daemon-example.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]:
daemon.start()
elif 'stop' == sys.argv[1]:
daemon.stop()
elif 'restart' == sys.argv[1]:
daemon.restart()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
else:
print "usage: %s start|stop|restart" % sys.argv[0]
sys.exit(2)



cli part

Code:
#! /usr/bin/python

# Echo client program
import socket
import time

# set returns ok unless error
# -1 = not check , set , help
# -2 = set can`t have analog
# -3 = port number too high or low
# -4 = not on , off , input , output , toggle

HOST = 'localhost'        # The remote host
PORT = 50007              # The same port as used by the server
debug = 1

def send_to_daemon(data_s):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send(data_s.strip()+'\n')
data_r = s.recv(1024)
if debug:print data_s.strip() ,' - ', data_r
s.close()
return data_s


send_to_daemon('set 12 on')

time.sleep(1) 

send_to_daemon('set 12 off')
send_to_daemon('set 12 toggle')
« Last Edit: April 03, 2010, 08:15:44 AM by peter a » Logged

fragfutter
Sr. Member
****

Karma: 12
Posts: 280


View Profile
« Reply #1 on: April 03, 2010, 03:49:45 AM »

There is a broken blank between "#! /usr/bin/python". The Rest is fine. What is your problem?

Code:
/usr/bin/python daemon.py start
ls -l /tmp/daemon-example.pid
ps -ef|grep python
/usr/bin/python daemon.py stop
[code]
[/code]
Logged

peter a
Full Member
***

Karma: 0
Posts: 132


View Profile
« Reply #2 on: April 03, 2010, 04:40:22 AM »

I`m having a bit of running before I`m walking problems.
The problem was having no error messages to go on I didn`t know what the problem was with my code I added to the daemon script.
I`m going to have to learn a little more about class set up !!!
Logged

fragfutter
Sr. Member
****

Karma: 12
Posts: 280


View Profile
« Reply #3 on: April 03, 2010, 05:10:45 AM »

I think you ran into an understanding problem. A daemon detaches from the controling terminal and you don't get any output from it. You might want to write your code first and daemonize it later.

Code:
class MyClass(object):
   def __init__(self):
      pass
   def dosomething(self):
      pass

class MyDaemon(Daemon):
   def run(self):
      MyClass().dosomething()

# testing with
MyClass().dosomething()

# later
MyDaemon().start()
[code]

A budy polling every second is a bad idea. Maybe you want to describe your Problem, it is propably not necessary to write a daemon.
[/code]
Logged

peter a
Full Member
***

Karma: 0
Posts: 132


View Profile
« Reply #4 on: April 03, 2010, 06:15:40 AM »

o.k , my task is to control a Arduino via a cgi script.
But why I need some form of daemon, was because each time I invoked the script which connected to the USB port with  ‘self = serial.Serial('/dev/ttyUSB2', 19200, timeout=10)’ and would reinitialise the Arduino.

Quote
You might want to write your code first and daemonize it later.
Yep, that`s what I had to do to get it working, move my code just before the daemonize .
Logged

birdman
Sr. Member
****

Karma: 4
Posts: 443


View Profile WWW
« Reply #5 on: April 03, 2010, 06:33:41 AM »

o.k , my task is to control a Arduino via a cgi script.
So not a daemon - which is a continuously running process.  A daemon wouldn't use stdout - a CGI script may well do so, to return info to the calling client.  And a CGI script would get input data using the CGI API (RFC3875).  In Perl you'd use the CGI module to do this for you, but I have no idea how Python would do it.
Logged

peter a
Full Member
***

Karma: 0
Posts: 132


View Profile
« Reply #6 on: April 03, 2010, 06:48:25 AM »

Yes I can agree with that “a continuously running process” or a form of proxy service.
It`s not the cgi part which is the problem, it`s the need to keep control of the USB port not let it  reinitialise after each call.
Logged

fragfutter
Sr. Member
****

Karma: 12
Posts: 280


View Profile
« Reply #7 on: April 03, 2010, 07:05:19 AM »

so you need two parts? A Daemon that opens the ttyUSB and waits for commands. And a CGI-Program that can communicate with the daemon?

Why is reopening the serial port resetting the arduino? It shouldn't know if anything is accessing it or not. It's a serial port. But if you realy need the daemon, i would work like this

create a socket in /var/tmp. Open serial port, do your initialization, attach stdout and stdin to the socket. Done with the daemon part. But that should actually not be different then opening and closing ttyUSB every time.
Logged

peter a
Full Member
***

Karma: 0
Posts: 132


View Profile
« Reply #8 on: April 03, 2010, 08:13:44 AM »

Why is reopening the serial port resetting the arduino?
I think it`s something to do with the rts / cts lines, which it uses as a auto reset for reprogramming.
I`ve completed my demo program which work o.k now, not very pretty , but I will improve as my python programming skills improve.

Daemon part :-

Code:
#! /usr/bin/python

import sys, os, time, atexit
import serial , string , socket

from signal import SIGTERM


class Daemon:
"""
A generic daemon class.

Usage: subclass the Daemon class and override the run() method
"""
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.pidfile = pidfile

def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)

# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)

# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)

# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
se = file(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())

# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+').write("%s\n" % pid)

def delpid(self):
os.remove(self.pidfile)

def start(self):
"""
Start the daemon
"""
# Check for a pidfile to see if the daemon already runs
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None

if pid:
message = "pidfile %s already exist. Daemon already running?\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1)

# Start the daemon

self.daemonize()
self.my_prog()
self.run()

def stop(self):
"""
Stop the daemon
"""
# Get the pid from the pidfile
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None

if not pid:
message = "pidfile %s does not exist. Daemon not running?\n"
sys.stderr.write(message % self.pidfile)
return # not an error in a restart

# Try killing the daemon process
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print str(err)
sys.exit(1)

def restart(self):
"""
Restart the daemon
"""
self.stop()
self.start()

def run(self):
"""
You should override this method when you subclass Daemon. It will be called after the process has been
daemonized by start() or restart().
"""
def my_prog(self):
self = serial.Serial('/dev/ttyUSB0', 19200, timeout=10)
self.flushInput()
time.sleep(2)       # 2 seconds ... gives a chance for the arduino to wake up ...
HOST = ''
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
a = 0
while a == 0:
conn, addr = s.accept()
data = conn.recv(1024)
self.write(data)
dat = self.readline().strip()
conn.send(dat)
conn.close()


class MyDaemon(Daemon):
def run(self):
while True:
time.sleep(1)

if __name__ == "__main__":
daemon = MyDaemon('/tmp/daemon-example.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]:
daemon.start()
elif 'stop' == sys.argv[1]:
daemon.stop()
elif 'restart' == sys.argv[1]:
daemon.restart()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
else:
print "usage: %s start|stop|restart" % sys.argv[0]
sys.exit(2)

cli - cgi part

Code:
#! /usr/bin/python

# Echo client program
import socket
import time

# set returns ok unless error
# -1 = not check , set , help
# -2 = set can`t have analog
# -3 = port number too high or low
# -4 = not on , off , input , output , toggle

HOST = 'localhost'        # The remote host
PORT = 50007              # The same port as used by the server
debug = 1

def send_to_daemon(data_s):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send(data_s.strip()+'\n')
data_r = s.recv(1024)
if debug:print data_s.strip() ,' - ', data_r
s.close()
return data_s


send_to_daemon('set 12 on')

time.sleep(1) 

send_to_daemon('set 12 off')
send_to_daemon('set 12 toggle')
Logged

Pages: [1]
Print
Jump to: