In a different post I noted that I have made the switch to OpenSUSE. For a different project, I was looking for a minimal OS and I was curious to see how well openSUSE JeOS (Just Enough OS) would perform on the RPI (3 or zero). I encountered some issues setting it up and this post documents my journey for getting it up and running.

I used the following images for the RPI 3 and RPI Zero W:

  1. RPI3 : openSUSE-Tumbleweed-ARM-JeOS-raspberrypi3.aarch64-2018.10.12-Snapshot20181101.raw.xz
  2. RPI-zeroW : openSUSE-Tumbleweed-ARM-JeOS-raspberrypi.armv6l-2018.10.12-Snapshot20181101.raw.xz

WIFI

WIFI simply did not work on the RPI Zero W. It requires a bit of workaround to fix it.

  1. If using the RPI Zero W, make sure to grab the armv6l build. For RPI 3, you can use the arch64 build.
  2. The wireless driver was not loaded right on the armv6l build and RPI Zero W. Grab the /lib/firmware/brcm/brcmfmac43430-sdio.txt from the arch64 build (I have a copy of it here) and put it in the /lib/firmware/brcm/ of the rpi zero (it is missing on the armv6l image.)
  3. Create config file for wifi interface.

    I noticed that there is no configuration file comes shipped OOTB for the wireless network interface. Create one

    su -c "cp /etc/sysconfig/network/ifcfg-eth0 /etc/sysconfig/network/ifcfg-wlan0"
    

    Without this, if your router does support ipv6, you will not get an ipv4.

    Hardcoding wlan0 should be OK if using the built-in wifi card (a good read on network interface naming).

  4. openSUSE JEOS defaults to wicked for network management.

    Note that there is no dhcp or dhclient binaries on the openSUSE system. Do not install them, they are all managed by wicked:

    su -c "systemctl list-unit-files | grep wicked"
    

    Example output:

    wicked.service enabled
    wickedd-auto4.service enabled
    wickedd-dhcp4.service enabled
    wickedd-dhcp6.service enabled
    wickedd-nanny.service enabled
    wickedd-pppd@.service static
    wickedd.service indirect
    
  5. Modify wpa_supplicant.service

    Edit /usr/lib/systemd/system/wpa_supplicant.service and make sure that the interface is specified under ExecStart. Example:

    # /usr/lib/systemd/system/wpa_supplicant.service contents
    
    # ...
    
    ExecStart=/usr/sbin/wpa_supplicant -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf -u -t -f /var/log/wpa_supplicant.log
    
    # ...
    
  6. Modify /etc/wpa_supplicant/wpa_supplicant.conf

    Disclaimer: Apparently all configurations should be handled by wicked directly. But i could not get it working. So I modified wpa_supplicant.conf directly.

    Edit /etc/wpa_supplicant/wpa_supplicant.conf and set the content:

    ctrl_interface=/var/run/wpa_supplicant.conf
    # ctrl_interface_group=wheel # wheel group doesn't exist
    ctrl_interface_group=root
    
    network={
       ssid="ssid name goes here"
       psk=see-notes-below-for-content-no-quotation
    }
    

    ctrl_interface_group specifies users of which group can use wpa_cli. In the original config file it was set to wheel which does not exist, and would result in wpa_supplicant not starting. The contents of psk should be the psk output of

    su -c "wpa_passphrase actual-wifi-passphrase-goes-here"
    
  7. Reboot the machine or restart the network
  8. su -c "systemctl restart network"
    
  9. Reduce grub timeout by editing etc/default/grub
  10. # /etc/default/grub contents
    
    # ...
    
    GRUB_TIMEOUT=3
    
    # ...
    

    and run

    su -c "grub2-mkconfig --output /boot/grub2/grub.cfg"
    
  11. For additional issues, you can look at some of openSUSE docs on managing the network from cli

Boot speedup

The primary reason for wanting to use the JeOS image was limited size and hopefully fast bootups. But the boot up out of the box takes about 2 minutes on the rpi Zero-W.

Fortunately, systemd comes with some handy tools to analyze the bootup process. Entire boot process (results below show after tinkering with the services)

> systemd-analyze
# Output:
# Startup finished in 13.577s (kernel) + 24.085s (initrd) + 32.004s (userspace) = 1min 9.667s

The top 5 services to blame for the poor bootup speed in userspace can be viewed:

> systemd-analyze blame | head -n 5
         33.030s wicked.service
         26.599s ca-certificates.service
         17.372s dev-mmcblk0p2.device
         14.161s sshd.service
          7.310s lvm2-monitor.service

wicked consistently was taking over 30 seconds to boot. Looking around, I came across this thread from the mailing lists this thread that suggested to edit /etc/sysconfig/network/config and reduce WAIT_FOR_INTERFACES="30" to WAIT_FOR_INTERFACES="5".

This took down the bootup speed on the RPI Zero-W down to 40 seconds:

> systemd-analyze critical-chain
graphical.target @39.526s
└─multi-user.target @36.388s
  └─sshd.service @22.217s +14.161s
    └─network.target @22.037s
      └─wicked.service @14.978s +7.030s
        └─wickedd-nanny.service @14.438s +402ms
          └─wickedd.service @13.699s +622ms
            └─wickedd-dhcp4.service @13.078s +523ms
              └─dbus.service @12.384s
                └─basic.target @12.319s
                  └─paths.target @12.317s
                    └─ca-certificates.path @12.307s
                      └─sysinit.target @12.290s
                        └─systemd-update-utmp.service @12.074s +212ms
                          └─auditd.service @11.442s +604ms
                            └─systemd-tmpfiles-setup.service @11.104s +313ms
                              └─local-fs.target @11.070s
                                └─boot-efi.mount @10.507s +524ms
                                  └─local-fs-pre.target @10.457s
                                    └─lvm2-monitor.service @2.099s +7.310s
                                      └─lvm2-lvmetad.service @2.938s
                                        └─lvm2-lvmetad.socket @1.865s
                                          └─system.slice

Next, following comments on a thread, ran

su -c "mkinitrd"

which reduced initrd down to 10 seconds, nearly halving the initial total boot time of ~2 minutes.

Startup finished in 10.870s (kernel) + 10.966s (initrd) + 36.498s (userspace) = 58.335s

Bonus - USB GPS

I was looking into JeOS for a project involving GPS data. I got a used BU-353 GPS for around $10 off of ebay which is surprisingly good for its performance: it got a position fix indoor (close to a window) after being hooked up. Getting it working on RPI ZeroW with minimal utilities is simple. Install gpsd from the repos

zypper in gpsd

Run dmesg -w and hook up the GPS to the rpi (need a microusb to USB converter). The filename port should show up as /dev/ttyUSB0. An additional step should really be taken and use udev to assign a fixed name since it may change if it was unplugged and plugged back in, but if it is plugged only once and is the only device plugged in, ttyUSB0 should be a good port filename.

For this particular model, blinking red light on the GPS unit means it has a fix. Just to make sure everything is working before making things permanent, stop the service and start it manually:

systemctl stop gpsd
gpsd /dev/ttyUSB0 -F /var/run/gpsd.sock

And then telnet to port 2947 (see /usr/lib/systemd/system/gpsd.socket)

> telnet localhost 2947
Trying ::1...
Connected to localhost.
Escape character is '^]'.
{"class":"VERSION","release":"3.17","rev":"3.17","proto_major":3,"proto_minor":12}

To start getting the parsed GPS data send ?WATCH={"enable":true,"json":true} to telnet and you should start getting gps outputs

?WATCH={"enable":true,"json":true}
{"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyUSB0","activated":"2018-11-05T03:53:37.159Z","native":0,"bps":4800,"parity":"N","stopbits":1,"cycle":1.00}]}
{"class":"WATCH","enable":true,"json":true,"nmea":false,"raw":0,"scaled":false,"timing":false,"split24":false,"pps":false}
{"class":"DEVICE","path":"/dev/ttyUSB0","driver":"SiRF","activated":"2018-11-05T03:53:37.442Z","native":1,"bps":4800,"parity":"N","stopbits":1,"cycle":1.00}
{"class":"TPV","device":"/dev/ttyUSB0","mode":3,"time":"2018-11-05T03:53:36.000Z","ept":0.005,"lat":<redacted>,"lon":<redacted>,"alt":<redacted>,"track":<redacted>,"speed":0.210,"climb":0.335}

and ?WATCH={"enable":false} to end the output.

This is a good resource for trouble shooting if things are not working.

To start it automatically on boot, you can enable the gpsd service, and specify which port filename to use: Create (or edit if it already exists) /etc/default/gpsd with contents

DEVICES="/dev/ttyUSB0"

This file is referenced by the gpsd service:

> cat /usr/lib/systemd/system/gpsd.service
# output:
[Unit]
Description=GPS (Global Positioning System) Daemon
Requires=gpsd.socket
# Needed with chrony SOCK refclock
After=chronyd.service

[Service]
Type=forking
EnvironmentFile=-/etc/default/gpsd
EnvironmentFile=-/etc/sysconfig/gpsd
ExecStart=/usr/sbin/gpsd $GPSD_OPTIONS $OPTIONS $DEVICES

[Install]
WantedBy=multi-user.target
Also=gpsd.socket

And it should ready for use on next reboot.

You can install the python3-gpsd (~120KB) from your repos to do other tasks with the data. The most barebore snippet to access the data I could come up with is

import gps

# see /usr/lib/systemd/system/gpsd.socket
session = gps.gps('localhost', '2947')
session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)

while True:
    try:
        report = session.next()
        print (report)
    except KeyError:
        pass
    except KeyboardInterrupt:
        quit()
    except StopIteration:
        session = None
        print('GPSD has terminated')