Setup:
Raspberry Pi 2 Model B V1.1
Raspbian Jessie Version March 2016
Hi I am new in the RPI world, I managed to setup 2 DHT22 temperature sensors connected to GPIOs 22 and 23, 2 analog temperature sensors and 1 light sensor connected to a MCP3008 analog to digital converter via hardware SPI. I also managed to send the readings every 5 seconds to a mysql library. I also setup a LAMP server. To send the values to the internet, I make use of the dweepy library to use the www.dweet.io website to eventually create a dashboard in freeboard.io. I was able to accomplish all that. The python code is located at /home/pi/python_programs/sensors.py
.
I want to run the code at startup, I was able to do that only after login as pi by doing this:
sudo nano /etc/profile
Scroll to the bottom and add the following line :
sudo python /home/pi/pythom_programs/sensors.py &
This only works after I SSH to the pi and then login as pi. I want the program to run without any intervention. I have already tried the @reboot in crontab -e, but it didn't work. I know that I have to go through systemd service setup since this is how the latest jessie runs its services (as far as I know). I have seen tutorials that deal with rc.local, but as far as I know, I MUST USE SYSTEMD IN THE LATEST JESSIE. I have tried several instructions online for systemd but I do not know how it works at all. Can somebody please help me.
@steverobillard Thank you for your response, I am also sorry I replied in the comment section. I followed your link and the python program worked partially. The program is supposed to read the sensors, store the values in a mysql database, then send them via internet to the dweet.io website, wait for 5 seconds and start from the beginning again). It reads the sensor, then saves the data in the mysql database, but it doesnt run the dweepy command dweepy.dweet_for('luxerel_rpi', binary,). This is the code for the luxerel.service file that I created:
[Unit]
Description=Luxerel Sensors
After=multi-user.target
[Service]
Type=idle
ExecStart=/usr/bin/python /home/pi/luxerel_programs/luxmspv1.py & > /home/pi/myscript.log 2>&1
[Install]
WantedBy=multi-user.target
When I test the service by entering sudo systemctl status -l luxerel.service y get the following output http://res.cloudinary.com/luxerel/image/upload/v1460048041/Capture_2_waeqqz.jpg
I think it is due to the network not being ready when systemd invokes the python script. I have seen the Wants and After commands included in the service file, but I do not know the right order, or in which sections to include them.
Please help me.
Thank you
@goldilocks Thank you for your help. I performed the following changes inside /home/pi/luxerel_programs:
$sudo nano startup.sh
Then entered this code:
*#!/bin/bash*
*exec &> /home/pi/myscript.log*
*echo $(date)*
*# Fork/exec*
*(*
*exec /usr/bin/python /home/pi/luxerel_programs/luxmspv1.py*
*) &*
*exit 0*
Then:
$sudo chmod 755 /home/pi/luxerel_programs/startup.sh
$sudo nano /lib/systemd/system/luxerel.service
I entered:
[Unit]
Description=Luxerel Sensors
Requires=local-fs.target
[Service]
Type=forking
GuessMainPID=no
StandardInput=null
ExecStart=/home/pi/luxerel_programs/startup.sh
[Install]
WantedBy=default.target
Then:
$sudo systemctl daemon-reload
$sudo systemctl enable luxerel.service
$sudo reboot
Once again it read everything but did not trigger the dweepy command at startup.
Please help!!!
Thank you!!
------------- UPDATE 04/08/2016 ---------------
@goldilocks, I thought it worked, but it didn't. I performed the following changes:
$ sudo nano /home/pi/luxerel_programs/startup.sh
*#!/bin/bash*
exec &> /home/pi/myscript.log
echo $(date)
*# Fork/exec*
(
*### Optional Code*
target=google.com
limit=100
count=0
while [ $count -lt $limit ]; do
count=$(($count+1))
ping -c 1 $target &> /dev/null
if [ $? -eq 0 ]; then
echo "Online."
break;
fi
echo "Ping $target failed..."
sleep 2
done
echo "$count pings."
*### End Optional Code*
exec /usr/bin/python /home/pi/luxerel_programs/luxmspv1.py
) &
exit 0
Then I entered
$ sudo chmod 755 /home/pi/luxerel_programs/startup.sh
$ sudo nano /lib/systemd/system/luxerel.service
[Unit]
Description=Luxerel Sensors
Requires=local-fs.target
[Service]
Type=forking
GuessMainPID=no
StandardInput=null
ExecStart=/home/pi/luxerel_programs/startup.sh
[Install]
WantedBy=default.target
I also tried adding Requires=network-online.target but it didn't work. For some reason, I think it worked once, but it didn't work again.
Please help me!!
Thank you!!
2 Answers 2
Systemd's primary documentation is in man pages, something you should like-it-or-not get used to reading. If reading them in a terminal is a little too old school for you, man -H
should display them in your browser if $BROWSER
is set (although I am not sure about this on Raspbian as I usually use it sans GUI, headless, and not all distros support this).
There's a stack of such man pages which apropos systemd
will show you (and see man apropos
for what that's about). There is a logic to their organization but you may have to read them a bit before it becomes clear. In this case we're interested in man systemd.unit
and man systemd.service
, which more-or-less correspond to documentation for the fields listed under those headings ([Unit]
and [System]
) from the service file. "More-or-less" meaning, not necessarily, some stuff is in man systemd.exec
and elsewhere. Note that man pages in the terminal are easily searchable via /, because the normal viewer is a program called less
, and that's a traditional "search key" in many traditional TUI apps (with which regular expressions can be used, in this case).
Anyway, I don't think making After=
and WantedBy=
the same is a very good idea. Generally your WantedBy=
should be default.target
, that way it is most likely to apply (although "default.target" may be "multi-user.target", it's also a target of its own).
I suggest you read man systemd.unit
to understand the difference between After=
, Requires=
, and WantedBy=
. You definitely need the last one, but the first two are optional.
In your case, I think you do need actual network connectivity for your script to work. This answer claims there is a systemd target for that, at least with some configurations.
A major problem I see is this:
[Service]
Type=idle
ExecStart=/usr/bin/python /home/pi/luxerel_programs/luxmspv1.py & > /home/pi/myscript.log 2>&1
First, type idle, described in the docs as a form of simple, is not necessarily "simple" in the sense of "simplest to use" (I think it's called that because it refers to something which is structurally "simple" in an init service context).
Second, doing bunches of shell redirection in the ExecStart
may or may not be allowed/encouraged/described in various tutorials or examples but I think it is a bad idea. There are other aspects of the [Service]
block intended to deal with this stuff, the only one you should bother with is:
StandardInput=null
Which in essence means this process does not expect or make use of any standard input.
There are corresponding ways to do redirection with StandardError
and StandardOutput
but I recommend against using them (all these are documented in man systemd.exec
, not systemd.service
), partially because they bring us back to the realm of the not-so-simple Type=simple
service.
Instead, capsulize your thing in its own startup script. I'm going to include in this how I would check to wait for network connectivity; you can try this if the network-online.target
mentioned later doesn't work.
#!/bin/bash
# Be sure that's 'bash' not just 'sh'.
exec &> /home/pi/myscript.log
echo $(date)
# Fork/exec
(
#### This starts the stuff you may not need.
target=google.com
limit=100
count=0
while [ $count -lt $limit ]; do
count=$(($count+1))
ping -c 1 $target &> /dev/null
if [ $? -eq 0 ]; then
echo "Online."
break;
fi
echo "Ping $target failed..."
sleep 2
done
echo "$count pings."
##### End of optional stuff.
exec /usr/bin/python /home/pi/luxerel_programs/luxmspv1.py
) &
exit 0
To explain the "optional stuff":
www.dweet.io
doesn't respond to pings, butgoogle.com
is very reliable this way.You may change the initial
limit
, and further down thesleep
duration (seconds) to extend how long to wait for. Right now this totals 200 seconds before it gives up (it will proceed immediately when the ping succeeds).
Now the service file:
[Unit]
Description=Luxerel Sensors
Requires=local-fs.target
Requires=network-online.target
[Service]
Type=forking
GuessMainPID=no
StandardInput=null
ExecStart=/path/to/the/start-up.sh
[Intall]
WantedBy=default.target
There's a Requires=local-fs.target
because almost anything useful (and certiainly this) first needs the root filesystem mounted properly.
The other Requires
comes from the other answer about waiting for network connectivity. Try that, and if it doesn't work, remove that line from the service file and try the ping loop in the wrapper script instead. If you do do that, be sure to check the log file. There should be a lot of stuff in there one way or the other.
Note if there is some mySQL service involved, prequisite, and systemd controlled, you should look into that. I'm not a mySQL user so I don't know.
systemctl list-units | grep -i sql
Should give you a clue about this. OTOH, by the time the network is online that should be going anyway.
The [Service]
part is primarily designed to make this something systemd will fire and forget, which is the real "simple" in the sense of "simplest to manage".
Disable your previous versions then try installing that one, systemctl enable whatever
, and see what happens.
-
Thank you for your response, please review my update. Thank you!!jmmb392– jmmb3922016年04月07日 23:04:48 +00:00Commented Apr 7, 2016 at 23:04
-
I realized when I re-read your question and error that you probably do need internet connectivity for that to work. I've added some stuff about this starting with the 5th paragraph above, which links to another Q&A at our big sibling site Unix & Linux, and then makes a couple of suggestions including an adaptation to the wrapper script.goldilocks– goldilocks2016年04月07日 23:46:30 +00:00Commented Apr 7, 2016 at 23:46
-
Dear friend, I added the extra pinging code to the bash file, and it worked as I wanted it to work. I really appreciate all your help. Thank you very much!!!jmmb392– jmmb3922016年04月08日 15:21:16 +00:00Commented Apr 8, 2016 at 15:21
-
Hi, I am sorry to bother you again, I thought that I had made it work, but I didn't. Please review my update. Once again, thank you for your cooperation.jmmb392– jmmb3922016年04月08日 23:05:45 +00:00Commented Apr 8, 2016 at 23:05
-
If there is literally nothing in
/home/pi/myscript.log
after boot you've done something wrong with enabling the service. At the very least it should have the output from$(date)
in it.goldilocks– goldilocks2016年04月08日 23:23:36 +00:00Commented Apr 8, 2016 at 23:23
In order to run script at startup, using crontab is fairly the best way.
Have you run crontab -e
as superuser (with sudo
)?
If not you must do so because only superuser can manage GPIO :
sudo crontab -e
If you did, why don't you try capturing what happens in an error log like so :
@reboot [command] > actions_log.txt
Also, does crontab work at all for you? You can do as follows to check :
@reboot touch test_file.txt
And see if the file is created or not.
-
Hi, thank you for your response, I think crontab is not working for me, I tried your test @reboot touch test_file.txt and the file was not created.jmmb392– jmmb3922016年04月07日 13:46:45 +00:00Commented Apr 7, 2016 at 13:46
-
Did you try getting errors in a log ?Ramanewbie– Ramanewbie2016年04月07日 16:22:28 +00:00Commented Apr 7, 2016 at 16:22
-
(@reboot [command] > actions_log.txt) If yes, what does the the log say ? Also, if not done yet you should restart your RPi and restart the crontab : sudo /etc/init.d/cron restartRamanewbie– Ramanewbie2016年04月07日 16:28:08 +00:00Commented Apr 7, 2016 at 16:28
systemd
service which runs a script but it requires a bit of study, as it is different in concept. See wiki.ubuntu.com/SystemdForUpstartUsers. I findcron
much easier. As you didn't post yourcron
we can't help. NOTE that the script (and everything it calls) NEEDS to be able run without logging in - no matter what method is used.