6. MoonShineP: Software setup
Contents
6. MoonShineP: Software setup#
Note
Compatibility Note: As of November 2026. MoonShineP was tested successfully on Raspberry Pi 4 running Python 3.11.2 (pre-installed version of Python with the OS), and relying on the system-installed rpi-ws281x Python package latest version 5.0.0. This chapter uses Raspberry Pi OS (Legacy, 32-bit) as the installation target; at the time of the test the Raspberry Pi OS Legacy release is Debian 12 (Bookworm).
Hardware Note: MoonShineP works best on Raspberry Pi 4 Model B, and should also work on the previous generation Pi 3 B. Raspberry Pi 5 uses a different GPIO architecture and as of November 2026, is not fully supported by the required rpi-ws281x Python package. The Raspberry Pi 4 Model B is expected to remain in production until at least 2034.
Setting up a new Raspberry Pi#
On a computer, download and install Raspberry Pi Imager.
Insert the microSD card into the computer for loading the OS.
Select Raspberry Pi 4 (or Pi 3 if that is what you are using) as the model.
Select Raspberry Pi OS (Legacy, 32-bit). As of November 2026, this is based on Debian 12 (Bookworm).
Fig. 34 Select Raspberry Pi OS (Legacy, 32-bit).#
It is very important to set the username to
piin the Imager’s OS Customisation / User settings. The user then chooses their own password. The supplied MoonShineP Python scripts and systemd examples contain absolute paths beginning with/home/pi/. Using another username is possible, but then all/home/pi/paths in the Python scripts and service files must be updated.
Fig. 35 Enter
pias the username to match the paths in the supplied scripts.#Skip or complete any other required settings, then write the OS image to the microSD card. If you skip customisation, create the username
piwhen prompted at first boot; the OS does not automatically usepias its default username.When writing is complete, insert the microSD card into the Raspberry Pi. Connect power, monitor, mouse, and keyboard, then boot the Pi.
Check the installed OS and Python versions. Python is already included in Raspberry Pi OS. At the time of November 2026, Raspberry Pi OS (Legacy, 32-bit) Python 3.11.2, which works properly with MoonShineP
cat /etc/os-release dpkg --print-architecture /usr/bin/python3 --version
Install the Python library that controls the SK6812 LEDs. Connect the Pi to the internet for this step, then enter:
sudo apt update sudo apt install python3-pip python3-dev build-essential swig sudo /usr/bin/python3 -m pip install --break-system-packages 'rpi-ws281x==5.0.0'
Enter Y when prompted for the installation.
Attention
On Raspberry Pi OS Bookworm,
pipnormally prevents installations into the system Python environment. The--break-system-packagesoption deliberately overrides that protection. It is included here to allow a working system-Python setup on the dedicated MoonShineP Pi, and it carries a risk of conflicts with OS-managed Python packages. For general-purpose Raspberry Pis, a Python virtual environment is preferable; its interpreter path would also need to be used in the systemd service.Check that Python can import the
rpi_ws281xmodule, and record its actual version:sudo /usr/bin/python3 -c "import rpi_ws281x; print('Success')" /usr/bin/python3 -m pip show rpi-ws281x
The first command should print
Success; the second should showVersion: 5.0.0for the installation.Version: 5.0.0of rpi_ws281x has been tested to work, so it is best to keep the version specification instead of installing the latest update.The Pi now has the required Python LED-control library installed. Continue with the RTC, folder, LED-count, and systemd configuration below before running MoonShineP.
Setup real time clock (RTC) and time#
A real-time clock (RTC) is recommended for MoonShineP when operating without internet access. On a Raspberry Pi 4, an external DS3231 module with a working backup battery can maintain time during power outages. Disable automatic internet time synchronisation if the experimental schedule must not be adjusted by network time updates, or run the system offline (recommended).
Connect the DS3231 RTC module as described in Assemble Raspberry Pi and LED strips.
Enable I2C using the Raspberry Pi configuration utility:
sudo raspi-configSelect Interface Options > I2C > Enable, then exit. (The menu numbering can differ among OS versions.)
Open the boot configuration:
sudo nano /boot/firmware/config.txt
Add two new lines at the top:
dtoverlay=i2c-rtc,ds3231
dtparam=audio=off
If the line
dtparam=audio=onalreay exists within the config.txt, delete it.Save with
Ctrl+O, Enter, and exit withCtrl+X.Reboot:
sudo rebootVerify that the RTC was detected. Enter:
ls /dev/rtc* for f in /sys/class/rtc/rtc*/name; do echo "$f: $(cat "$f")"; done
Identify the RTC device associated with the DS3231; on a Pi 4 with one RTC, it is typically
/dev/rtc0. If more than one RTC exists, specify the correct one inhwclockcommands with--rtc /dev/rtcN. If the module is not detected, check wiring, I2C enablement, and the device-tree overlay before setting time.Disable automatic network time synchronisation:
sudo timedatectl set-ntp false
Set a fixed time zone without daylight saving time. For example, for EST (UTC-05:00) all year. It does not have to be the actual geographical time zone you are located at, because we will change the clock time manually in the next step, and the .csv schedule file simply provides a time without compensation for time zone.
sudo timedatectl set-timezone Etc/GMT+5
Set the current date and time without applying a daylight saving adjustment. Enter:
sudo date -s 'YYYY-MM-DD HH:MM:SS'
Replace the placeholder with the current date and standard-zone time, for example
2026-11-05 17:00:00if that is the correct time in your selected zone.Copy the system time to the RTC (stored in UTC):
sudo hwclock --systohc --utc
Check RTC device:
cat /sys/class/rtc/rtc0/name && sudo hwclock --show --rtc /dev/rtc0
Hardware connection:
rtc-ds1307 1-0068confirms Linux detects the DS3231.RTC operation: A successfully displayed date and time confirms the RTC can be read.
Test timekeeping after a power outage. Disconnect the Pi from the network, then shut it down:
sudo shutdown -h now
After shutdown completes, disconnect the power supply for a few minutes. Reconnect power and boot without internet access. Check:
timedatectl sudo hwclock --show
Confirm that the system clock has advanced properly.
Desktop folders#
Download the control_moon and control_sun folders from Download files.
control_moon contains
moonshine_moon.py.control_sun contains
moonshine_sun.py.
Move the folders to the Raspberry Pi Desktop so the script paths are:
/home/pi/Desktop/control_moon/moonshine_moon.py /home/pi/Desktop/control_sun/moonshine_sun.py
Place each generated LED schedule CSV in the corresponding control folder, using the filename expected by its Python script. For example,
moonshine_moon.pyreads:/home/pi/Desktop/control_moon/LED_schedule_moon.csv
Note
In
moonshine_moon.py,LED_PIN = 18sends the moonlight LED data through GPIO 18. Inmoonshine_sun.py,LED_PIN = 21is used for the sunlight/twilight LEDs through GPIO 21. The two scripts control separate LED outputs.Download
clear_moon.pyandclear_sun.pyfrom Download files and place them directly on the Raspberry Pi Desktop.
Setting LED numbers in moonshine_moon.py and moonshine_sun.py#
In 2. MoonShineR: Moonlight scheduler and 3. MoonShineR: Sunlight/twilight scheduler, the user specifies the LED array using diode_per_strip and strip_count when generating the schedule CSV files. The corresponding LED_COUNT in the MoonShineP Python script must equal the product of these values. The Python script treats the LEDs as a one-dimensional sequence.
Calculate the LED count:
LED_COUNT = diode_per_strip * strip_count
For example, 144 LEDs per strip multiplied by four daisy-chained strips gives 576 LEDs.
Open
moonshine_moon.pyandmoonshine_sun.py, and setLED_COUNTto the actual total for each independent LED array (see Fig. 36).
Fig. 36 Set
LED_COUNT = 576inmoonshine_sun.pywhen using four daisy-chained strips of 144 LEDs each.#Check the LED channel order in both Python scripts. For the GRBW SK6812 strips used in this MoonShineP setup, the setting is:
LED_STRIP = ws.SK6812_STRIP_GRBW
GRBWis correct for the LED strip model we recommend. TheGRBWorder differs from the conventionalRGBW, and properly determines how the red, green, blue, and white data are assigned to the physical LED channels.Save the Python scripts. Changing LED count or strip hardware also requires matching changes to the MoonShineR schedule generation and a new illuminance calibration.
Setting up systemd service#
Using the Linux systemd service manager lets MoonShineP launch automatically at boot and restart if its continuously running Python script exits. Complete the folder and LED settings above first.
Create the moonlight service file:
sudo nano /etc/systemd/system/moonshine_moon.service
Paste the complete contents below. Pay particular attention to the
ExecStartline: it must contain both the Python interpreter and the path tomoonshine_moon.py.[Unit] Description=MoonShineP moonlight scheduler [Service] User=root Group=root Type=simple ExecStart=/usr/bin/python3 /home/pi/Desktop/control_moon/moonshine_moon.py Restart=always RestartSec=3 [Install] WantedBy=multi-user.target
Restart=alwaysrestarts the script after an unexpected failure or a normal exit.RestartSec=3pauses for three seconds before restarting. The service is run as root because the LED-control library requires privileged hardware access on this configuration.Save with
Ctrl+O, Enter, and close withCtrl+X.If sunlight/twilight simulation is also used, create a second service:
sudo nano /etc/systemd/system/moonshine_sun.service
Paste:
[Unit] Description=MoonShineP sunlight and twilight scheduler [Service] User=root Group=root Type=simple ExecStart=/usr/bin/python3 /home/pi/Desktop/control_sun/moonshine_sun.py Restart=always RestartSec=3 [Install] WantedBy=multi-user.target
Reload the systemd unit definitions:
sudo systemctl daemon-reload
Perform this reload Whenever a
.servicefile is created or edited.Enable and start the moonshine_moon.service:
sudo systemctl enable --now moonshine_moon.service
If configured, do the same for sunlight/twilight:
sudo systemctl enable --now moonshine_sun.service
enableconfigures automatic startup at boot;--nowalso starts the service immediately. If you want to start a service just for the current session without enabling it at boot, usesudo systemctl start moonshine_moon.serviceinstead.Check the service state:
sudo systemctl status moonshine_moon.service --no-pager -l
A continuously running scheduler should normally show
active (running). Note also that a running scheduler does not guarantee the LEDs will be illuminated at that moment; the schedule may intentionally specify zero output.If the service is
failed,inactive, or repeatedlyactivating (auto-restart), inspect its logs:sudo journalctl -u moonshine_moon.service -n 50 --no-pager
Typical checks are:
ModuleNotFoundError: No module named 'rpi_ws281x': Recheck the Python library installation using the same/usr/bin/python3interpreter asExecStart.can't open file ...or a clean exit immediately after launch: Check the fullExecStartline and the actual script path.No such file or directoryfor the schedule or log: Check the control folder, CSV filename, and/home/pi/paths inside the Python script.active (running)but no light: Check the present schedule values,LED_COUNT,LED_PIN,LED_STRIP, power, and connections.
For more information on starting and stopping
moonshine_moon.service, see 8. MoonShineP: Launch procedure.