Spawn more salmon
Sean D. Conway’s passion for salmon fishing motivated him to implement a Pi solution to automate temperature measurements for fish conservation.
Sean D. Conway’s passion for salmon fishing motivated him to implement a Pi solution to automate temperature measurements for fish conservation.
One summer visit to an Atlantic salmon conservation site spawned (sounds fishy!–ed) the idea for this project. The organisation, Salmon Preservation Association for the Waters of Newfoundland (SPAWN) https://spawn1.ca, manages a fish ladder in the city of Corner Brook in Canada. The ladder enables salmon to bypass the dam as the fish return from the ocean to lay eggs in the freshwater rivers they were born in – see the picture (right).
SPAWN members are responsible for counting fish that return to the river, as well as taking water temperature readings. At the top of the ladder there is a gate that stops the fish. Twice a day a visit is made to the site to release fish held at the gate as well as to gather water data.
After observing this routine, the idea of automating the temperature recordings using a Raspberry Pi was conceived. There are no usable wired or Wi-fi networks available at the fish ladder, so the Pi is configured as a wireless access point (AP). Using an SSID of ‘pispawn’, a wireless host can connect to the AP and download data accumulated over the collection schedule.
A Python script runs on the Pi every 15 minutes via Cron, recording temperature readings from two waterproof DS18B20 temperature sensors connected to the GPIO pins. One sensor is in the water, with the second in the air. Comma-delimited data containing date, time, water temperature and air temperature are saved to a file. In order to ensure the time accuracy of the Pi, a real-time DS3231 clock module is installed. The Pi itself and its power supply are housed in a waterproof enclosure.
Counting down the time
In the interests of saving space, this tutorial will omit the sundries of installing the Raspbian operating system and establishing an SSH connection to the Pi using wireless. The details are contained in an article published in LXF239 called ‘Build a Pi screen for a model drive-in’. Now that you’ve taken out a subscription in order to use the LXF online archives to secure that last reference (you have, haven’t you?), it’s also a good idea to implement the security options listed in (the nighmareish–ed) LXF240, ‘Assemble a night vision baby monitor’. But that’s enough shameless self-promotion…
Temperature data collected needs to reflect accurate time. The Raspbian OS uses two software solutions to establish time. The Pi uses a fake-hwclock routine to store time periodically and recall it on booting. NTP is software that queries a network time server to establish accurate time. If no network is available, the system defaults to the fake-hwclock.
So to ensure the Pi has accurate time, we’ll configure a real-time clock (RTC) DS3231 module.
The Pi doesn’t rely on a Basic Input/output System (BIOS) firmware burned into an EPROM; instead, system configuration parameters which would normally be retained in the BIOS are stored in the /boot/config. txt file used during boot. Using your favourite text editor, add a call for the kernel to support a RTC on boot to the bottom of the /boot/config.txt file – a reboot is required for this change to take effect:
#enable RTC DS3231 dtoverlay=i2c-rtc,ds3231
Now that we have a time reference, let’s remove the two software packages that Raspbian uses for supporting time. From the command line interface (CLI), issue the following command to remove the NTP and fake hardware clock software:
sudo apt-get purge ntp fake-hwclock
Using the CLI, let’s establish the time zone configuration by entering the following command and following the prompts.
sudo dpkg-reconfigure tzdata
Now let’s establish the date and time. This can be done through the command line using the sudo date --set ‘yyyy-mm-dd hh:mm:ss’ command. That requires a little more typing than needed, so while the device is connected to a network, we’ll cheat and use an online time source to nail up the date and time. sudo apt-get install ntpdate sudo ntpdate <replace with the URL or IP address of a time source, this includes the parenthesis>
ntpdate takes over the heavy lifting of establishing time. It forces the clock to the time of the reference source. This only needs to be done once, but only works if there is a network available, of course.
One last step and then we are out of time. We need to write the time settings that have been configured into the RTC, so that it has the correct time. The RTC with its battery backup will keep accurate time from now on. sudo hwclock -w
Access point
In order for the data to be uploaded from the Pi to a load host, a connection mechanism needs to be established. If we configure the Pi as an access point (AP), the load host can use a Wi-fi connection and access the AP using the SSID and password.
Two software components are required: an access point application and DHCP support. hostapd is a userspace daemon for access point and authentication servers. It can be used to create a wireless hotspot for computers running Linux. When the load host accesses the AP, it will need to obtain an IP address in order to communicate with the Pi. dnsmasq supports DHCP services which will provide an IP on successful authentication to the AP. From the CLI, load the software pieces using the following command.
sudo apt-get install hostapd dnsmasq
The normal Wi-fi connection needs to be disabled and reconfigured to support the AP. To do this we prevent the Wi-fi interface from securing an IP from a network DHCP source. Using your favourite text editor, edit /etc/dhcpcd.conf to include the following on a separate line.
Denyinterfaces wlan0
We need to ensure our Pi Wi-fi has an IP address when it starts up. Assign a public IP address to the Pi Wi-fi interface by adding the following lines to the
/etc/network/interfaces file.
Auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp allow-hotplug wlan0 iface wlan0 inet static address 192.168.5.1 netmask 255.255.255.0 network 192.168.5.0 broadcast 192.168.5.255
Configuration for the AP is contained in the /etc/ hostapd/hostapd.conf file. Create the file and add the following lines.
Interface=wlan0 driver=nl80211 ssid=pispawn hw_mode=g channel=6 suieee80211n=1 wmm_enabled=1 HT_CAPAB=[HT40][SHORT-GI-20][DSSS_CCK-40] macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_key_mgmt=wpa-psk wpa_passphrase=raspberry rsn_pairwise=ccmp
The SSID and password are contained in the fields ssid= and wpa_passphrase= respectively; change these references to reflect your own AP conventions. Just remember the SSID is being broadcast, so you will want to have a robust password to ensure security. Now we need to tell the AP application where to find the
newly minted configuration file. Modify the /etc/default/hostapd file to include the following reference. Daemon_conf=”/etc/hostapd/hostapd.conf”
We need some DHCP service here!
dnsmasq is software designed to provide network infrastructure for small networks. It has a small footprint, suitable for memory-constrained routers and firewalls. Domain Names Services (DNS), Dynamic Host Configuration Protocol (DHCP) and router advertisement are three of the services provided by this software.
The configuration file for dnsmasq contains all the options for these services. Instead of wading through the file culling the options needed, we can retain the file contents for reference by moving the file to a backup and create a replacement file with the options needed.
sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.bak/
Using your favourite text editor, copy the following lines to the /etc/dnsmasq.conf file:
interface=wlan0 listen-address=192.168.5.1 bind-interfaces server=8.8.8.8 domain-needed bogus-priv dhcp-range=192.168.5.100,192.168.5.200,24h
A reboot of the Pi should return a device that is now configured as an AP, broadcasting its SSID and accessible from a Wi-fi-supported host if it knows the passphrase. A quick check of the IP on the load host after establishing a connection to the AP should show an IP address assigned from the address pool configured – that is, 192.168.5.100-200.
Comfortable temperature
The DS18B20 temperature sensor contains a one-wire serial interface, control logic and the temperature sensor itself. The one-wire serial interface protocol will need to be supported on the Pi.
Using your favourite text editor, add the following lines to the /boot/config.txt file. Remember that a reboot of the Pi is needed in order for this change to take effect.
#1-wire support enabled dtoverlay=w1-gpio,gpiopin=10 dtoverlay=w1-gpio,gpiopin=9
By default, the Pi provides one-wire serial interface support on GPIO04, pin 7. The RTC module doesn’t use GPIO04 but physically spans the pin to obtain other connections. Since the RTC module is occupying the default one-wire serial interface connection, an alternate pin will need to be configured.
In order to use a connector that combines all the temperature sensor wires and that plugs into the Pi onboard connector in a contiguous row of pins, we’ve used pin 17, 19, 21, 23 and 25. This pin order provides DC Power, Gnd and GPIO pins all in a row, enabling a simpler connection. This does result in physically spanning a pin, thus making it unavailable – similar to what was described for the RTC module.
After the reboot, from the command line issue the following to begin initialisation:
sudo modprobe w1–gpio sudo modprobe w1-therm
The modprobe commands start the serial interface running. Each temperature probe will be assigned a directory. Taking a listing of the one-wire serial devices directory with ls /sys/bus/w1/devices identifies the directories created to support the temperature sensors. The number and letters of the directories are the unique identifier for each device; this is needed in order to communicate with the sensor.
A DS18B20 sensor has a unique 64-bit serial code, which allows multiple DS18B20S to function on the same one-wire bus. Each temperature sensor periodically writes its output data to a file in its home directory. Using the following command, we can access the temperature sensor’s data.
cat /sys/bus/w1/devices/[replace including bracket with serial code numbers]/w1_slave
The output from the command is two lines of text. The values after the t= is the sensor’s raw temperature data. Divide the value by 1,000 to yield the temperature in degrees Celsius. Hold the temperature sensor in your hand and take the reading again; you should notice a change in the temperature.
Writing the Python code
Now that we have a configuration that provides accurate time and supports the two sensors, let’s examine a Python script that will read the sensor and write the data to a file. For this project, a /scripts directory was created in the Pi /home directory to hold both the Python script and the associated data file it produces. You can find the full code in the LXF Archives
and at https://pastebin.com/rsi8bzbj. The Python script is anatomically annotated using the markers
#{Block comment followed by a #} to assist you in following the code dissection.
Initialise the one-wire serial interface and devices:
os.system(‘modprobe w1-gpio’) os.system(‘modprobe w1-therm’)
Initialise the variables for the sensor temperature readings:
sensor_water_reading = ‘/sys/bus/w1/devices/2801131b643158/w1_slave’ sensor_air_reading = ‘/sys/bus/w1/devices/280113134c72aa/w1_slave’ Define the temperature functions or blocks of code that perform a task. Get the water/air temperature data from the sensor and parse the data into Celsius values. def temp_water_data(): i = open(sensor_water_reading, ‘r’) lines = i.readlines() i.close() return lines def temp_water_cal(): lines = temp_water_data() while lines[0].strip()[-3:] != ‘YES’: time.sleep(0.2) lines = temp_water_data() temp_water_output = lines[1].find(‘t=’) if temp_water_output != -1:
temp_water_string = lines[1].strip()[temp_water_ output+2:] temp_water_celsius = float(temp_water_ string)/1000.0 return temp_water_celsius
Initialise the time variable when the reading taken: sample_time = datetime.datetime.now().strftime(“%y%m-%d %H:%M”)
Open a data file, establish a string-data line using variables, text and function returns, write the line to the file and close the file. Some points to note: the a append mode creates a new file if it doesn’t exist and keeps the original file’s data from being overwritten.
A w write mode would create a new file every time and overwrite the old data. In creating a line of data it’s important to remember that data written by Python to a file must be of the string data type, or Python will throw an error.
Data is stored in buffers, and data is only written to a file at buffer levels. Closing a file forces a buffer write regardless of levels. Failing to close a file could leave the file data in an ambiguous state. temp_data_file = open(‘/home/pi/scripts/cbs_temp_ data.txt’,‘a’) temp_data = str(sample_time) + ‘,water_celsius ,’ + str(temp_water_cal()) + ‘,air_celsius ,’ + str(temp_air_ cal()) + ‘\n’ temp_data_file.write(temp_data) temp_data_file.close() sys.exit()
Making it happen with cron
cron is a daemon used to execute commands at a specific date and time. It can schedule activities as a one-time event or as recurring tasks. In this project, the cron daemon will be configured to run the Python script every 15 minutes. Use the command crontab -e to edit the crontab to contain the following line of text:
/15 * * * homepi/scripts/temp_reader_both.py >/dev/ null 2>&1
crontab instructions have six fields, separated by spaces or tabs. The first five fields detail the time at which it should run. The last field is the command, made up of remaining characters, including spaces. This field is the actual command that will be run. A good way to confirm that cron won’t have a problem with the command is to try it using the command line.
Roe, roe, roe your boat
The Pi unit will be exposed to the elements. The design of the temperature sensors enables them to remain outside; the Raspberry Pi, not so much. Finding a 5V DC power supply with sufficient current and weatherproofing proved to be costly. With that in mind, using a standard Pi power supply while protecting the Pi from the elements made finding a suitable enclosure for it most important.
The project is undergoing soak-testing (literally) using a fish aquarium. The device is scheduled to be installed the summer of 2019; our remaining work involves configuring a laptop to access the data.
During testing, the heating elements in the home hot water system became intermittent. To troubleshoot the issue, we installed the pispawn temperature sensors on the hot water tank – one sensor near the upper thermostat, and the second near the lower thermostat. The cron job was adjusted for fiveminute readings.
After a week of normal hot water tank operations (showers, running the dishwasher, washing clothes and so on), it was determined from the temperature data available that the lower tank element wasn’t reliable and needed replacing. It works, it really works!
So there you have it: two temperature sensors being monitored and recorded using a slice of tasty Raspberry Pi.