I picked up a TEMPer USB temperature sensor from Walmart for about $12. My goal was to use it with my Home Assistant home automation system.
The model that I picked up supports Windows and it can be used directly in Excel. There is also integration with Home Assistant.
I found that the integration for Linux was tricky. This blog looks at how I got things working with a Raspberry Pi.
USB Connections
The lsusb command can be used to see which USB devices are connected:
pi@pi4:~ $ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 007: ID 413d:2107 Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
It is important to identify the ID model. The TEMPer USB model that I purchased was 413d:2107.
When I searched the Internet I found that people had created different packages but they were based on specific models. (Check your model).
temper.py
There is a Python library file that can be used on the TEMPer family of sensors. This library component is designed to be run directly as a Python file. It can be accessed by:
pip install temper-py
# Or get the file
wget https://raw.githubusercontent.com/ccwienk/temper/master/temper.py
Using the file directly will show the TEMPer device information (Note: use sudo):
$ sudo python3 temper.py
Bus 001 Dev 007 413d:2107 TEMPerGold_V3.1 29.31C 84.76F - - - -
$ sudo python3 temper.py --v
Firmware query: b'0186ff0100000000'
Firmware value: b'54454d506572476f6c645f56332e3120' TEMPerGold_V3.1
Data value: b'80800b6d4e200000'
Bus 001 Dev 007 413d:2107 TEMPerGold_V3.1 29.25C 84.65F - - - -
$ sudo python3 temper.py --json
[
{
"vendorid": 16701,
"productid": 8455,
"manufacturer": "",
"product": "",
"busnum": 1,
"devnum": 7,
"devices": [
"hidraw0",
"hidraw1"
],
"port": "1-1.4",
"firmware": "TEMPerGold_V3.1",
"hex_firmware": "54454d506572476f6c645f56332e3120",
"hex_data": "80800b6d4e200000",
"internal temperature": 29.25
}
]
I found that the Python app was useful and it could be used on a variety of sensors.
Human Interface Devices
The TEMPer sensor acts like a Human Interface Device. When the TEMPer sensor is connected the dmesg utility can be used to show kernel information:
$ dmesg -H
[May 1 21:22] usb 1-1.4: USB disconnect, device number 6
[May 1 21:23] usb 1-1.4: new full-speed USB device number 7 using xhci_hcd
[ +0.135008] usb 1-1.4: New USB device found, idVendor=413d, idProduct=2107, bcdDevice= 0.00
[ +0.000020] usb 1-1.4: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ +0.011366] input: HID 413d:2107 as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:
[ +0.064445] hid-generic 0003:413D:2107.0009: input,hidraw0: USB HID v1.11 Keyboard [HID 413
[ +0.007181] hid-generic 0003:413D:2107.000A: hiddev96,hidraw1: USB HID v1.10 Device [HID 41
(END)
From this output I can see that TEMPer sensor is on the raw human interface device of hidraw1. (For this example the hidraw0 acts like a keyboard but it can’t be used to get temperature info). When I move the TEMPer sensor to a different PC I need to run dmesg again to recheck the hidraw device number, it could be 2,3,4 etc.
A Bash Script
There are some excellent links that got me about 95% of the way. The Bash script below will return a temperature value for my series of TEMPer USB thermometers.
#!/bin/bash
#
# Get the temperature from a USB Temper Thermometer
#
# find the HID device from the kernel msg via dmesg
# parse the line get HID device
hidstr=$(dmesg | grep -E -m 1 'Device.*413d:2107')
# find the postion of the "hidraw" string
hidpos=$(echo $hidstr | grep -b -o hidraw | awk 'BEGIN {FS=":"}{print $1}')
if [ $hidpos = "" ]; then
echo "No TEMPer device found"
else
#get the hidraw device from the string, Note: offset of 1
hidpos1=$((hidpos +1))
hid=$(echo "/dev/${hidstr:hidpos1:7}")
exec 5<> $hid
# send out query msg
echo -e '\x00\x01\x80\x33\x01\x00\x00\x00\x00\c' >&5
# get binary response
OUT=$(dd count=1 bs=8 <&5 2>/dev/null | xxd -p)
# characters 5-8 is the temp in hex x1000
HEX4=${OUT:4:4}
DVAL=$((16#$HEX4))
CTEMP=$(bc <<< "scale=2; $DVAL/100")
echo $CTEMP
fi
If you are always using the TEMPer in only one place you could simplify the script by hard coding the HID number. I wanted to move the sensor between devices so I added a check find the device.
Hi, I find your code simple and is exactly what I need. But I can’t get the temperature from my Temper (1a86:e025). I uncommented the line : echo “TEMPer device found on: $hid”. and removed the “2>/dev/null” from the OUT line to see what is happening. I get:
TEMPer device found on: /dev/0003:1A (so the Temper is found)
from dd, I get:
0+0 records in
0+0 records out
0 bytes (0 B) copied, 7.159e-05 s, 0.0 kB/s
You talked about changing the hidraw number: where do you change it in the code. Can’t figure it out…
Any idea? I tried the Python and temperv14.c and pcsensor.c and I get similar results.
from lsusb:
Bus 004 Device 003: ID 1a86:e025 QinHeng Electronics
from dmesg:
[ 6.188363] hid-generic 0003:1A86:E025.0001: input,hidraw0: USB HID v1.11 Keyboard [HID 1a86:e025] on usb-0000:00:14.0-1/input0
[ 6.188584] hid-generic 0003:1A86:E025.0002: hiddev0,hidraw1: USB HID v1.10 Device [HID 1a86:e025] on usb-0000:00:14.0-1/input1
Thanks in advance
LikeLike
Found the issue. In the line:
awk ‘{ p=index($4,”,”); print “/dev/” substr($4,p+1,7) }’)
changed to:
awk ‘{ p=index($5,”,”); print “/dev/” substr($5,p+1,7) }’)
On the dmesg, the number of fields is not the same…
LikeLike
Hi Pierre,
I’m glad to hear that you got things working. I did some playing with OpenWRT when I repurposed some home routers and I found that the dmsg output isn’t as standard as I had thought.
Below is the code I used on OpenWRT. I hand coded hidraw0…1,2. So basically I started at 0, then 1… until I got a temperature output. I’d like to review the dsmg search to account for different output.
Cheers
Pete
#!/bin/ash
# Note: change to ash to bash for non OpenWRT
#
# temper.sh – get temperature from a USB thermometer
#
hid=”/dev/hidraw1″
exec 5 $hid
# send out query msg
echo -e ‘\x00\x01\x80\x33\x01\x00\x00\x00\x00\c’ >&5
# get binary response
OUT=$(dd count=1 bs=8 /dev/null | xxd -p)
# characters 5-8 is the temp in hex x1000
HEX4=${OUT:4:4}
DVAL=$(printf ‘%d’ “0x${HEX4}”)
awk “BEGIN {print ($DVAL/100)}”
LikeLike
Thanks for the reply. I am using slackware 14.2
LikeLike
Hi Pierre,
The dmesg output doesn’t appear to be consistent between Linux OSs, so I changed the code to search for the position of the “hidraw” string.
The new code is working fine in Ubuntu/Raspian. I wonder if you’d mind checking my temper Bash code in slackware?
Thanks
Pete
#!/bin/bash
#
# Get the temperature from a USB Temper Thermometer
#
# find the HID device from the kernel msg via dmesg
# parse the line get HID device
hidstr=$(dmesg | grep -E -m 1 ‘Device.*413d:2107’)
# find the postion of the “hidraw” string
hidpos=$(echo $hidstr | grep -b -o hidraw | awk ‘BEGIN {FS=”:”}{print $1}’)
if [ $hidpos = “” ]; then
echo “No TEMPer device found”
else
#get the hidraw device from the string, Note: offset of 1
hidpos1=$((hidpos +1))
hid=$(echo “/dev/${hidstr:hidpos1:7}”)
exec 5 $hid
# send out query msg
echo -e ‘\x00\x01\x80\x33\x01\x00\x00\x00\x00\c’ >&5
# get binary response
OUT=$(dd count=1 bs=8 /dev/null | xxd -p)
# characters 5-8 is the temp in hex x1000
HEX4=${OUT:4:4}
DVAL=$((16#$HEX4))
CTEMP=$(bc <<< "scale=2; $DVAL/100")
echo $CTEMP
fi
LikeLike
Hi,
the line:
exec 5 $hid
should be:
exec 5 $hid
the line:
OUT=$(dd count=1 bs=8 /dev/null | xxd -p)
should be:
OUT=$(dd count=1 bs=8 /dev/null | xxd -p)
It’s called “technician dyslexia” LOL!
Here is the result from your script:
root@husky2:/usr/pierre/bin/temper# ./tempernewtest
0
Here is the result from mine:
root@husky2:/usr/pierre/bin/temper# ./tempertest
23.87
Even after a reboot, I still get the same result.
Here is my code:
#!/bin/bash
#
# Get the temperature from a USB Temper Thermometer
#
# find the HID device from the kernel msg via dmesg
# parse the line get HID device
hid=/dev/hidraw1
if [ $hid = “” ]; then
echo “No TEMPer device found”
else
#echo “TEMPer device found on: $hid”
exec 5 $hid
# send out query msg
echo -e ‘\x00\x01\x80\x33\x01\x00\x00\x00\x00\c’ >&5
# get binary response
OUT=$(dd count=1 bs=8 /dev/null | xxd -p)
# characters 5-8 is the temp in hex x1000
HEX4=${OUT:4:4}
DVAL=$((16#$HEX4))
CTEMP=$(bc <<< "scale=2; $DVAL/100")
echo $CTEMP
fi
One thing I noticed with my code: If I get the result ok, then disconnect the usb key and reconnect it right away, result is still ok. But if I try the script while the usb key is out, I get a 0 result, which is normal. But even after reconnecting the usb key, I still get the 0 result. I need to reboot to get back to normal.
LikeLike
Hi Pierre,Thanks for checking out my code.I tried my code
LikeLike
This is what I get when executing the script with debugging:
root@husky2:/usr/pierre/bin/temper# ./tempernewtest
hidstr found on: [ 6.623658] hid-generic 0003:1A86:E025.0002: hiddev0,hidraw1: USB HID v1.10 Device [HID 1a86:e025] on usb-0000:00:1d.0-1.8/input1
hidpos found on: 53
0
Note the 53
If I call it directly from the command line, I get:
echo “[ 6.623658] hid-generic 0003:1A86:E025.0002: hiddev0,hidraw1: USB HID v1.10 Device [HID 1a86:e025] on usb-0000:00:1d.0-1.8/input1″ |grep -b -o hidraw| awk ‘BEGIN {FS=”:”}{print $1}’
56
Note the 56, which is accurate.
Here is the complete script:
#!/bin/bash
#
# Get the temperature from a USB Temper Thermometer
#
# find the HID device from the kernel msg via dmesg
# parse the line get HID device
hidstr=$(dmesg | grep -E -m 1 ‘Device.*1a86:e025’)
# find the postion of the “hidraw” string
hidpos=$(echo $hidstr | grep -b -o hidraw | awk ‘BEGIN {FS=”:”}{print $1}’)
if [ $hidpos = “” ]; then
echo “No TEMPer device found”
else
echo “hidstr found on: $hidstr”
echo “hidpos found on: $hidpos”
#get the hidraw device from the string, Note: offset of 1
hidpos1=$((hidpos +1))
hid=$(echo “/dev/${hidstr:hidpos1:7}”)
exec 5 $hid
# send out query msg
echo -e ‘\x00\x01\x80\x33\x01\x00\x00\x00\x00\c’ >&5
# get binary response
OUT=$(dd count=1 bs=8 /dev/null | xxd -p)
# characters 5-8 is the temp in hex x1000
HEX4=${OUT:4:4}
DVAL=$((16#$HEX4))
CTEMP=$(bc <<< "scale=2; $DVAL/100")
echo $CTEMP
fi
LikeLike
i tried this it says exec: 5: not found
LikeLike
Hi,
What is your hardware and OS? I found that this script worked on my Raspberry PI (Raspbian), and 2 nodes that I had at home.
I was getting the USB temper device info from dmesg. I would suggest putting in some echo messages to check the positioning within the returned string.
LikeLike
Hello, thank you for sharing your project with so much detail. I’m kind of a newbie for raspberry/programming and homeassistant. And that’s why I’m embarrassed to make you this question. I think I was able to get/install the temper.py but I’m not being able to run Sudo commands for following your remaining steps…I tried to go trough both the Home Assistant Add-on “Terminal & SSH” and with PuTTy using root to login. I always got the same message: “sudo: command not found”. I sense the solution might be very simple, and that’s the reason of my embarrassment…Sorry for upbringing the question anyway, and thank you in advance for giving an hand to a newbie.
LikeLike
Hi Sergio,
Hey no problem asking questions.
If you’re on a Raspberry Pi with the Homeassistant image, only a subset of the Bash command set loaded, and “sudo” is not available.
When I originally wrote the blog, there was no Temper HA add-in, however since then one has been added, see: https://www.home-assistant.io/integrations/temper/
If you’re on a Pi with the generic Raspian or Debian image, you should have no problem with “sudo”. The only exception would be if you loaded a custom image for students and your user login is restricted.
I hope that this helps. Good luck. Let me know if you get stuck.
Cheers
Pete
LikeLike
Dear Pete, thank you very much for your answer during a weekend 🙂 I will follow your hints! Cheers
LikeLike