python

Python Daemon

Here is what I have, that works for me. It also has a sysv init script. Repo is at GitHub, and I also have a brief blog post with links to other possible solutions I found.

There can only be one daemon process running: that is managed by the PID lock file, like most other Linux daemons. To stop it, do

kill `cat /var/run/eg_daemon.pid`

To see if it is running:

ps -elf | grep `cat /var/run/eg_daemon.pid`

Using the pidfile submodule, the PID file is managed automatically. When the daemon is stopped, the pidfile is cleared up. Please see the linked GitHub repo for the init script.

Here’s the Python daemon code:

#!/usr/bin/env python3.5
import sys
import os
import time
import argparse
import logging
import daemon
from daemon import pidfile

debug_p = False

def do_something(logf):
    ### This does the "work" of the daemon

    logger = logging.getLogger('eg_daemon')
    logger.setLevel(logging.INFO)

    fh = logging.FileHandler(logf)
    fh.setLevel(logging.INFO)

    formatstr = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    formatter = logging.Formatter(formatstr)

    fh.setFormatter(formatter)

    logger.addHandler(fh)

    while True:
        logger.debug("this is a DEBUG message")
        logger.info("this is an INFO message")
        logger.error("this is an ERROR message")
        time.sleep(5)


def start_daemon(pidf, logf):
    ### This launches the daemon in its context

    ### XXX pidfile is a context
    with daemon.DaemonContext(
        working_directory='/var/lib/eg_daemon',
        umask=0o002,
        pidfile=pidfile.TimeoutPIDLockFile(pidf),
        ) as context:
        do_something(logf)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Example daemon in Python")
    parser.add_argument('-p', '--pid-file', default='/var/run/eg_daemon.pid')
    parser.add_argument('-l', '--log-file', default='/var/log/eg_daemon.log')

    args = parser.parse_args()

    start_daemon(pidf=args.pid_file, logf=args.log_file)

For completeness’ sake, here is the init script. Note that “kill” is really just a method for sending a POSIX signal — see man page for signal(7) for an overview. The python-daemon context will catch the signal, terminate the process cleanly closing file descriptors, and delete the PID file automatically. So, it really is a clean termination.

You can write your code to catch SIGUSR1 or something similar, in order to do a reload of the daemon config. There is no advantage to writing Python stop the daemon.

#!/bin/bash
#
# eg_daemon      Startup script for eg_daemon
#
# chkconfig: - 87 12
# description: eg_daemon is a dummy Python-based daemon
# config: /etc/eg_daemon/eg_daemon.conf
# config: /etc/sysconfig/eg_daemon
# pidfile: /var/run/eg_daemon.pid
#
### BEGIN INIT INFO
# Provides: eg_daemon
# Required-Start: $local_fs
# Required-Stop: $local_fs
# Short-Description: start and stop eg_daemon server
# Description: eg_daemon is a dummy Python-based daemon
### END INIT INFO

# Source function library.
. /etc/rc.d/init.d/functions

if [ -f /etc/sysconfig/eg_daemon ]; then
        . /etc/sysconfig/eg_daemon
fi

eg_daemon=/var/lib/eg_daemon/eg_daemon.py
prog=eg_daemon
pidfile=${PIDFILE-/var/run/eg_daemon.pid}
logfile=${LOGFILE-/var/log/eg_daemon.log}
RETVAL=0

OPTIONS=""

start() {
        echo -n $"Starting $prog: "

        if [[ -f ${pidfile} ]] ; then
            pid=$( cat $pidfile  )
            isrunning=$( ps -elf | grep  $pid | grep $prog | grep -v grep )

            if [[ -n ${isrunning} ]] ; then
                echo $"$prog already running"
                return 0
            fi
        fi
        $eg_daemon -p $pidfile -l $logfile $OPTIONS
        RETVAL=$?
        [ $RETVAL = 0 ] && success || failure
        echo
        return $RETVAL
}

stop() {
    if [[ -f ${pidfile} ]] ; then
        pid=$( cat $pidfile )
        isrunning=$( ps -elf | grep $pid | grep $prog | grep -v grep | awk '{print $4}' )

        if [[ ${isrunning} -eq ${pid} ]] ; then
            echo -n $"Stopping $prog: "
            kill $pid
        else
            echo -n $"Stopping $prog: "
            success
        fi
        RETVAL=$?
    fi
    echo
    return $RETVAL
}

reload() {
    echo -n $"Reloading $prog: "
    echo
}

# See how we were called.
case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  status)
    status -p $pidfile $eg_daemon
    RETVAL=$?
    ;;
  restart)
    stop
    start
    ;;
  force-reload|reload)
    reload
    ;;
  *)
    echo $"Usage: $prog {start|stop|restart|force-reload|reload|status}"
    RETVAL=2
esac

exit $RETVAL

ESP8266 WiFi module

Link for add board manager

http://arduino.esp8266.com/stable/package_esp8266com_index.json

Erase the esp

esptool.py erase_flash

Code to flash AT firmware to ESP8266 (ESP8266_AT_Bin_V1.5.1)

esptool.py --baud 115200 --port /dev/tty.wchusbserial1420 write_flash -fm dio -ff 40m -fs detect 0x00000 boot_v1.7.bin 0x01000 user1.1024.new.2.bin 0xfc000 esp_init_data_default.bin 0x7e000 blank.bin 0xfe000 blank.bin

Arduino and Python

If you want to read Arduino serial from Python.

Install pySerial:

pip intall pyserial

the code:

import serial
...
print('# Arduino Reader - hackweb')
print('entering loop...')

ardu = serial.Serial('COM3', 115200)

time.sleep(2)

while True:

print(ardu.readline())