Fast boot to python script without networking?

Hello,

I apologize in advance for my kindergarten-level working knowledge of Linux.

I am developing a wildlife camera based on Pi Zero. To conserve battery power the Pi will remain powered down until an Arduino supervisor (http://spellfoundry.com/product/sleepy-pi-2/) detects motion via a passive infrared sensor. Once motion is detected it is critical to get the Pi booted up and running my python camera script ASAP to capture the pictures.

I am not too keen on learning buildroot to try create my own custom fast-boot os image and DietPi seems to have GREAT potential as a lightweight customizable platform for my application, but it still takes ~19 seconds to boot (see systemd-analyze critical-chain output below). I would still like to cut that in half or better and would really appreciate any suggestions for how to improve it!

Removing networking is one obvious optimization as it takes 3+ seconds (even with static IP) and is not needed to take a picture. Moreover, I specifically want to keep WLAN powered down to save battery except for one specific scheduled time per day when it will wake-up and “phone home” to Google Drive. How can I do this?

What about dietpi-boot, ramdisk and/or dev-mmcblk0p1 services, which together total over 13 secs? Can these be sped up in any way? FWIW, I am already using a very fast SD card.

Anything further that can be done with overclocking (there only seems to be one profile available for Pi Zero)?

Thanks!

systemd-analyze critical-chain:

graphical.target @18.846s
└─multi-user.target @18.838s
  └─getty.target @18.836s
    └─getty@tty1.service @18.828s
      └─rc-local.service @18.792s
        └─[1;31mdietpi-boot.service @13.924s +4.847s[0m
          └─[1;31mdietpi-ramdisk.service @11.396s +2.414s[0m
            └─basic.target @11.367s
              └─timers.target @11.339s
                └─systemd-tmpfiles-clean.timer @11.339s
                  └─sysinit.target @11.272s
                    └─[1;31mnetworking.service @7.974s +3.216s[0m
                      └─local-fs.target @7.718s
                        └─[1;31mboot.mount @7.525s +152ms[0m
                          └─[1;31msystemd-fsck@dev-mmcblk0p1.service @6.344s +570ms[0m
                            └─dev-mmcblk0p1.device @6.241s

Hi,

Yep its lightweight, but boot does take a little longer than non-DietPi minimal images. This is mainly for the RAMdisk and RAMlog creation, detection of hardware info of system, used in DietPi scripts (eg: network index, network enabled, network online, CPU type, CPU arch, launch ntpd, etc etc).

Static IP and disabling DietPi-RAMlog was a good start.

└─[1;31mdietpi-boot.service @13.924s +4.847s[0m
└─[1;31mdietpi-ramdisk.service @11.396s +2.414s[0m

RAMdisk is critical to DietPi operation, so that cant be disabled.

You could probably tweak/remove some commands from boot script, but either way, I cant see any worth-while reduction to boot times to warrant it.
I’am not sure what boot times your aiming for, but for me, unless its <3 seconds, you may miss the wildlife completely? :frowning:

Have you considered leaving the system running, forcing 600MHz + powersave, power usage too much?

Once motion is detected it is critical to get the Pi booted up and running my python camera script ASAP to capture the pictures.

Hibernation/sleep may be an option to skip boot altogether, although i’ve never tested this and not sure RPi even supports it:
https://wiki.archlinux.org/index.php/Power_management/Suspend_and_hibernate

Anything further that can be done with overclocking (there only seems to be one profile available for Pi Zero)?

We only add overclocking values that have been tested by us, and prove “stable”. Haven’t had a chance to add more yet, although, you could modify /DietPi/config.txt as needed for manual overclocking tweaks.

Moreover, I specifically want to keep WLAN powered down to save battery except for one specific scheduled time per day when it will wake-up and “phone home” to Google Drive. How can I do this?

Cron job for the scheduled time /etc/cron.daily/myscript, use dietpi-cron to change times. Without RTC/network for time sync, system time may slew and be slightly off.

WLAN, I believe bringing the adapter down, should also power it off:

ifdown wlan0

Then when you need it

ifup wlan0

Thanks for the reply. My understanding is the Pi SoC has no support for true low power mode. Standby power consumption needs to be <1mA to keep from draining the battery, which is already pretty big 5Ah 12V lead acid + 5W solar panel.

I would like to get boot under 10 seconds, but I’ll take any improvement I can get relatively easily then deploy it and see how many missed triggers I have before delving into something really difficult (e.g. buildroot custom image). Since loading the networking service is over 3 seconds could I at least remove that? Or, in the alternative, would it be better to run my python script as a service earlier in the boot sequence? All it needs is the file system and camera.

BTW, the Arduino supervisor (http://spellfoundry.com/product/sleepy-pi-2/) includes HW RTC so I will only run NTP once per day when I fire up the WLAN.

Thanks again.

Yep that should do it.

The following systemD service will launch a python script /root/myscript.py before networking, and, after local FS mounted:

cat << _EOF_ > /etc/systemd/system/python.service
[Unit]
Description=Python start script early
After=local-fs.target
Before=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python /root/myscript.py

[Install]
WantedBy=network.target
_EOF_
systemctl daemon-reload
systemctl enable python.service

Thanks. That worked (in my case I also needed to use WorkingDirectory= ).

However there is still the issue that after booting WLAN will be up and burning power. And if the WLAN hotspot is not found (which will be the normal case except for the pre-determined daily time window when the hotspot will be fired up), then I assume the networking service startup may drag on even longer while attempting to establish a connection before timing out.

I suppose I could create another service that runs after network-online.target to run “ifdown wlan0”, but seems like it would be cleaner to just remove the network initialization from the boot sequence altogether and defer it to be started by my python script if/when it is appropriate. Any hints on how I can do that?

Thanks again.

Yep thats best route.

You should be able to control it via /etc/network/interfaces
To disable from coming up automatically during boot:
In /etc/network/interfaces , comment out:

#allow-hotplug wlan0

Reload systemd

systemctl daemon-reload

To enable/start:
In /etc/network/interfaces , uncomment:

allow-hotplug wlan0

Reload systemd

systemctl daemon-reload

Start hostapd

systemctl restart hostapd

To stop:

systemctl stop hostapd
#Might not be needed
ifdown wlan0

In /etc/network/interfaces , comment out:

#allow-hotplug wlan0

Reload systemd

systemctl daemon-reload

Thanks for the continued advice. I have not had a chance to try this yet. Will be somewhat tricky to modify /etc/network/interfaces on the fly from within my python script. :thinking:

Just out of curiosity, why is ‘hostapd’ involved when my device is a client not an AP?

You could exec shell commands from Python:
http://stackoverflow.com/questions/89228/calling-an-external-command-in-python

The following will replace line starting with FORCE= to FORCE=force in /etc/default/fake-hwclock:

sed -i '/^FORCE=/c\FORCE=force' /etc/default/fake-hwclock

If you installed the WiFi Hotspot? This contains HostAPD. If you didnt, it shouldnt be installed. Can you please list the installed software on system so we can verify?

dietpi-software list | grep ' =2 '

I have not installed the WiFi Hotspot. Here is what I am using (most of which I will remove from the final image once I am done developing):

id 6 | =2 | xserver: linux display system |
id 17 | =2 | git client: git clone etc |
id 23 | =2 | lxde: ultra lightweight desktop | +alsa +xserver | https://dietpi.com/forum/t/dietpi-software-details-for-all-installation-options/22/1
id 27 | =2 | tightvnc server: desktop for remote connection | +desktop | https://dietpi.com/forum/t/resolved-cannot-log-in-to-the-mysql-server/41/1
id 96 | =2 | samba: feature-rich file server | | http://dietpi.com/phpbb/viewtopic.php?f=8&t=5&start=10#p56
id 103 | =2 | dietpi-ramlog: minimal, optimized logging | | https://dietpi.com/forum/t/dietpi-survey-information/32/1
id 104 | =2 | dropbear: ssh server | | https://dietpi.com/forum/t/dietpi-survey-information/32/1

Thanks,

Strange, none of those software titles would be pulling in hostapd. Not sure how its been installed.
Did you install any software manually through apt-get that you can remember?

Yes, I have installed some python and camera-related software using apt-get, however, to be clear, I have no reason to think hostapd is currently installed I was just asking about it because of your prior post:

To enable/start:
In /etc/network/interfaces , uncomment:
allow-hotplug wlan0

Reload systemd
systemctl daemon-reload

Start > hostapd
systemctl restart > hostapd

Thanks again.

Ah yes, apologies.

I assumed you used dietpi-software to install WiFi hotspot :slight_smile:

I’m finally returning to this project after several months hiatus! Here’s how I ended up bringing up and taking down WLAN from within my python script…

First, I edited /etc/network/interfaces to comment out everything but the following:

# Local
auto lo
iface lo inet loopback

Then to bring up the WLAN with static IP from within python:

proc = subprocess.Popen("sudo ip link set wlan0 up", shell=True, stdout=subprocess.PIPE)
proc.wait()
proc = subprocess.Popen("sudo iwconfig wlan0 txpower auto", shell=True, stdout=subprocess.PIPE)
proc.wait()
proc = subprocess.Popen("sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf", shell=True, stdout=subprocess.PIPE)
proc.wait()
proc = subprocess.Popen("sudo ip addr add 192.168.15.123/24 broadcast 192.168.15.255 dev wlan0", shell=True, stdout=subprocess.PIPE)
proc.wait()
proc = subprocess.Popen("sudo ip route add default via 192.168.15.1", shell=True, stdout=subprocess.PIPE)

Or, to use DHCP, replace the last two “ip” calls with:

proc = subprocess.Popen("sudo dhclient -v wlan0", shell=True, stdout=subprocess.PIPE)

Note that WLAN details (e.g. SSID and PSK) are defined in /etc/wpa_supplicant/wpa_supplicant.conf. Alternatively this should work:

wpa_supplicant -B -i wlan0-c <(wpa_passphrase MYSSID passphrase)

making use of wpa_passphrase, a command line tool which generates the minimal configuration needed by wpa_supplicant.

Also “sudo” should not be needed anywhere as long as python script is running as root, but I included to eliminate that requirement (although apparently the following wouldn’t work for non-root user due to process substitution:

sudo wpa_supplicant -B -i wlan0-c <(wpa_passphrase MYSSID passphrase)

)

To take the network down from within the python script I used the following:

proc = subprocess.Popen("sudo iwconfig wlan0 txpower off ", shell=True, stdout=subprocess.PIPE)
proc.wait()
proc = subprocess.Popen("sudo ip link set wlan0 down", shell=True, stdout=subprocess.PIPE)

Next I need to get NTP to run after bringing up the network. For some reason, the following seems to hang:

proc = subprocess.Popen("ntpd -g -q", shell=True, stdout=subprocess.PIPE)

Comments and/or suggestions appreciated![/b]

For more info see: https://wiki.archlinux.org/index.php/WPA_supplicant ,
https://wiki.archlinux.org/index.php/Network_configuration and
https://wiki.archlinux.org/index.php/Wireless_network_configuration