Installing the AM2302 Temp/Humidity sensor on OpenWrt

OpenWrt SNAPSHOT, r15090-52a5d0d27f
Pi 4

I would like to install my AM2302 temperature and humidity sensor on OpenWrt. Is this possible?

I currently have it installed on a Pi running Raspbian.

To install the sensor there is a python library that needs a few dependencies which I got for Raspbian this way:

sudo apt-get upgrade
sudo apt-get install build-essential python-dev

I tried installing those dependencies in OpenWrt with opkg but they are not there..

root@OpenWrt:~# opkg install build-essential
Unknown package 'build-essential'.
Collected errors:
 * opkg_install_cmd: Cannot install package build-essential.
root@OpenWrt:~# opkg install python-dev
Unknown package 'python-dev'.
Collected errors:
 * opkg_install_cmd: Cannot install package python-dev.
root@OpenWrt:~#

Is it possible to compile OpenWrt with those dependenies baked in?

Cheers,

Flex

Did you run first :

opkg update

Consider using more standard sensors like those using 1-wire or I²C

Packages on Raspbian may or may not have an equivalent on OpenWrt, and may or may not have the same name, even if you are using the same platform.

Perhaps there are other libraries that support those sensors and have been ported to OpenWrt. Or you can try to find out the equivalent dependencies on OpenWrt.

@Hegabo
Yes I did opkg update but those dependencies are still not available.

@eduperez
How would I search for equivalent dependencies on OpenWrt for the AM2302 sensor ? Is that done at the stage of compiling OpenWrt where you select what packages and things you want in your build?

@AndrewZ
Do you have experience getting I2C sensors working on OpenWrt? I found the AHT20 I2C sensor.

Looks like it could connect directly to the GPIO pins on my Pi 4. I see this page describes installing the OpenWrt I2C kernel module and apart from that looks like I would need Python3 and pip3 to install various python packages.

Will this AHT20 sensor definitely install and work on OpenWrt?

Cheers,

Flex

just use search :wink:


The first step in the instructions seem to be installing packages related to Python. I would start with the description on Raspbian of those packages, and the description of packages related to Python on OpenWrt.

Or you can jump directly to the next step, and see what fails and what seems to be missing.

On the other hand, OpenWrt is not designed to be used as a building environment. I am not sure this is the right path.

@AndrewZ
Thanks for those links... so at least I have some options with I2C based sensors. I like the BME280 that I see you got working. Was there anything difficult about installing it? You need Python and I2C installation? Did you have to compile a customized OpenWrt image or anything like that?

@eduperez
Maybe you are right. But there seems to be a DHT11 module for OpenWrt that adds support for DHT11 and DHT22 sensors like my AM2302. Do you know how I would use it? Maybe I don't need build-essentials after all?

Cheers,

Flex

No Python required, no need to build a custom image. Just decide whether you will use native I²C ports or emulate I²C using GPIO, then install required packages in a standard way.
One more useful link for you: [How to] install RTC hardware clock pcf8563 (I2c)

Cheers AndrewZ
Do you see the steps in the prerequisites section in this thread. Are they the steps to set up I2C emulation using GPIO? From this thread it looks like you didn't go with native I2C yourself? Why not and which is better do you know?

With your BME280 sensor did you follow all these steps to install various python libraries? In that previous (second) link I see you simply reading the temp with the cat command.

Sorry for all the questions!

Flex

This is what I have in my records:

kmod-i2c-gpio kmod-i2c-gpio-custom kmod-i2c-core kmod-i2c-algo-bit kmod-iio-bmp280 kmod-iio-bmp280-i2c kmod-rtc-ds1307
optionally: i2c-tools hwclock iio-utils tree

kmod-rtc-ds1307 and hwclock are there because of RTC module I'm using on the same bus. No python required! All the data is available through sysfs, so you can use cat to read the values.
With the board I was using I found that native I²C support is not that good, so I switched to GPIO emulation that was found to be rock solid. Different board will give different result, I suggest to start from native support if available then switch to GPIO in case of failure.

1 Like

@AndrewZ
Brilliant, thanks for that.

Now, since it is the title of this thread... I wonder what is this link about that talks about adding support for DHT11/22/AM2302 sensors in OpenWrt? If there is support already in the firmware it would be nice to know as I already have three of those sensors.

Flex

Looks like the AM2302 is the same as the DHT22, and there is a kernel module specific to support it: https://openwrt.org/packages/pkgdata/kmod-iio-dht11. After installing ("opkg install ...") and loading ("modprobe ...") that module, you should see a new special file being created somewhere around "/sys/bus/iio/devices/iio"; then you just have to read the contents using "cat ...".

1 Like

Sounds promising... I connected my AM2302 to the Pi but it's not working for me quite yet:

I did opkg update then opkg install kmod-iio-dht11 but modprobe kmod-iio-dht11 gives error: "failed to find a module named kmod-iio-dht11"

OK then I did modprobe dht:

root@OpenWrt:/sys/bus/iio/devices# modprobe dht11
root@OpenWrt:/sys/bus/iio/devices# ls
root@OpenWrt:/sys/bus/iio/devices# lsmod | grep dht
dht11                  16384  0
industrialio           65536  1 dht11
root@OpenWrt:/sys/bus/iio/devices# ls
root@OpenWrt:/sys/bus/iio/devices#

The dht11 module seems to be loaded but when I do an ls on /sys/bus/iio/devices there is nothing in there?

When I opkg list and grep for that module I get this:

root@OpenWrt:/sys/bus/iio/devices# opkg list | grep -e kmod-iio-dht11
kmod-iio-dht11 - 5.4.80-1 - support for DHT11 and DHT22 digitial humidity and temperature sensors attached at GPIO lines. You will need a custom device tree file to specify the GPIO line to use.

Maybe I need to make a "custom device tree file to specify the GPIO line to use". Any ideas how I do that? I connected the Output line of the sensor to Pin 7 (GPIO4).

Thank so much,

Flex

I got the Am2302 sensor working on my Pi 4 running OpenWrt.

Thanks to @eduperez and @AndrewZ for help and advice.

My Router details:
OpenWrt SNAPSHOT r15090-52a5d0d27f / LuCI Master git-20.332.74200-03c77da
Kernel: 5.4.80
Raspberry Pi 4

Here are the steps I followed:

I connected the sensor to GPIO pins on the Pi as explained here but obtained readings not via python but using the sysfs method reading values from a device tree file set up like this..

opkg update
opkg install kmod-iio-dht11
modprobe dht11

This loads the needed dht11 module.. industrialio is also loaded:

lsmod | grep dht
dht11 16384 0
industrialio 65536 1 dht11

As mentioned in the information about the dht11 module..

root@OpenWrt:/sys/bus/iio/devices# opkg list | grep -e kmod-iio-dht11
kmod-iio-dht11 - 5.4.80-1 - support for DHT11 and DHT22 digitial humidity and temperature sensors attached at GPIO lines. You will need a custom device tree file to specify the GPIO line to use.

It requires a device tree file to specify the GPIO line to use and then where readings can be read from.
For this, there is already a device tree overlay in: /boot/overlays/dht11.dtbo

To make use of it, to /boot/config.txt you add this:
dtoverlay=dht11,gpiopin=4
Now reboot the Pi.

You you will see that a "device tree" exists at /sys/bus/iio/devices/iio:device0 for your attached sensor and you can "cat" two files for temperature and humidity readings.

cat /sys/bus/iio/devices/iio:device0/in_temp_input
cat /sys/bus/iio/devices/iio:device0/in_humidityrelative_input

Sometimes the readings don't give values. This is expected and is to do with the features of the sensor. A workaround created by adam van gaalen in this really helpful Raspberry Pi forum thread uses a tcsh script that takes five consecutive readings and reports that which occurred most often in the sample.

I had to install bc and tsch and make the script executable.

opkg update
opkg bc
opkg tsch
chmod +x scriptname

Here is the script:

#!/bin/tcsh
	#
	@ NTRIES = 0
	echo '' >& TEMP_readings
	echo '' >& RH_readings
	while ( ${NTRIES} < 5 )
	/bin/cat /sys/devices/platform/dht11@4/iio:device0/in_temp_input >>& TEMP_readings
	/bin/cat /sys/devices/platform/dht11@4/iio:device0/in_humidityrelative_input >>& RH_readings
	@ NTRIES = ${NTRIES} + 1
	end
	#
	set TEMP = "`/bin/cat TEMP_readings |& /bin/grep -v dht11@0 | /bin/grep -v -- '-' | /usr/bin/uniq -c | /usr/bin/sort -n | /usr/bin/tail -1 | /usr/bin/tr -s ' ' ' ' | /bin/sed -e 's/^ //' | /usr/bin/cut -f2 -d' '`"
    set RH = "`/bin/cat RH_readings |& /bin/grep -v dht11@0 | /bin/grep -v -- '-' | /usr/bin/uniq -c | /usr/bin/sort -n | /usr/bin/tail -1 | /usr/bin/tr -s ' ' ' ' | /bin/sed -e 's/^ //' | /usr/bin/cut -f2 -d' '`"
	#
	
	# Format the readings to one decimal place
	# Credit: https://unix.stackexchange.com/a/264283/400373
	set T = "`echo 'scale=1; $TEMP' / 1000 | bc -l`"
	set H = "`echo 'scale=1; $RH' / 1000 | bc -l`"
	echo "TEMP = ${T}, RH = ${H}"
	#
	
	# This was the original way of printing out the readings
	#echo "TEMP = ${TEMP}, RH = ${RH}"
	#

exit 0

Then run the script to get sensor values from AM2302 attached to Pi 4 running OpenWrt.
./scriptname

I have two AM2302 sensors at home now. One uses the Adafruit_DHT library in which Python is used to get the readings. And now this other attached to OpenWrt using the sysfs approach. I positioned them both close together to compare their readings. The temperature readings are about 1C apart however for the humidity readings one sensor is saying 65%RH but the other is saying 88%RH.

I guess the difference in RH is down to cheap sensors rather than any difference using the sysfs approach to reading sensor values instead of python..

Cheers,

Flex

1 Like

you dont really need modprobe... tcsh or bc...

you could however install coreutils-sleep for nano-second backoff to speed up faulty read cycles...
edit: sadly it seems that 2-10 seconds seems to be 'required' to not cause protocol lockups ( hard reset ) with these... change 0.23 in the script to 3... then call it from cron every 5-30mins because it's slow and redirect to a file/s... then read the files...
edit2: seems these sensors have a habit of locking up regardless of poll interval... luckily the rpi has spare gpio's so optimally the script can be adapted on 'sensor-issues' to toggle and additional gpio which should be used for sensor vcc...

non-tcsh-sample
#!/bin/sh
FAILcMAX=23
FAILc=0

readsensor() {

	local FN="readsensor"
	local RETVAL=
	local RESULT=
	local SYSNODE="${2}"
	case "${1}" in
		dht11temp)
			RESULT=$(/bin/cat $SYSNODE 2>/dev/null)
			RETVAL=$?
		;;
		dht11hum)
			RESULT=$(/bin/cat $SYSNODE 2>/dev/null)
			RETVAL=$?
		;;
	esac
	if [ "$RETVAL" -ne 0 ]; then return 1; else echo "$RESULT" && return 0; fi

}

outputbestresult() {

	local FILE="${1}"
	local rawRESULT=
	local RESULTmajor=
	local RESULTminor=
	rawRESULT=$(/bin/cat $FILE | /usr/bin/uniq -c | /usr/bin/sort -n | tail -n 1 | tr -s '\t' ' ' | cut -d' ' -f3)
	if [ ! -z "$rawRESULT" ]; then #&& result -gt 0 && -lt 100000
		RESULTmajor=$(echo "$rawRESULT" | cut -c1,2)
		RESULTminor=$(echo "$rawRESULT" | cut -c3)
		echo "$RESULTmajor.$RESULTminor"
	else
		echo "00.0"
	fi
}

if [ "$(opkg status coreutils-sleep | wc -l)" -eq 0 ]; then
 opkg update && opkg install coreutils-sleep
fi

TMPd="/tmp"
if [ -f "$TMPd/.sensorissues" ]; then echo "sensor has issues or rm $TMPd/.sensorissues" && exit 0; fi
rm $TMPd/TEMPout 2>/dev/null
rm $TMPd/HUMout 2>/dev/null
SYSNODE_TEMP="$(find /sys/devices/platform | grep '/in_temp_input$' | head -n1)"
SYSNODE_HUM="$(find /sys/devices/platform | grep '/in_humidityrelative_input$' | head -n1)"
if [ -z "$SYSNODE_TEMP" ] || [ -z "$SYSNODE_HUM" ]; then echo "no temp or hum in sysfs" >&2 && exit 0; fi


i=1
while [ "$FAILc" -lt "$FAILcMAX" ]; do	

	Tresult=
	Hresult=

	l=0
	while [ -z "$Tresult" ]; do
		[ $((l++)) -gt 4 ] && break
		sleep 0.23
		Tresult=$(readsensor dht11temp "$SYSNODE_TEMP")
		[ "$l" -gt 1 ] && FAILc=$(($FAILc + 1))
	done
	echo "$Tresult" >> $TMPd/TEMPout

	l=0
	while [ -z "$Hresult" ]; do
		[ $((l++)) -gt 4 ] && break
		sleep 0.23
		Hresult=$(readsensor dht11hum "$SYSNODE_HUM")
		[ "$l" -gt 1 ] && FAILc=$(($FAILc + 1))
	done
	echo "$Hresult" >> $TMPd/HUMout

	[ $((i++)) -gt 4 ] && break
done

if [ "$FAILc" -ge "$FAILcMAX" ]; then touch $TMPd/.sensorissues && exit 1; fi

echo "TMPavg=\"$(outputbestresult "$TMPd/TEMPout")\""
echo "HUMavg=\"$(outputbestresult "$TMPd/HUMout")\""

exit 0
1 Like

Do you mean AM2320 sensor?

I have one of those I can read it in OpenWrt with the kernel I2C stack, smbus and the python smbus2 library. smbus2 is not in OpenWrt (smbus 1 is) so it needs to be compiled / installed.

Going to try the dht11 driver now.

The sensor has a non-disableable sleep feature. Basically the first reading will be stale data from before it went to sleep. Take a reading to wake up the sensor, throw away that data, then read again about 100 ms later after it has acquired a new reading.

1 Like

I tried your script, it's awesome.. I've a lot to learn about shell scripting. The only bit I'm confused about is where you use cut -d' ' -f3. The last line from $FILE will contain only a single string such as 18400 so there will only be one token anyway?

Actually with the other script I have seen entries in the temp file like these:

cat: read error: Operation timed out
cat: read error: I/O error

So I guess that makes sense then.. assuming the file contained no numerical values at all which is possible if the sensor was faulty.

Why I don't need to use the modprobe command I guess you mean that opkg install automatically installs and enables the module? I see there is an entry for the module in /etc/modules.d/56-iio-dht11 so it will be automatically loaded at boot time.

Cheers,

Flex

@mk24
It's the AM2302 sensor I'm using. Yes, getting data from it seems to be a bit hit and miss hence the two scripts in this thread that retry multiple times to get readings. The coreutils sleep feature is an improvement in that regard.

I was very glad to see I can use it without the Adafruit library that requires build-essentials to compile a python library because and I wasn't able to figure out if build-essentials can be installed on to OpenWrt... don't think it can without maybe compiling it in yourself?

Cheers,

Flex

on recent releases ( last 2 years )... I think i've only ever had to do that once out of over 1000's of kmod installs... so yes... opkg handles...

the clunky logic, has a space at the beginning of the line... thus the value is token 3... ( after tr )... = xyz000 = cut 1,2 + 3 = nn.n