1

I'm running a bell app connected by ENet between two RPI 4. The button end works well, but the server end only works when I sign in to activate it. How do I get it to start at start-up in Crontab?

@reboot python3 /home/pi/Coding/BellButton.py >> /home/pi/Coding/BellButton.log

Log has nothing

#!/usr/bin/env python3
import threading
import pygame.mixer
import automationhat
import datetime
from datetime import date
import time
import socket

class ButtonServer(threading.Thread):
    def __init__(self, channel, serverIP, serverPort):
        threading.Thread.__init__(self)
        self.channel = channel
        self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.serv.bind((serverIP,serverPort))
        self.serv.listen(5)
        self.BellButtonOne = -1
        self.BellButtonTwo = -1
        self.BellButtonThree = -1
        self.deamon = True
        self.start()

    def run(self):
        while True:
            conn, addr = self.serv.accept()
            from_client = ""

            while True:
                from_client = ""
                data = conn.recv(4096)

                if not data:
                    break

                from_client = data.decode()

                if from_client == "Input 1 On":
                    self.BellButtonOne = 1
                if from_client == "Input 1 Off":
                    self.BellButtonOne = 0

                if from_client == "Input 2 On":
                    self.BellButtonTwo = 1
                if from_client == "Input 2 Off":
                    self.BellButtonTwo = 0

                if from_client == "Input 3 On":
                    self.BellButtonThree = 1
                if from_client == "Input 3 Off":
                    self.BellButtonThree = 0
            conn.close()

B8 = ButtonServer(36,"123.456.789.123",12345)

pygame.mixer.init(48000, -16, 1, 1024)
pygame.mixer.init()

sndAChr = pygame.mixer.Sound("/home/pi/Public/Active/ChristmasChurchBell.wav")
sndBChr = pygame.mixer.Sound("/home/pi/Public/Active/ChristmasDinnerBell.wav")
sndA = pygame.mixer.Sound("/home/pi/Public/Active/ChurchBell.wav")
sndB = pygame.mixer.Sound("/home/pi/Public/Active/DinnerBell.wav")
sndB1 = pygame.mixer.Sound("/home/pi/Public/Active/DinnerBell2.wav")
sndB2 = pygame.mixer.Sound("/home/pi/Public/Active/DinnerBell3.wav")
sndC = pygame.mixer.Sound("/home/pi/Public/Active/Doing.wav")

snd1 = pygame.mixer.Sound("/home/pi/Public/Active/Doing.wav")
snd15 = pygame.mixer.Sound("/home/pi/Public/Active/Quarter.wav")
snd30 = pygame.mixer.Sound("/home/pi/Public/Active/Half.wav")
snd45 = pygame.mixer.Sound("/home/pi/Public/Active/3Quarter.wav")
snd100 = pygame.mixer.Sound("/home/pi/Public/Active/Hour.wav")

sc1 = pygame.mixer.Channel(1)
sc1.play(snd1)
playDoing = False

DinnerBellNo = 0
while True:
    tnow = datetime.datetime.now()
    today = date.today()
    ChristStartYear = date(today.year,11,19)
    ChristEndYear = date(today.year + 1,1,7)

    if B8.BellButtonOne == 1:
        if pygame.mixer.get_busy():
            playDoing = False
            pygame.mixer.stop()
        time.sleep(0.2)
        if B8.BellButtonOne == 0:
            if today >= ChristStartYear and today <= ChristEndYear:
                sc1.play(sndAChr)
            else:
                sc1.play(sndA)
            time.sleep(0.2)

    if B8.BellButtonTwo == 1:
        if pygame.mixer.get_busy():
            playDoing = False
            pygame.mixer.stop()
        time.sleep(0.2)
        if B8.BellButtonTwo == 0:
            if today >= ChristStartYear and today <= ChristEndYear:
                sc1.play(sndBChr)
            else:
                if DinnerBellNo == 2:
                    DinnerBellNo += 1
                    sc1.play(sndB2)
                if DinnerBellNo == 1:
                    DinnerBellNo += 1
                    sc1.play(sndB1)
                if DinnerBellNo == 0:
                    DinnerBellNo += 1
                    sc1.play(sndB)
                if DinnerBellNo == 3:
                    DinnerBellNo = 0
                time.sleep(0.2)

    if B8.BellButtonThree == 1:
        if pygame.mixer.get_busy():
            playDoing = False
            pygame.mixer.stop()
        time.sleep(0.2)
        if B8.BellButtonThree == 0:
            sc1.play(sndAChr)
            time.sleep(0.2)



    #On Board Buttons
    #if automationhat.input.one.is_on():
    #    if pygame.mixer.get_busy():
    #        playDoing = False
    #        pygame.mixer.stop()
    #    time.sleep(0.2)
    #    if automationhat.input.one.is_off():
    #        if today >= ChristStartYear and today <= ChristEndYear:
    #            sc1.play(sndAChr)
    #        else:
    #            sc1.play(sndA)
    #        time.sleep(0.2)

    #if automationhat.input.two.is_on():
    #    if pygame.mixer.get_busy():
    #        playDoing = False
    #        pygame.mixer.stop()
    #    time.sleep(0.2)
    #    if automationhat.input.two.is_off():
    #        if today >= ChristStartYear and today <= ChristEndYear:
    #            sc1.play(sndBChr)
    #        else:
    #            if DinnerBellNo == 2:
    #                DinnerBellNo += 1
    #                sc1.play(sndB2)
    #            if DinnerBellNo == 1:
    #                DinnerBellNo += 1
    #                sc1.play(sndB1)
    #            if DinnerBellNo == 0:
    #                DinnerBellNo += 1
    #                sc1.play(sndB)
    #            if DinnerBellNo == 3:
    #                DinnerBellNo = 0
    #        time.sleep(0.2)

    #if automationhat.input.three.is_on():
    #    if pygame.mixer.get_busy():
    #        playDoing = False
    #        pygame.mixer.stop()
    #    time.sleep(0.2)
    #    if automationhat.input.three.is_off():
    #        sc1.play(sndAChr)
    #        time.sleep(0.2)

    #Chime Clock
    if tnow.hour >= 6 and tnow.hour <= 22:
        if tnow.hour % 1 == 0 and tnow.minute == 0 and tnow.second == 0:
            if not pygame.mixer.get_busy():
                sc1.play(snd100)
                playDoing = True
            time.sleep(0.2)

    if tnow.hour >= 6 and tnow.hour <= 21:
        if tnow.minute % 15 == 0:
            if tnow.minute == 15 and tnow.second == 0:
                if not pygame.mixer.get_busy():
                    sc1.play(snd15)
                    time.sleep(0.2)
            if tnow.minute == 30 and tnow.second == 0:
                if not pygame.mixer.get_busy():
                    sc1.play(snd30)
                    time.sleep(0.2)
            if tnow.minute == 45 and tnow.second == 0:
                if not pygame.mixer.get_busy():
                    sc1.play(snd45)
                    time.sleep(0.2)

    if playDoing == True and not pygame.mixer.get_busy():
        h=tnow.hour
        if h > 12:
            h -= 12
        sc1.play(snd1, h-1)
        playDoing = False
1
  • 1
    please format all of your code, not just parts of it
    – jsotola
    Commented Nov 7, 2019 at 1:39

3 Answers 3

3

@Ingo has provided a good and correct answer. This answer is provided to augment Ingo's answer & provide details that may be helpful to your understanding.

Know that cron is useful, but to use it effectively, you should understand its limitations.

1. cron has no knowledge of the state of your system during the boot process.

This means that it is your responsibility to ensure that the services required to execute your @reboot entry in your crontab file are available before your script/program is started. In general, this can often be accomplished by simply adding a sleep statement to your @reboot entry in crontab.

2. cron runs under a different environment than your user id.

When you are logged in under a user id (pi for example), the OS has created an environment that includes (among other things) a default path in which to find executables. However, when your cron job executes, it is NOT executed with all of the same environment variables as your user id. Since cron's PATH environment variable is not defined same as your user id, then you should use a "complete" file specification (path) for your executable to ensure your system knows which file(s) you intend to execute or use.

If you want to explore this business of the environment in more detail:

  • To get your (user id) environment at the bash command line: printenv

  • To get the cron environment, use this technique

3. a failed cron job needs your help to tell you if or why it fails to execute.

This is related to the limitation above; i.e. your cron job is not actually run under your user id. Linux utilizes three (3) "streams" to communicate with a user: stdin, stderr and stdout. When you use a terminal to interact with your RPi, the system knows where to direct your input/commands at the terminal (stdin to a process), and it also knows to direct any output (stderr and stdout) from that process to your terminal. HOWEVER, unless you tell the system, it doesn't know where to direct the cron user's output or error messages. Thus, when a cron job fails to run, an error message is (may be) generated, but the system doesn't know where this "stream" should be directed, and you (your user id) doesn't have the benefit of this feedback. It's a bit like driving with your eyes closed. Recovering the stderr output from cron is accomplished with a simple "redirect" to a file.

OVERCOMING cron's LIMITATIONS

Fortunately, it's fairly straightforward to deal with all three of these limitations. I'll use your cron job to illustrate how you might deal with all these limitations by modifying your one line cron job:

@reboot ( /bin/sleep 30; /usr/bin/python3 /home/pi/Coding/BellButton.py  > /home/pi/cronjoblog 2>&1)   

If any of this is unclear, please let us know.

4
  • 1
    Awesome!! I have fooled around for two weeks just to try and get this going! A simple wait/sleep that fixed the problem. Commented Nov 7, 2019 at 17:20
  • Another problem; How would I make it so if the connection is broken so it reconnects? Commented Nov 9, 2019 at 15:31
  • When the server side looses power at power outages but the client doesn't how do I check if that happens to shut down the connection on both ends and reconnect? Commented Nov 9, 2019 at 15:35
  • or when the client looses power/shuts down how do I reconnect them? Commented Nov 9, 2019 at 15:35
2

You tagged the question with python-3 but you call everywhere python that is calling python 2. Because you don't tell us how do you start the script after login it is unclear why it then unexpected runs. You should also use full path calls in crontab:

@reboot /usr/bin/python3 /home/pi/Coding/BellButton.py >> /home/pi/Coding/BellButton.log

Also correct the shebang (first line) in your script to:

#!/usr/bin/env python3
2
  • 1
    Sorry Guys!, I don't know why it didn't format the code right, I pasted it and look good to me, after posting it was all jumbled together. Commented Nov 7, 2019 at 16:26
  • 1
    I know I need to make sure that all resources are running before executing, not sure how though. Commented Nov 7, 2019 at 16:27
2

In addition to what @ingo has stated, crontab can often start running your script before the Pi is able to do any networking, so it might be worth adding a sleep function to your code after your imports.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.