Getting started
As I'll be using the Pi in "headless" mode (no monitor or keyboard in normal operation) I decided to start as I mean to go on. This also means I don't yet need adapters for the mini HDMI and OTG USB ports on the Pi Zero.
I downloaded and copied the current version of Raspbian, called "stretch", and copied it to a 16 GB micro SD card. An 8 GB card would have been sufficient but the larger card only cost a few pence extra. Note that this is the full version of Raspbian (i.e. not "lite") and is not the NOOBS version.
Booting the Pi directly into headless mode turned out to be surprisingly easy. The instructions in this forum post were all I needed, and worked perfectly despite the negative comments on the post. I inserted the micro SD card, in an adapter, into my openSUSE Linux PC and used the "open with file manager" prompt to mount both partitions. The
df
command showed them to be mounted as /run/media/jim/boot
and /run/media/jim/rootfs
.Having changed directory to the
/run/media/jim/boot
partition all I had to do was create an empty file called ssh
(with the command sudo touch ssh
) then use a text editor (run via sudo
) to create a file wpa_supplicant.conf
with the following contents:country=GB ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="my_wifi_ssid" scan_ssid=1 psk="my_wifi_password" key_mgmt=WPA-PSK }
After safely unmounting the SD card partitions I removed it from the PC, put it in the Pi, and turned the power on. About a minute later the hostname
raspberrypi
showed up in the DHCP server's list of hosts and I was able to ssh into it (the initial password is raspberry
):jim@brains:~$ ssh pi@raspberrypi The authenticity of host 'raspberrypi (192.168.1.176)' can't be established. ECDSA key fingerprint is SHA256:bw10eHPZ3debE04S+5a8xEYSDHT9AmZk8MJWxfNTapQ. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'raspberrypi,192.168.1.176' (ECDSA) to the list of known hosts. pi@raspberrypi's password: Linux raspberrypi 4.14.34+ #1110 Mon Apr 16 14:51:42 BST 2018 armv6l The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Wed Apr 18 01:25:27 2018 SSH is enabled and the default password for the 'pi' user has not been changed. This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password. pi@raspberrypi:~ $ passwd Changing password for pi. (current) UNIX password: Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully pi@raspberrypi:~ $
Creating a user
I could continue to use the default
pi
user name, but I find it more convenient to have the same user name on all my computers. As I'll be using NFS to share storage with some of those computers it's also useful if the user has the same UID number:pi@raspberrypi:~ $ sudo adduser --uid 1026 jim Adding user `jim' ... Adding new group `jim' (1026) ... Adding new user `jim' (1026) with group `jim' ... Creating home directory `/home/jim' ... Copying files from `/etc/skel' ... Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully Changing the user information for jim Enter the new value, or press ENTER for the default Full Name []: Jim Easterbrook Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] y pi@raspberrypi:~ $ sudo visudo -f /etc/sudoers.d/010_pi-nopasswd pi@raspberrypi:~ $The final
visudo
command is to add the new user to the list of users permitted to do things as root.Logging in without a password
It may sound strange but this is a way to improve security when using
ssh
. Passwords can perhaps be guessed, but a 2048 bit RSA key is harder to crack. I already have a key, so I just needed to copy the public key to my new account on the Pi:jim@brains:~$ ssh-copy-id -i ~/.ssh/id_rsa.pub raspberrypi /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/jim/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys jim@raspberrypi's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'raspberrypi'" and check to make sure that only the key(s) you wanted were added. jim@brains:~$ ssh raspberrypi Linux raspberrypi 4.14.34+ #1110 Mon Apr 16 14:51:42 BST 2018 armv6l The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Fri May 25 07:13:41 2018 from 192.168.1.162 jim@raspberrypi:~ $No password was needed to login to the Pi, as expected.
The next step is to disable ssh with passwords entirely. Edit the
sshd_config
file and restart the ssh daemon:jim@raspberrypi: $ sudo vi /etc/ssh/sshd_config jim@raspberrypi: $ sudo service ssh restartThere is just one line to edit, to disable password logins uncomment the
PasswordAuthentication
line and set it to no
:# To disable tunneled clear text passwords, change to no here! PasswordAuthentication no #PermitEmptyPasswords noTest by attempting to login as another user:
jim@brains:~$ ssh pi@raspberrypi Permission denied (publickey). jim@brains:~$
Completing initial setup
I used
sudo raspi-config
to set the host name (under network options), set the locale (en_GB.UTF-8
) and timezone (Europe/London
) under localisation options, and set it to boot to console rather than desktop (under boot options).To minimise SD card "wear" I moved some directories to RAM by adding the following to
/etc/fstab
and then rebooting:tmpfs /tmp tmpfs defaults,noatime,nosuid,size=100m 0 0 tmpfs /var/log tmpfs defaults,noatime,nosuid,mode=0755,size=100m 0 0 tmpfs /run tmpfs defaults,noatime,nosuid,mode=0755,size=2m 0 0(At first the Pi failed to boot, so I moved the SD card to my main PC, mounted
rootfs
and deleted everything in the directories that have been moved to tmpfs
.)I also disabled swap (with
sudo apt-get remove dphys-swapfile
) and turned off file system journaling.I added a few of my favourite command aliases by creating a file
/etc/profile.d/aliases.sh
containing the following:alias df='df -h' alias la='ls -ao' alias ll='ls -l'
To save a small amount of power consumption I turned off video output by adding the following to
/etc/rc.local
, before the exit 0
line:# turn off video output signal /usr/bin/tvservice -off
File sharing with NFS
It's very convenient to be able to copy files from one machine to another with NFS. The
autofs
service can be used to mount NFS shares when needed. I started by exporting the Pi's /home
file system so it can be mounted on other machines. This requires installing the NFS server package:jim@gordon:~ $ sudo apt-get -o Acquire::ForceIPv4=true update jim@gordon:~ $ sudo apt-get -o Acquire::ForceIPv4=true install nfs-kernel-serverThe
-o Acquire::ForceIPv4=true
option stops apt-get
using IPv6, as I don't yet have an IPv6 internet connection.I then added the following line to
/etc/exports
:/home 192.168.1.0/24(rw,root_squash,sync,no_subtree_check)This should allow any machine on my local network to read and write files in
/home
on the Pi, once the NFS server is restarted:sudo service nfs-kernel-server restart
To mount other machines on the Pi requires
autofs
to be installed:jim@gordon:~ $ sudo apt-get -o Acquire::ForceIPv4=true install autofsI then edited
/etc/auto.master
and added the following line:/auto /etc/auto.tracy.island --timeout=30The file
/etc/auto.tracy.island
lists the NFS shares I want access to:brains -bg,intr brains:/home zero-x -fstype=nfs4,bg,intr zero-x:/volume1
brains
is my main PC and zero-x
is my Synology NAS box. (Fans of 1960s children's television should know what inspired my local network naming scheme.)After restarting
autofs
I can access files on other machines:jim@gordon:~ $ sudo service autofs restart jim@gordon:~ $ ll /auto/brains/ total 32 drwxr-xr-x 7 1024 users 4096 May 19 09:42 admin drwxr-xr-x 94 jim users 4096 May 25 11:18 jim drwx------ 2 root root 16384 Aug 21 2011 lost+found drwxr-xr-x 13 2001 users 4096 May 22 2016 sarah drwxr-xr-x 19 pi users 4096 Sep 9 2017 test jim@gordon:~ $ ll /auto/zero-x total 208 drwxrwxrwx 113 root root 4096 Mar 6 18:15 audio drwxrwxrwx 6 root root 4096 May 18 15:12 brains drwxrwxrwx 5 root root 4096 May 10 12:19 DVD drwxrwxrwx 6 root root 4096 May 10 14:22 firefly drwxrwxrwx 6 root root 4096 May 9 08:59 kyrano drwxrwxrwx 29 root root 4096 May 15 14:07 photos drwxrwxrwx 7 root root 131072 May 17 12:59 pvr drwxrwxrwx 5 root root 12288 May 12 08:41 toppy drwxrwxrwx 11 root root 4096 May 20 09:45 video jim@gordon:~ $
Scheduling backup
Experience has taught me the value of backing up computers. The Raspberry Pi is no exception, and as I have a NAS that's always on backing up couldn't be easier. I created a "scripts" directory and added two files.
/home/jim/scripts/backup_to_zero-x.sh
does the actual backup:#!/bin/sh log=/var/log/log-backup dest="jim@zero-x::gordon" export RSYNC_PASSWORD=xxxxxx rsync -av \ /etc $dest >$log 2>&1 rsync -av \ --exclude=".cache" \ --exclude="cache" \ /home $dest >>$log 2>&1 # mail the log file if [ -s $log ]; then /home/jim/scripts/email-log.py $log "backup log" fi
/home/jim/scripts/email-log.py
emails the backup log to an email server running on the NAS:#!/usr/bin/env python from email.utils import formatdate import platform from smtplib import SMTP import sys def main(): file = sys.argv[1] subject = sys.argv[2] with open(file, 'r') as f: contents = f.read() if not contents: return sender = platform.node() + '@tracy.island' date = formatdate() msg = '''Subject: {subject} From: {sender} Date: {date} {file} contents follows ===START=== '''.format(date=date, file=file, sender=sender, subject=subject) msg += contents msg += ''' ====END==== ''' smtp = SMTP(host='zero-x', port=25, timeout=20) smtp.sendmail(sender, 'jim@zero-x.tracy.island', msg) if __name__ == '__main__': main()I set up a root user "cron" job to run the backup script daily at around 4 am.
Installation of pywws
You'll probably want to install pywws from PyPI, but I use the development version from GitHub:
jim@gordon:~ $ mkdir weather jim@gordon:~ $ cd weather/ jim@gordon:~/weather $ git clone https://github.com/jim-easterbrook/pywws.git Cloning into 'pywws'... remote: Counting objects: 9190, done. remote: Compressing objects: 100% (24/24), done. remote: Total 9190 (delta 10), reused 15 (delta 4), pack-reused 9162 Receiving objects: 100% (9190/9190), 4.55 MiB | 724.00 KiB/s, done. Resolving deltas: 100% (5557/5557), done. jim@gordon:~/weather $ cd pywws jim@gordon:~/weather/pywws $ python3 setup.py build ... jim@gordon:~/weather/pywws $ sudo python3 setup.py install ... jim@gordon:~/weather/pywws $The install process was hanging whilst fetching dependencies from
https://pypi.python.org/
until I disabled IPv6 entirely by adding net.ipv6.conf.all.disable_ipv6 = 1
to /etc/sysctl.conf
and rebooting.The next step is to install the required Python USB library:
jim@gordon:~/weather/pywws $ sudo apt-get install python3-libusb1 Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed: python3-libusb1 0 upgraded, 1 newly installed, 0 to remove and 38 not upgraded. Need to get 35.1 kB of archives. After this operation, 189 kB of additional disk space will be used. Get:1 http://raspbian.mirror.uk.sargasso.net/raspbian stretch/main armhf python3-libusb1 all 1.6.3-1 [35.1 kB] Fetched 35.1 kB in 0s (67.1 kB/s) Selecting previously unselected package python3-libusb1. (Reading database ... 124808 files and directories currently installed.) Preparing to unpack .../python3-libusb1_1.6.3-1_all.deb ... Unpacking python3-libusb1 (1.6.3-1) ... Setting up python3-libusb1 (1.6.3-1) ... jim@gordon:~/weather/pywws $Finally I can test that the core pywws software is installed correctly:
jim@gordon:~/weather/pywws $ pywws-version -v 18.5.0 build: 1541 commit: d505b50 Python: 3.5.3 (default, Jan 19 2017, 14:11:04) [GCC 6.3.0 20170124] USB: pywws.device_libusb1 examples: /usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/examples docs: http://jim-easterbrook.github.com/pywws/ jim@gordon:~/weather/pywws $ pywws-testweatherstation 12:29:22:pywws.logger:pywws version 18.5.0, build 1541 (d505b50) Traceback (most recent call last): File "/usr/local/bin/pywws-testweatherstation", line 11, inload_entry_point('pywws==18.5.0', 'console_scripts', 'pywws-testweatherstation')() File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/testweatherstation.py", line 117, in main ws = pywws.weatherstation.WeatherStation() File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/weatherstation.py", line 462, in __init__ self.cusb = CUSBDrive() File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/weatherstation.py", line 316, in __init__ self.dev = USBDevice(0x1941, 0x8021) File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/device_libusb1.py", line 78, in __init__ raise IOError("Weather station device not found") OSError: Weather station device not found jim@gordon:~/weather/pywws $
Connecting the weather station
Given the limitations of the "OTG" USB port on the Pi Zero I was pleasantly surprised that when I connected my test weather station console (an old one whose outside sensors have failed) via a standard USB A to micro USB lead (as used to connect a phone to a computer) it powered up normally. It also works with pywws:
jim@gordon:~/weather/pywws $ sudo pywws-testweatherstation 12:32:56:pywws.logger:pywws version 18.5.0, build 1541 (d505b50) 0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 03 20 01 41 11 00 00 00 81 7f 00 01 00 00 00 01 0020 94 27 87 27 00 00 00 00 00 00 00 07 01 01 16 55 41 23 c8 00 00 00 46 2d 2c 01 64 80 c8 00 00 00 0040 64 00 64 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 12 00 00 00 00 00 00 00 00 0060 00 00 5a 0a 63 0a 41 01 56 00 dc 01 08 81 dc 01 c5 81 68 01 75 81 95 28 d3 25 24 29 5a 25 fd 02 0080 04 03 f4 ff fd ff 85 ff 91 ff 6c 09 00 14 10 19 06 29 12 02 01 19 32 11 09 09 05 18 12 03 28 13 00a0 00 13 07 19 18 28 07 01 01 12 00 13 09 24 13 02 13 09 24 13 33 13 09 24 13 02 12 07 28 12 50 13 00c0 09 24 13 02 13 10 14 16 18 12 02 07 19 00 16 03 28 04 45 13 01 04 10 28 15 01 30 05 22 12 03 10 00e0 22 02 07 01 02 00 02 12 07 28 11 59 13 03 06 06 43 12 04 13 00 04 12 04 13 00 04 12 07 31 03 34 jim@gordon:~/weather/pywws $I used
sudo
as the USB device is "owned" by root by default.The USB ownership is best dealt with by adding a "udev" rule. Create a file
/etc/udev/rules.d/39-weather-station.rules
containing the following:ACTION!="add|change", GOTO="weatherstation_end" SUBSYSTEM=="usb", ATTRS{idVendor}=="1941", ATTRS{idProduct}=="8021", OWNER="jim" LABEL="weatherstation_end"(Replace
jim
with your user name.)Restart the udev system (
sudo service udev restart
) and unplug then replug the weather station. You should now have access to the weather station without using sudo
:jim@gordon:~/weather/pywws $ ll /dev/bus/usb/001/ total 0 crw-rw-r-- 1 root root 189, 0 May 25 12:20 001 crw-rw-r-- 1 jim root 189, 2 May 25 13:03 003 jim@gordon:~/weather/pywws $ pywws-testweatherstation 13:04:14:pywws.logger:pywws version 18.5.0, build 1541 (d505b50) 0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 03 20 01 41 11 00 00 00 81 7f 00 01 00 00 00 01 0020 94 27 88 27 00 00 00 00 00 00 00 07 01 01 12 31 41 23 c8 00 00 00 46 2d 2c 01 64 80 c8 00 00 00 0040 64 00 64 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 12 00 00 00 00 00 00 00 00 0060 00 00 5a 0a 63 0a 41 01 56 00 dc 01 08 81 dc 01 c5 81 68 01 75 81 95 28 d3 25 24 29 5a 25 fd 02 0080 04 03 f4 ff fd ff 85 ff 91 ff 6c 09 00 14 10 19 06 29 12 02 01 19 32 11 09 09 05 18 12 03 28 13 00a0 00 13 07 19 18 28 07 01 01 12 00 13 09 24 13 02 13 09 24 13 33 13 09 24 13 02 12 07 28 12 50 13 00c0 09 24 13 02 13 10 14 16 18 12 02 07 19 00 16 03 28 04 45 13 01 04 10 28 15 01 30 05 22 12 03 10 00e0 22 02 07 01 02 00 02 12 07 28 11 59 13 03 06 06 43 12 04 13 00 04 12 04 13 00 04 12 07 31 03 34 jim@gordon:~/weather/pywws $As soon as I tried "live" logging, with the command
pywws-testweatherstation -l -vv
, I got USB timeout errors as reported by other pywws users on the pywws mail list.A bit of experimenting with longer timeouts and measuring times to read data from the station showed the problem only occurs after pywws has paused USB activity for 5 seconds or more. I had a hunch the the Pi might be switching USB modes during this apparent inactivity, so I added the line
dtoverlay=dwc2,dr_mode=host
to /boot/config.txt
to fix the USB port in "host" mode. This appears to have cured the timeout problem.Final steps
To finish off I installed all the pywws dependencies I need, then copied the pywws data directory from the Pi 2 I was using. That machine has a disc drive so I haven't had to worry about SD card wear. I made a few changes to
weather.ini
to minimise writes to the card:[config] frequent writes = False [paths] local_files = /tmp/pywws/results work = /tmp/pywwsI'm also using
/tmp/pywws
for the logfile. This avoids writing to the SD card, but does mean that the log is cleared every time the Pi is rebooted. I don't expect to have to do this too often.The Raspberry Pi Zero is so small I'm tempted to stick it on the back of the weather station console, with a short USB lead (with right angle plugs?) to make a neat installation. However I suspect the wi-fi may interfere with the station's reception of data from the outside sensors.