/temper-python

libusb/PyUSB-based driver to read TEMPer USB HID devices (USB ID 0c45:7401) and serve as a NetSNMP passpersist module

Primary LanguagePythonOtherNOASSERTION

This is a rewrite of a userspace USB driver for TEMPer devices presenting a USB ID like this: 0c45:7401 Microdia My device came from M-Ware ID7747 and also reports itself as 'RDing TEMPerV1.2'.

Also provides a passpersist-module for NetSNMP (as found in the snmpd packages of Debian and Ubuntu) to present the temperature of 1-3 USB devices via SNMP.

Requirements

Basically, libusb bindings for python (PyUSB) and snmp-passpersist from PyPI.

Under Debian/Ubuntu, treat yourself to some package goodness:

sudo apt-get install python-usb python-setuptools snmpd # The latter is only necessary for SNMP-usage.
sudo easy_install snmp-passpersist

Usage

To print temperatures of all sensors found in the system, just run

python temper/temper.py

If your udev installation does not provide access as a normal user to the USB device, you need to run it as root:

sudo python temper/temper.py

Installation

After you run

sudo python setup.py install

you should end up with two scripts conveniently installed:

/usr/local/bin/temper-poll
/usr/local/bin/temper-snmp

Serving via SNMP

Using NetSNMP, you can use temper/snmp.py as a pass_persist module. You can choose one of two OIDs to be emulated: APC's typical internal/battery temperature (.1.3.6.1.4.1.318.1.1.1.2.2.2.0) or Cisco's typical temperature OIDs (.1.3.6.1.4.1.9.9.13.1.3.1.3.1 - 3.3).

Note that you should not activate both modes at the same time. The reason for this limitation is that the script will keep running for each pass_persist entry and they will interfere with each other when updating the temperature. This typically leads to syslog entries like this:

temper-python: Exception while updating data: could not release intf 1: Invalid argument

USB device permissions

At least on Debian Wheezy, the default USB device node has permissions to only allow access for root. In the same case, snmpd is running as the user snmpd. Bam. No access. You might find a corresponding note in syslog.

To solve that, the file 99-tempsensor.rules is a udev rule that allows access to the specific USB devices (with matching VID/PID) by anyone. Install like this:

sudo cp etc/99-tempsensor.rules /etc/udev/rules.d/

To check for success, find the bus and device IDs of the devices like this:

pi@raspi-temper1 ~ $ lsusb | grep "0c45:7401"
Bus 001 Device 004: ID 0c45:7401 Microdia 
Bus 001 Device 005: ID 0c45:7401 Microdia 

pi@raspi-temper1 ~ $ ls -l /dev/usb*
crw------- 1 root root 189, 0 Jan  1  1970 /dev/usbdev1.1
crw------- 1 root root 189, 1 Jan  1  1970 /dev/usbdev1.2
crw------- 1 root root 189, 2 Jan  1  1970 /dev/usbdev1.3
crw-rw-rwT 1 root root 189, 3 Jan  1  1970 /dev/usbdev1.4
crw-rw-rwT 1 root root 189, 4 Jan  1  1970 /dev/usbdev1.5
pi@raspi-temper1 ~ $ 

Note that /dev/usbdev1.4 and /dev/usbdev1.5 have permissions for read/write for anyone, including snmp. This will work for the passpersist-module running along with snmpd.

What to add to snmpd.conf

To emulate an APC Battery/Internal temperature value, add something like this to snmpd.conf. The highest of all measured temperatures in degrees celcius as an integer is reported.

pass_persist    .1.3.6.1.4.1.318.1.1.1.2.2.2 /usr/local/bin/temper-snmp

Alternatively, emulate a Cisco device's temperature information with the following. The first three detected devices will be reported as ..13.1.3.1.3.1, ..3.2 and ..3.3 . The value is the temperature in degree celcius as an integer.

pass_persist    .1.3.6.1.4.1.9.9.13.1.3 /usr/local/bin/temper-snmp

Add --testmode to the line (as an option to snmp.py to enable a mode where APC reports 99°C and Cisco OIDs report 97, 98 and 99°C respectively. No actual devices need to be installed but libusb and its Python bindings are still required.

The path /usr/local/bin/ is correct if the installation using python setup.py install did install the scripts there. If you prefer not to install them, find and use the temper/snmp.py file.

Troubleshooting NetSNMP-interaction

The error reporting of NetSNMP is underwhelming to say the least. Expect every error to fail silently without a chance to find the source.

snmp.py reports some simple information to syslog with an ident string of temper-python and a facility of LOG_DAEMON. So this should give you the available debug information:

sudo tail -f /var/log/syslog | grep temper-python

Try stopping the snmpd daemon and starting it with logging to the console:

sudo service snmpd stop
sudo snmpd -f

It will not start the passpersist-process for snmp.py immediately but on the first request for the activated OIDs. This also means that the first snmpget you try may fail like this:

iso.3.6.1.4.1.9.9.13.1.3.1.3.2 = No Such Instance currently exists at this OID

To test the reporting, try this (twice if it first reports No Such Instance):

snmpget -c public -v 2c localhost .1.3.6.1.4.1.9.9.13.1.3.1.3.1 # Cisco #1
snmpget -c public -v 2c localhost .1.3.6.1.4.1.9.9.13.1.3.1.3.2 # Cisco #2
snmpget -c public -v 2c localhost .1.3.6.1.4.1.9.9.13.1.3.1.3.3 # Cisco #3
snmpget -c public -v 2c localhost .1.3.6.1.4.1.318.1.1.1.2.2.2.0 # APC

When NetSNMP starts the instance (upon first snmpget), you should see something like this in syslog:

Jan  6 16:01:51 raspi-temper1 temper-python: Found 2 thermometer devices.
Jan  6 16:01:51 raspi-temper1 temper-python: Initial temperature of device #0: 22.2 degree celsius
Jan  6 16:01:51 raspi-temper1 temper-python: Initial temperature of device #1: 10.9 degree celsius

If you don't even see this, maybe the script has a problem and quits with an exception. Try running it manually and mimik a passpersist-request (-> means you should enter the rest of the line):

-> sudo temper/snmp.py 
-> PING
<- PONG
-> get
-> .1.3.6.1.4.1.318.1.1.1.2.2.2.0
<- .1.3.6.1.4.1.318.1.1.1.2.2.2.0
<- INTEGER
<- 22.25

If you have a problem with the USB side and want to test SNMP, run the script with --testmode.

Note on multiple device usage

The devices I have seen do not have any way to identify them. The serial number is 0. There is no way (and this driver does not make any attempt) to present a persistent ordering among the USB devices. The effective order is the one that libusb presents. That seems to be based on the enumeration order of the devices.

That in turn seems to be based primarily on the physical ordering in the root hub -> hub port hierarchy on bootup. But if you unplug and replug the device (or it gets detached due to a glitch and is redetected) then the order of the devices may be changed.

If that happens, your temperature readings will change and you cannot say which device belongs to what OID if you are using SNMP.

Long story short: Only use the device order if the USB bus is stable and you reboot after any plugging on the device. Even then, you are not safe. Sorry.

Origins

The USB interaction pattern is extracted from here as seen on Google+.

Authors