Page 1 of 1

Python script fail @reboot

Posted: Thu Apr 21, 2016 12:10 pm
by ilfra
Hello to everyone, I hope someone can help me to solve my issue that make me crazy.
This is my simple code in python, if I run it in console (with or without sudo), it works perfectly: it does the http get and turn on the light.
But if I configure it to automatically start at boot, by cron or /etc/rc.local, it fails. The last command in log is logger.debug('Conf: %s', zone) (it prints correctly 'Conf: 4') in initEva(). If I comment the next row (bulb.off(zone)) it goes ahead until weather_data = get('...') in get_time_to_switch_on().
It never stop, the process is running (the led "breath").
In crontab I've written: @reboot python3 /home/pi/EVA/eva.py.
I've also tried to write it in root crontab but nothing.
I've also tried to call by cron a .sh script that call my python code but nothing
What's wrong with it?? Something related to user permission? Or to thread?

Thanks to everyone that can help me.

Code: Select all

#!/usr/bin/python3
# EVA
# v0.3

import os
import time
from requests import get
from datetime import datetime
from calendar import timegm
import ledcontroller
import RPi.GPIO as GPIO
import threading
from gtts import gTTS
from random import randint
import logging
import logging.handlers
import sys
import signal
import json






####### FUNCTIONS #######

def log_setup(level, logDir, logFile):
    levels = {'CRITICAL' : logging.CRITICAL,
        'ERROR' : logging.ERROR,
        'WARNING' : logging.WARNING,
        'INFO' : logging.INFO,
        'DEBUG' : logging.DEBUG
    }
    logFileName = logDir + '/' + logFile
    logger = logging.getLogger(os.path.basename(__file__))
    # add a rotating handler
    handler = logging.handlers.RotatingFileHandler(logFileName, maxBytes=50000000, backupCount=5)
    log_format = logging.Formatter("%(name)s %(asctime)s %(levelname)s : %(message)s")
    handler.setFormatter(log_format)
    logger.addHandler(handler)
    logger.setLevel(levels[level])
    return logger


def sigterm_handler(_signo, _stack_frame):
    GPIO.cleanup()
    sys.exit(0)

signal.signal(signal.SIGTERM, sigterm_handler)


def initEVA():
    logger.debug('Start init.')
    logger.debug('light: %s', EVAconf['light']['light_is_on'])
    for zone in EVAconf['light']['led_zones']:
        logger.debug('Conf: %s', zone)
        bulb.off(zone)
    logger.debug('step 1')
    EVAconf['light']['light_is_on'] = False
    logger.debug('step 2')
    EVAconf['light']['time_to_switch_on'] = get_time_to_switch_on()
    logger.debug('step 3')
    EVAconf['light']['last_check_time_to_switch_on'] = int(time.time())+get_time_offset()
    logger.debug('step 4')
    EVAconf['light']['light_is_on'] = False
    logger.debug('End init.')


def heartbeat():
    logger.debug('Start heartbeat.')
    LedPin = EVAconf['ledBlue']['pin']
    GPIO.setmode(GPIO.BCM)  # Numbers GPIOs by physical location
    GPIO.setup(LedPin, GPIO.OUT)  # Set LedPin's mode is output
    GPIO.output(LedPin, GPIO.LOW)  # Set LedPin to low(0V)
    p = GPIO.PWM(LedPin, 50)     # set Frequece to 1KHz
    p.start(0)                     # Duty Cycle = 0
    try:
        while EVAconf['ledBlue']['breath']:
            for dc in range(0, 101, 4):   # Increase duty cycle: 0~100
                p.ChangeDutyCycle(dc)     # Change duty cycle
                time.sleep(0.1)
            for dc in range(100, -1, -4): # Decrease duty cycle: 100~0
                p.ChangeDutyCycle(dc)
                time.sleep(0.1)
            time.sleep(20)
    except KeyboardInterrupt:
        pass
    p.stop()
    #GPIO.cleanup()
    print('stop heartbeat!!!')








def get_time_offset():
    t=time.localtime()
    return(int(timegm(t)-timegm(time.gmtime(time.mktime(t)))))


def get_time_to_switch_on():
    logger.debug('Aggiornamento ora accensione luci giardino in corso.')
    weather_data = get('http://api.openweathermap.org/data/2.5/weather?id={}&APPID={}'.format(EVAconf['meteo']['city_id'], EVAconf['meteo']['key']))
    logger.debug('weather data.')
    weather_data_json = weather_data.json()
    time = weather_data_json['sys']['sunset'] + get_time_offset() + 60*EVAconf['light']['diffmin_to_switch_on']
    logger.debug('Accensione luci giardino alle ore: %s' % datetime.fromtimestamp(int(time-get_time_offset())).strftime('%Y-%m-%d %H:%M:%S'))
    return time
    #return 1458173100


def get_time_to_switch_off():
    return int(time.mktime(datetime.strptime(time.strftime("%d/%m/%Y") + ' ' + EVAconf['light']['time_to_switch_off'], "%d/%m/%Y %H:%M").timetuple()) + get_time_offset())

def accendi_luci_giardino():
#    voice('Accensione luci giardino in corso')
    logger.debug('Accensione luci giardino.')
    for zone in EVAconf['light']['led_zones']:
        bulb.set_brightness(30, zone)


def spegni_luci_giardino():
#    voice('Spegnimento luci giardino in corso')
    logger.debug('Spegnimento luci giardino.')
    for zone in EVAconf['light']['led_zones']:
        bulb.off(zone)


# MAIN

EVAconf = {
    'ledBlue':
        {
            'pin': 26,
            'breath': True
        },
    'light':
        {
            'ledcontrollerIP': '192.168.0.9',
            'retry': 20,
            'led_zones': [4],
            'last_check_time_to_switch_on': '',
            'time_to_switch_on': '',
            'light_is_on': False,
            'diffmin_to_switch_on': 30,
            'time_to_switch_off': '23:50'
        },
    'meteo':
        {
            'key': 'b3c7f3d6733f527d1f81a6dc8481061f',
            'city_id': '3179809'
        }
}

bulb = ledcontroller.LedController(EVAconf['light']['ledcontrollerIP'], repeat_commands=EVAconf['light']['retry'])
bulb.on(4)

evaDir = '/home/pi/EVA'
logFile = 'eva.log'
logLevel = 'DEBUG'
logger = log_setup(logLevel, evaDir, logFile)

logger.info('               ---------------                  \n')
logger.info('Start Eva')

EVAconf['ledBlue']['breath'] = True
thread_heartbeat = threading.Thread(target=heartbeat, args=())
thread_heartbeat.start()
time.sleep(2)
initEVA()


try:
    logger.debug('Start pre loop.')
    while True:
        logger.info('Start loop')
        now_unix = int(time.time())+get_time_offset()
        after_noon = int(time.mktime(datetime.strptime(time.strftime("%d/%m/%Y") + ' 12:00', "%d/%m/%Y %H:%M").timetuple()) + get_time_offset())

    #####   Light garden   #####
        time_to_switch_on = EVAconf['light']['time_to_switch_on']
        if(now_unix > (EVAconf['light']['last_check_time_to_switch_on']+get_time_offset()+3600)):
            EVAconf['light']['time_to_switch_on'] = get_time_to_switch_on()
            EVAconf['light']['last_check_time_to_switch_on'] = now_unix

    #####   Switch on Light garden  #####
        if( (now_unix > after_noon) &
            (now_unix > time_to_switch_on) &
            (now_unix < get_time_to_switch_off()) &
            (not EVAconf['light']['light_is_on'])):
            accendi_luci_giardino()
            EVAconf['light']['light_is_on'] = True

    #####   Switch off Light garden  #####
        if((now_unix > get_time_to_switch_off()) & (EVAconf['light']['light_is_on'])):
            spegni_luci_giardino()
            EVAconf['light']['light_is_on'] = False

except KeyboardInterrupt:
    GPIO.cleanup()





Re: Python script fail @reboot

Posted: Fri Apr 22, 2016 8:31 am
by keithellis
Hi there, I have had a similar problem with python code not starting at boot.

I was also calling data from the internet. What was happening, it would try to call the internet, the internet connection was not up yet so the code bombed out. For me the easy way to deal with it was to put a time.sleep(10) command at the beginning.

The better way would be to find out what exception is being created, possibly a ConnectionError exception. You could then use a try: exception statement to catch it and pause then retry until indefinitely, That way when the internet connection comes up the script will start working.

My example looks something like this

Code: Select all

def get_temp(self, fieldID=1):
		self.fieldID = fieldID
		try:
			return round(float(self.channel.get_field_last_text(field=self.fieldID)),1)
		except Exception:
			return "9999"
Then later on

Code: Select all

	t = temp.get_temp()  #1 = external temperature; 2 = internal temperature
	while t == "9999":
		t = temp.get_temp()  #1 = external temperature; 2 = internal temperature
		time.sleep(2)
Keith.

Re: Python script fail @reboot

Posted: Fri Apr 22, 2016 9:10 am
by ilfra
Great!! It was the lan connection! The bulbs to switch on/off are wifi bulbs and without a lan connection probably the script hangs.
Yes, I have to put a try catch inside the loop (or somewere else) to check the lan connection.
Thank you very much, you give me my sleep back :D

Re: Python script fail @reboot

Posted: Fri Apr 22, 2016 9:18 am
by keithellis
ilfra wrote:Great!! It was the lan connection! The bulbs to switch on/off are wifi bulbs and without a lan connection probably the script hangs.
Yes, I have to put a try catch inside the loop (or somewere else) to check the lan connection.
Thank you very much, you give me my sleep back :D
No problem, glad I could help, it took me a while to figure it out.
Keith.

Re: Python script fail @reboot

Posted: Wed May 02, 2018 8:48 am
by ayu_geek
I am also facing the same problem.
Code runs fine from interpreter but during reboot it shows error in importing a library - import gtts saying that "ImportError : No module named gtts".
I tried using time.sleep(100) , but to no help!
The importing of library doesn't even require internet then why is this happenning to me :roll: :roll:
Please help

Re: Python script fail @reboot

Posted: Wed May 02, 2018 2:00 pm
by pfletch101
ayu_geek wrote:
Wed May 02, 2018 8:48 am
I am also facing the same problem.
Code runs fine from interpreter but during reboot it shows error in importing a library - import gtts saying that "ImportError : No module named gtts".
I tried using time.sleep(100) , but to no help!
The importing of library doesn't even require internet then why is this happenning to me :roll: :roll:
Please help
Problems running scripts at boot that run normally from the command line can result from hidden assumptions in the script about where external (to the script) files are. Remember that scripts run at boot are run as if from the user's home folder. Generally speaking, import libraries that have been installed in the normal way will be found by the python interpreter regardless of where a script is invoked from, but import libraries that have simply been placed in the same folder as the script will only be found if it is invoked from that folder. This may be your problem. An easy way of avoiding that problem is to make a habit of running boot scripts from a bash command file which starts by cding to the script's home folder.

Re: Python script fail @reboot

Posted: Wed May 02, 2018 3:02 pm
by Paul Hutch
ayu_geek wrote:
Wed May 02, 2018 8:48 am
I am also facing the same problem.
Code runs fine from interpreter but during reboot it shows error in importing a library - import gtts saying that "ImportError : No module named gtts".
I tried using time.sleep(100) , but to no help!
The importing of library doesn't even require internet then why is this happenning to me :roll: :roll:
Please help
Does it give the error if you run it from a command prompt with sudo?

If yes, it means the library is not installed for root, so you need to install it for root.