TEMPer USB Temperature Sensor

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.

9 thoughts on “TEMPer USB Temperature Sensor

  1. 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

    Like

  2. 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…

    Like

    1. 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)}”

      Like

  3. 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

    Like

    1. 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.

      Like

    2. 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

      Like

Leave a Reply to Pete Metcalfe Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s