Skip to Content

← All functionalities

Two-axis solar trackersRaspberry PLC 21systemdInfrastructure

Making a tracker controller survive reboots with systemd

Field controllers reboot: power dips, watchdogs fire, technicians cycle breakers. In a real two-axis solar tracker deployment, two systemd services keep the Raspberry PLC 21 self-sufficient — solar-tracker.service runs the Python control process and tracker-ap.service watches the hotspot button — while Node-RED serves a dashboard with control, calibration, inverter and configuration tabs behind Authelia authentication. This example is the annotated unit file plus its installation steps.

Anatomy of the unit file

The unit waits for network-online.target, runs the control script as a simple service from its working directory, and uses root because socketcan and GPIO require it. Every print statement lands in journald, so journalctl -u solar-tracker.service -f replaces SSH-and-tail debugging. Enable the unit once and the tracker controller starts at every boot, unattended, exactly the behavior a remote site demands from day one.

Restart policy without restart storms

Restart=always with RestartSec=10 revives the process after a CAN exception or a crash, which on a remote site is the difference between a log entry and a truck roll. The StartLimit settings cap retries: ten failures in five minutes stop the loop, leaving a clearly failed unit for diagnosis instead of a PLC burning CPU forever on an unfixable error.

Two services, one pattern

The watcher for the access-point button is the same unit file with a different Description and an ExecStart pointing at manage_ap.py — the header comments document the copy-and-edit steps. Splitting the controller and the access point into separate services means a crash in one never disturbs the other, and each one can be restarted independently from the command line during commissioning or troubleshooting.

A snippet from the implementation

Straight from the example as deployed on the Raspberry PLC 21 — copy it freely:

[Unit]
Description=Solar tracker control (PyEphem + CANopen + TCP Node-RED)
# Starts once the network is up and the CAN bus is already configured
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
# Main tracker control script
ExecStart=/usr/bin/python3 /home/pi/tracker/main.py
WorkingDirectory=/home/pi/tracker
# Needs root for socketcan and GPIO
User=root

# Automatic restart if the process dies (CAN bus failure, exception, etc.)
Restart=always
RestartSec=10

# Logs to journald (check with journalctl -u solar-tracker.service)
StandardOutput=journal
StandardError=journal

# Avoid aggressive restart loops if something is truly broken
StartLimitIntervalSec=300
StartLimitBurst=10

[Install]
WantedBy=multi-user.target

The full example is a complete program — wiring header, setup and main loop — ready to adapt to your application.

Frequently asked questions

Why run the service as root instead of a dedicated user?

The control process needs raw access to the CAN interface and GPIO character devices. You can tighten this with group permissions and udev rules, but on a single-purpose industrial PLC, root with a hardened image is the pragmatic baseline.

How does Authelia fit in front of Node-RED?

Authelia sits as an authentication portal in front of the dashboard, so every tab — control, calibration, inverter, configuration — requires login. Node-RED itself stays bound locally and never faces the network unauthenticated.

How do I check why the service failed in the field?

systemctl status solar-tracker.service shows the last state and exit code, and journalctl -u solar-tracker.service --since today gives the full log. Because StandardOutput goes to journald, no separate log files need rotating.

Related functionalities