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
-
1please format all of your code, not just parts of itjsotola– jsotola2019年11月07日 01:39:29 +00:00Commented Nov 7, 2019 at 1:39
3 Answers 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 thebash
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.
-
1Awesome!! I have fooled around for two weeks just to try and get this going! A simple wait/sleep that fixed the problem.David Jr Wollmann– David Jr Wollmann2019年11月07日 17:20:40 +00:00Commented Nov 7, 2019 at 17:20
-
Another problem; How would I make it so if the connection is broken so it reconnects?David Jr Wollmann– David Jr Wollmann2019年11月09日 15:31:29 +00:00Commented 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?David Jr Wollmann– David Jr Wollmann2019年11月09日 15:35:03 +00:00Commented Nov 9, 2019 at 15:35
-
or when the client looses power/shuts down how do I reconnect them?David Jr Wollmann– David Jr Wollmann2019年11月09日 15:35:50 +00:00Commented Nov 9, 2019 at 15:35
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
-
1Sorry 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.David Jr Wollmann– David Jr Wollmann2019年11月07日 16:26:54 +00:00Commented Nov 7, 2019 at 16:26
-
1I know I need to make sure that all resources are running before executing, not sure how though.David Jr Wollmann– David Jr Wollmann2019年11月07日 16:27:38 +00:00Commented Nov 7, 2019 at 16:27
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.