Table of Contents¶
Installation¶
Prepare a Raspberry Pi (RPi) to read a DHT22 (digital humidity and temperature sensor) and post values as an EPICS IOC server.
- Initial configuration of the RPi
- Installation of required libraries
- Installation of the project code
- Run the project
Initial Configuration¶
There are several steps to configure a new RaspberryPi for use. We’ll follow (more or less) this guide from Adafruit: https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/installing-circuitpython-on-raspberry-pi
- Parts list
- Connect a DHT22 sensor to the RPi
- Prepare the Operating System media
- Boot the RPi
- Pick a unique host name
raspi-config
- Apply Operating system updates
- Enable the hardware interfaces used by this project
- Make Python v3 be the default
python
- Reboot
Connect the DHT22 sensor¶
If needed, solder a single-row, 6-pin socket header to the RPi board, covering GPIO pins 1,3,5,7,9,11
Press a single-row, 5-pin strip of right-angle header pins into the sockets for pins 1,3,5,7,9, as shown in the next two photos.
connect the 3 pins of the DHT22 as follows:
DHT22 pin GPIO pin meaning +
1 3v3 Power (+3.3 VDC) out
7 GPIO 4 (Pin 4, to match the software) -
9 Ground
Prepare the Operating System media¶
- OS Media choice: micro SD card, 4 GB (larger is not needed for this project but works fine, takes longer to flash AND backup, takes more space to backup)
- flash a new Raspberry Pi OS Lite onto a micro SD card (Balena Etcher recommended)
- enable SSH login: create empty
ssh
file on boot partition - configure WiFi: create
wpa_supplicant.conf
file on boot partition per https://desertbot.io/blog/headless-raspberry-pi-4-ssh-wifi-setup - Make Python v3 be the default python (python v2 is EOL starting 2020).
Boot the RPi¶
- install micro SD card in RPi and apply power
- identify new RPi IP number on your subnet and login:
ssh pi@new.I.P.number
- password is
raspberry
until you change it (highly recommended)
Pick a unique host name¶
If you plan on having more than one RPi on your local subnet, then you
should give a unique to each and every one of them. You can be
creative, or mundane. Here, we name our pi based on its Serial number
(from /proc/cpuinfo
). We’ll start with rpi
(to make the host
name recognizable), then pick the last four characters of the serial
number, expecting that to make a unique name:
# Suggested host name:
echo rpi$(cat /proc/cpuinfo | grep Serial | tail -c 5)
Use this name in raspi-config
below.
raspi-config¶
Run sudo raspi-config
and configure these settings:
- 1 change password for user
pi
- 2 Network Options: N1 Hostname – pick a unique name, see suggestion above
- 4 Localisation Options: I2 Change Timezone – (if not set in
wpa_supplicant.conf
file) - 5 Interfacing Options: P4 SPI – Yes
- 5 Interfacing Options: P5 I2C – Yes
- 5 Interfacing Options: P8 Remote GPIO – No
- 8 Update – select it
You may be prompted to reboot now. Probably best to reboot if you changed the hostname.
In different versions of RaspberryPi OS and raspi-config
, these
settings may be moved to other submenus. You might have to hunt for
them.
Apply Operating system updates¶
Update the operating system with latest changes, patches, and security items. This command only runs the install if the first command (identify the packages with available upgrades) succeeds:
sudo apt-get update && sudo apt-get upgrade -y
This step could take some time (5-60 or more), depending on how many updates have been released since your download of the OS image was released.
Make Python v3 be the default python
¶
By default, python v2 is what you get when you type python
. Since
python v2 reached the end-of-life after 2019, we want python3
to be
called when we type python
. Here’s how to make that happen:
# make python3 the default python
sudo apt-get install -y python3 git python3-pip
sudo pip3 install --upgrade setuptools
sudo update-alternatives --install /usr/bin/python python $(which python2) 1
sudo update-alternatives --install /usr/bin/python python $(which python3) 2
sudo update-alternatives --config python
Installation of required libraries¶
Enable the _I2C_ and _SPI_ interfaces:
sudo apt-get install -y python3-smbus i2c-tools
This command will show any I2C or SPI devices in the system:
ls -l /dev/{i2c,spi}*
Any i2c-connected devices will report their address here:
sudo i2cdetect -y 1
# install python modules to support our Python code
# need module adafruit_dht
# https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/installing-circuitpython-on-raspberry-pi
pip3 install RPI.GPIO adafruit-blinka adafruit-circuitpython-dht
sudo apt-get install -y libgpiod2
# need module caproto
pip3 install caproto --no-warn-script-location
# to run EPICS IOC in a detached shell
sudo apt-get install -y screen
Installation of the project code¶
mkdir ~/Documents
cd ~/Documents
git clone https://github.com/prjemian/dhtioc
cd dhtioc/
pip3 install -e .
chmod +x dhtioc/dhtioc_manage.sh
pushd ${HOME}/.local/bin
ln -s ${HOME}/Documents/dhtioc/dhtioc/dhtioc_manage.sh ./
Run the IOC : command line¶
dhtioc -h
dhtioc --list-pvs --prefix ${HOSTNAME}:
Run the IOC : automatically¶
With a bash shell script, the dhtioc
program can be started or
stopped. When this script is added as a periodic cron
task, the
program will start automatically if it has stopped.
pi@rpi170f:~/Documents/dhtioc $ dhtioc_manage.sh
Usage: dhtioc_manage.sh {start|stop|restart|status|checkup|console|run}
COMMANDS
console attach to IOC console if IOC is running in screen
checkup check that IOC is running, restart if not
restart restart IOC
run run IOC in console (not screen)
start start IOC
status report if IOC is running
stop stop IOC
- start the IOC:
dhtioc_manage.sh start
- stop the IOC:
dhtioc_manage.sh stop
- restart the IOC:
dhtioc_manage.sh restart
- is the IOC running:
dhtioc_manage.sh status
- start IOC if not running:
dhtioc_manage.sh checkup
Add checkup
and restart
to periodic tasks¶
The cron
program runs periodic tasks. It is flexible to configure.
The following first line is the configuration to run the checkup
every two
minutes (*/2
). Any output (both print and error) will be discarded.
Sometimes, the dhtioc will stop logging temperature, such as shown in the next chart. Until the source of that is resolved, the second line below will restart the IOC at 3 minutes past the hour, every hour of every day.
*/2 * * * * /home/pi/.local/bin/dhtioc_manage.sh checkup 2>&1 > /dev/null
3 * * * * /home/pi/.local/bin/dhtioc_manage.sh restart 2>&1 > /dev/null
Add these lines to the list of periodic tasks using an editor (you’ll be
asked which editor, pick nano
if you aren’t sure which):
crontab -e
Scroll to the bottom of the file and enter the line above on a new line. Save the file and exit the editor. Within a couple minutes, the IOC should start automatically.
Look for the data log files¶
Once the IOC is running and has started collecting valid readings from the DHT22 sensor, there should be log files under ~/Documents/dhtioc_raw/ based on the year, month, and day. A new log file will be written each day (so no file get more than about 1 MB). These are text files with whitespace as separator between columns.
EXAMPLE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # file: /home/pi/Documents/dhtioc_raw/2020/12/2020-12-05.txt
# created: 2020-12-05 00:00:00.126145
# program: dhtioc
# version: 1.1.1+1.gcd2796d
# URL: https://dhtioc.readthedocs.io/
#
# IOC prefix: rpidec7:
#
# time: python timestamp (``time.time()``), seconds (since 1970-01-01T00:00:00 UTC)
# RH: relative humidity, %
# T: temperature, C
#
# time RH T
1607148000.12 43.0 22.5
1607148002.13 43.0 22.5
1607148004.13 43.0 22.5
1607148006.12 42.9 22.5
1607148008.13 42.9 22.5
1607148010.13 42.9 22.5
1607148012.12 42.9 22.5
|
Parts, Purchasing¶
RPi Zero W, preferred for this project:
RPi Zero series, because it easily runs headless, and only needs a 5 VDC, 1A power supply with micro USB connector.
Unlike the plain RPi Zero, has built-in WiFi.
Unlike the RPi Zero WH, you can solder just the pins you want, so you don’t expose possible short circuits of supply Voltage to ground from the unused pins.
- RPi 4 running NextCloudPi : Follow the wiring and installation instructions to add dhtioc to your NextCloudPi server!
Tip
Enclosures
For the best measurement of ambient conditions, place the DHT22 sensor head outside of the enclosure. Place the sensor inside to measure the RPi operating temperature.
Parts List¶
- Raspberry Pi (any model)
- power supply for the RPi (if you don’t have)
- SD card for the RPi, 4GB or larger (if you don’t have)
- enclosure or case for the RPi (suggested, optional)
- DHT22 (AM2302) Digital Humidity & Temperature sensor
- solderable header pins, sockets, jumper wires (optional), as needed
- connector wiring (optional), as needed
Purchasing Suggestions¶
- RPi Zero W complete starter kit:
- https://www.microcenter.com/product/627789/vilros-raspberry-pi-zero-w-complete-starter-kit
- RPi Zero W board:
- https://www.adafruit.com/category/933?src=raspberrypi
typical indoor enclosure (Adafruit case for the Zero): https://www.adafruit.com/product/3252 or https://chicagodist.com/products/adafruit-raspberry-pi-zero-case
typical outdoor electrical outlet enclosure: https://www.homedepot.com/p/Red-Dot-1-Gang-GFCI-Weatherproof-Non-Metallic-Electrical-Box-Cover-Kit-S355P/204193191
DHT22 sensor: https://www.amazon.com/HiLetgo-Temperature-Humidity-Electronic-Practice/dp/B0795F19W6
header pins & sockets, assortment: https://www.amazon.com/MCIGICM-Connector-Assortment-arduino-Stackable/dp/B07X23LQQF or https://chicagodist.com/search?q=header
jumper wires: pin/pin, socket/socket: https://www.adafruit.com/category/306 or https://chicagodist.com/search?q=jumper%20wire
References¶
- Balena Etcher
- caproto
- EPICS
- RPi CircuitPython
- RPi pinout
- RPi OS downloads -
- RPi WiFi -
- Statistics - Linear Regression
- Statistics - Correlation and Rgression
- Statistics - numpy polyfit
- Statistics - Weighted least squares
- Statistics - weighted linear regression
- Statistics - least squares method
- Statistics - regression analysis
- Statistics - Deming regression
Source : StatsReg
¶
source code: StatsReg¶
Implement a set of statistics registers in the style of a pocket calculator.
The available routines are:
def Clear(): clear the stats registers
def Show(): print the contents of the stats registers
def Add(x, y): add an X,Y pair
def Subtract(x, y): remove an X,Y pair
def AddWeighted(x, y, z): add an X,Y pair with weight Z
def SubtractWeighted(x, y, z): remove an X,Y pair with weight Z
def Mean(): arithmetic mean of X & Y
def StdDev(): standard deviation on X & Y
def StdErr(): standard error on X & Y
def LinearRegression(): linear regression
def LinearRegressionVariance(): est. errors of slope & intercept
def LinearRegressionCorrelation(): the regression coefficient
def CorrelationCoefficient(): relation of errors in slope & intercept
see: | http://stattrek.com/AP-Statistics-1/Regression.aspx?Tutorial=Stat |
---|
pocket calculator Statistical Registers, Pete Jemian, 2003-Apr-18
Source code documentation¶
-
class
dhtioc.StatsReg.
StatsRegClass
[source]¶ pocket calculator Statistical Registers class
-
Add
(x, y)[source]¶ add an X,Y pair to the statistics registers
Parameters: - x (float) – value to accumulate
- y (float) – value to accumulate
-
AddWeighted
(x, y, z)[source]¶ add a weighted X,Y, +/- Z trio to the statistics registers
Parameters: - x (float) – value to accumulate
- y (float) – value to accumulate
- z (float) – variance (weight =
1/z^2
) of y
-
Clear
()[source]¶ clear the statistics registers: \(N=w=\sum{x}=\sum{x^2}=\sum{y}=\sum{y^2}=\sum{xy}=0\)
-
CorrelationCoefficient
()[source]¶ relation of errors in slope and intercept
Returns: correlation coefficient Return type: float
-
LinearEval
(x)[source]¶ Evaluate a linear fit at the given value: \(y = a + b x\)
Parameters: x (float) – independent value, x Returns: y Return type: float
-
LinearRegression
()[source]¶ For (x,y) data pairs added to the registers, fit and find (a,b) that satisfy:
\[y = a + b x\]Returns: (a, b) for fit of y=a+b*x Return type: (float, float)
-
LinearRegressionCorrelation
()[source]¶ the regression coefficient
Returns: (corr_a, corr_b) – is this correct? Return type: (float, float) See: http://stattrek.com/AP-Statistics-1/Correlation.aspx?Tutorial=Stat Look at “Product-moment correlation coefficient”
-
LinearRegressionVariance
()[source]¶ est. errors of slope & intercept
Returns: (var_a, var_b) – is this correct? Return type: (float, float)
-
Mean
()[source]¶ arithmetic mean of X & Y
\[(1 / N) \sum_i^N x_i\]Returns: mean X and Y values Return type: float
-
StdDev
()[source]¶ standard deviation on X & Y
Returns: standard deviation of mean X and Y values Return type: (float, float)
-
StdErr
()[source]¶ standard error on X & Y
Returns: standard error of mean X and Y values Return type: (float, float)
-
Subtract
(x, y)[source]¶ remove an X,Y pair from the statistics registers
Parameters: - x (float) – value to remove
- y (float) – value to remove
-
Source : datalogger
¶
source code: datalogger¶
-
class
dhtioc.datalogger.
DataLogger
(ioc_prefix, path=None)[source]¶ Record raw values in data files.
PARAMETERS
- ioc_prefix
- str : EPICS IOC prefix
- path
- str :
Base directory path under which to store data files.
(default:
~/Documents/dhtioc_raw
)
-
create_file
(fname)[source]¶ Create the data file (and path as necessary)
PARAMETERS
- fname
- str : File to be created. Absolute path.
Source : ioc
¶
source code: ioc¶
Provide humidity and temperature using EPICS and Raspberry Pi
DHT_IOC (*args, sensor, report_period, **kwargs) |
EPICS server (IOC) with humidity & temperature (read-only) PVs. |
main () |
Entry point for command-line program. |
-
class
dhtioc.ioc.
DHT_IOC
(*args, sensor, report_period, **kwargs)[source]¶ EPICS server (IOC) with humidity & temperature (read-only) PVs.
counter
Used by autodoc_mock_imports. humidity
(instance, async_lib)Set the humidity, temperature and other PVs. humidity_raw
Used by autodoc_mock_imports. humidity_trend
Used by autodoc_mock_imports. humidity_trend_array
Used by autodoc_mock_imports. temperature
Used by autodoc_mock_imports. temperature_raw
Used by autodoc_mock_imports. temperature_f
Used by autodoc_mock_imports. temperature_f_raw
Used by autodoc_mock_imports. temperature_trend
Used by autodoc_mock_imports. temperature_trend_array
Used by autodoc_mock_imports.
Source : reader
¶
source code: reader¶
-
class
dhtioc.reader.
DHT_sensor
(pin, period)[source]¶ Get readings from DH22 sensor.
read
()Read signals from the DHT22 sensor. read_in_background_thread
(**kwargs)ready
Has a value been read for both humidity and temperature? terminate_background_thread
(*args, **kwargs)Signal the background thread to stop. -
ready
¶ Has a value been read for both humidity and temperature?
-
Source : trend_analysis
¶
source code: trend_analysis¶
Analyze signal for its recent trend.
Trend () |
Compute the current trend in signal values |
-
class
dhtioc.trend_analysis.
Trend
[source]¶ Compute the current trend in signal values
Apply smoothing with various factors, and take the slope of the smoothed signal v. the smoothing factor.
compute
(reading)(Re)compute the trend. slope
Set the trend as the slope of smoothed v. -
compute
(reading)[source]¶ (Re)compute the trend.
Actually, reset the stats registers and load new values
-
slope
¶ Set the trend as the slope of smoothed v. (1-smoothing factor).
-
Source : utils
¶
source code: utils¶
Utility functions.
C2F (celsius) |
Convert celsius to fahrenheit. |
run_in_thread (func) |
(decorator) run func in thread USAGE. |
smooth (reading, factor, previous) |
apply smoothing function |
Change History¶
1.1.2: | release expected -tba- |
---|---|
1.1.1: | released 2020-08-20 |
1.1.0: | released 2020-08-18 |
1.0.0: | released 2020-08-17 |
0.3.3: | |
0.3.2: | |
0.3.1: | |
0.3.0: |
|
0.2.0: | |
0.1.2: | |
0.1.1: | |
0.1.0: | |
0.0.4: | |
0.0.3: | |
0.0.2: | |
0.0.1: |
This project uses [sematic versioning](https://semver.org).