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#

  1. On a computer, download and install Raspberry Pi Imager.

  2. Insert the microSD card into the computer for loading the OS.

  3. Select Raspberry Pi 4 (or Pi 3 if that is what you are using) as the model.

  4. Select Raspberry Pi OS (Legacy, 32-bit). As of November 2026, this is based on Debian 12 (Bookworm).

    _images/os.jpg

    Fig. 34 Select Raspberry Pi OS (Legacy, 32-bit).#

  5. It is very important to set the username to pi in 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.

    _images/username.jpg

    Fig. 35 Enter pi as the username to match the paths in the supplied scripts.#

  6. Skip or complete any other required settings, then write the OS image to the microSD card. If you skip customisation, create the username pi when prompted at first boot; the OS does not automatically use pi as its default username.

  7. When writing is complete, insert the microSD card into the Raspberry Pi. Connect power, monitor, mouse, and keyboard, then boot the Pi.

  8. 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
    
  9. 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, pip normally prevents installations into the system Python environment. The --break-system-packages option 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_ws281x module, 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 show Version: 5.0.0 for the installation. Version: 5.0.0 of rpi_ws281x has been tested to work, so it is best to keep the version specification instead of installing the latest update.

  10. 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).

  1. Connect the DS3231 RTC module as described in Assemble Raspberry Pi and LED strips.

  2. Enable I2C using the Raspberry Pi configuration utility:

    sudo raspi-config
    

    Select Interface Options > I2C > Enable, then exit. (The menu numbering can differ among OS versions.)

  3. 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=on alreay exists within the config.txt, delete it.

    Save with Ctrl+O, Enter, and exit with Ctrl+X.

  4. Reboot:

    sudo reboot
    
  5. Verify 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 in hwclock commands with --rtc /dev/rtcN. If the module is not detected, check wiring, I2C enablement, and the device-tree overlay before setting time.

  6. Disable automatic network time synchronisation:

    sudo timedatectl set-ntp false
    
  7. 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
    
  8. 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:00 if that is the correct time in your selected zone.

  9. Copy the system time to the RTC (stored in UTC):

    sudo hwclock --systohc --utc
    
  10. Check RTC device:

    cat /sys/class/rtc/rtc0/name && sudo hwclock --show --rtc /dev/rtc0
    
    • Hardware connection: rtc-ds1307 1-0068 confirms Linux detects the DS3231.

    • RTC operation: A successfully displayed date and time confirms the RTC can be read.

  11. 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#

  1. Download the control_moon and control_sun folders from Download files.

    • control_moon contains moonshine_moon.py.

    • control_sun contains moonshine_sun.py.

  2. 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.py reads:

    /home/pi/Desktop/control_moon/LED_schedule_moon.csv
    

    Note

    In moonshine_moon.py, LED_PIN = 18 sends the moonlight LED data through GPIO 18. In moonshine_sun.py, LED_PIN = 21 is used for the sunlight/twilight LEDs through GPIO 21. The two scripts control separate LED outputs.

  3. Download clear_moon.py and clear_sun.py from 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.

  1. 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.

  2. Open moonshine_moon.py and moonshine_sun.py, and set LED_COUNT to the actual total for each independent LED array (see Fig. 36).

    _images/led_count.png

    Fig. 36 Set LED_COUNT = 576 in moonshine_sun.py when using four daisy-chained strips of 144 LEDs each.#

  3. 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
    

    GRBW is correct for the LED strip model we recommend. The GRBW order differs from the conventional RGBW, and properly determines how the red, green, blue, and white data are assigned to the physical LED channels.

  4. 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.

  1. Create the moonlight service file:

    sudo nano /etc/systemd/system/moonshine_moon.service
    
  2. Paste the complete contents below. Pay particular attention to the ExecStart line: it must contain both the Python interpreter and the path to moonshine_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=always restarts the script after an unexpected failure or a normal exit. RestartSec=3 pauses for three seconds before restarting. The service is run as root because the LED-control library requires privileged hardware access on this configuration.

  3. Save with Ctrl+O, Enter, and close with Ctrl+X.

  4. 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
    
  5. Reload the systemd unit definitions:

    sudo systemctl daemon-reload
    

    Perform this reload Whenever a .service file is created or edited.

  6. 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
    

    enable configures automatic startup at boot; --now also starts the service immediately. If you want to start a service just for the current session without enabling it at boot, use sudo systemctl start moonshine_moon.service instead.

  7. 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.

  8. If the service is failed, inactive, or repeatedly activating (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/python3 interpreter as ExecStart.

    • can't open file ... or a clean exit immediately after launch: Check the full ExecStart line and the actual script path.

    • No such file or directory for 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.

  9. For more information on starting and stopping moonshine_moon.service, see 8. MoonShineP: Launch procedure.