This device kit seeks to display how simple Avimesa Gadget can make IoT projects and is intended for a Raspberry Pi. In this tutorial, we’ll use the Python (3) programming language and we’re going to get friendly with the subprocess module in order to drive (or control) Gadget. We’ll also learn how to hook up an ADC (analog-to-digital converter) to an arbitrary sensor with an analog output and a Raspberry Pi. The ADC we’ll be using is the MCP3008-I/P. We should note that the MCP3008-I/P uses SPI for communication to its controller (in our case a Raspberry Pi). The last piece of information we’ll need before getting started is that we’ll be using another Python module for ease of access to the Raspberry Pi’s peripherals (in our case, SPI): gpiozero. The gpiozero module is the recommended Python module for controlling the Raspberry Pi’s peripherals.
Components
- a (1) SPI-enabled Raspberry Pi – (2) I’m using this Raspbian (Stretch) Lite image
- an Avimesa Gadget installation
- a valid set of Avimesa Device credentials. Get a free account here
- Python 3 – This comes pre-installed in most relevant Raspbian images
- a (3) Python 3 gpiozero installation
- a MCP3008-I/P or MCP3XXX series chip
- a sensor with an analog output – I’ll be using this humidity sensor
- a breadboard and wiring (female and male)
(1) From the CLI, run sudo raspi-config
and enable SPI via Interfacing Options > P4 SPI > Yes. Next, reboot: sudo reboot
. Finally, verify /dev/spidev0.0
is present in the filesystem. If you run into any issues, please visit this page for help troubleshooting.
(2) If you need help flashing an SD card with a Raspbian image, please visit here.
(3) To install the Python module gpiozero, you’ll first want to make sure your repository list is up to date by running sudo apt update
. Second, install the module for Python (3) using the following command: sudo apt install python3-gpiozero
. If you run into any issues, please visit here for help troubleshooting.
Hardware Setup
First, let’s wire up our MCP3008. Following is the pinout for the MCP3008, obtained here, and the associated Raspberry Pi (PX) and analog sensor (AX) pin connections: NOTE: The Raspberry Pi pin connections are from the Raspberry Pi 40 pinout header (Not the physical Broadcom connections). This link contains a great representation of the Raspberry Pi 40 pinout header and the associated Broadcom connections.
The analog sensor connections are (usually) simple and can be determined via the sensor’s datasheet. For the soil humidity sensor I’m using: connect P0 (3V3) and P6 (GND) to the specified (+) and (-) pins respectively and connect the analog out to A0 of the MCP3008.
Software Setup
The script:
import subprocess
from time import sleep
from gpiozero import MCP3008, DigitalOutputDevice
def get_soil_moisture():
# gpiozero has a MCP3008 implementation that
# has SPI under the hood
adc = MCP3008(channel=0)
sleep(.1)
r_val = adc.value
adc.close()
# Values determined through sensor
# calibration and through usage of the
# equation of a line
r_val = 100.0 * (-1.33 * r_val + 1.33)
return r_val
# Use your own Avimesa credentials here
gadget_args = ['avmsagadget',
'-i',
'DEADBEEFDEADBEEFDEADBEEFDEADBEEF',
'DEADBEEFDEADBEEFDEADBEEFDEADBEEF']
# Wrap Gadget using Popen class
gadget = subprocess.Popen(gadget_args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# Let's use Gadget's AUTORUN feature
# to automatically send sensor data
gadget.stdin.write(b'set AUTORUN = 1\n')
gadget.stdin.flush()
# GPIO17 for momentary sensor power.
# Slow degradation to soil moisture
# sensor
sensor_power = DigitalOutputDevice(17)
while True:
try:
# Only apply power to soil moisture sensor
# whenever we take a reading
sensor_power.on()
sleep(.001)
# A little gross, JSON to inject with sensor
# reading
reading = ('{{"chans":[{{"ch_idx":0,"ch_data":['
'{{"data_idx":0,"units":1,"val":{0}}}]}}]}}'
'\n'.format(get_soil_moisture()))
# Turn string into binary
reading = reading.encode()
# Write command to STDIN
gadget.stdin.write(reading)
gadget.stdin.flush()
sensor_power.off()
sleep(5)
except KeyboardInterrupt:
# Trick to send EOF to STDIN
# in order to close Gadget
gadget.stdin.close()
gadget.wait()
print('Gadget exited with rc {0}'.format(gadget.returncode))
break
Avimesa.Live Integration
If you have an active Avimesa.Live account, you can add your sensor there and get some output like this: NOTE: The spike in the graph here is me pouring water into the soil near the soil humidity sensor.