TEMPered
TEMPered copied to clipboard
A hack to support TEMPer2 / TEMPerX_V3.2 / 413d:2107
I purchased this USB stick with an external sensor, and did not have any luck finding Linux drivers.
After a few hours I managed to hack a way to read the temperatures.. it's ugly, but it works and gives identical readings to the "TXT" feature controlled by caps lock and num lock.
Initially running TEMPERed gave the error "Failed to enumerate devices: (null)". lsusb shows the device has ID 413d:2107, so I opened temper_type.c and tried changing the vendor and product id for the "TEMPerV1.2 or TEMPer2V1.3" section from 0c45:7401 to 413d:2107 to see what would happen.
Then I got the error "/dev/hidraw1: Could not open device: Unknown device subtype ID: 0x04". I added a new subtype block with id = 4, based on the id = 2 section. That got TEMPered to recognize and talk to the device, however the two temperatures shown when running the "tempered" command are incorrect.
"hid-query /dev/hidraw1 0x01 0x86 0xff 0x01 0x00 0x00 0x00 0x00" returns hex values for the string: "TEMPerX_V3.2 "
Similar to what was noted in the description of a different device, a single query results in two responses:
"hid-query /dev/hidraw1 0x01 0x80 0x33 0x01 0x00 0x00 0x00 0x00" returns:: Response from device (8 bytes): 80 80 09 98 4e 20 00 00 Response from device (8 bytes): 80 01 07 c9 4e 20 00 00
Here the internal temperture is represented by "09 98", and the external temperature by "07 c9". Below is the C code to convert these to the actual values in degrees celsius:
unsigned char high_byte = data[2]; unsigned char high_byte = data[3]; int temp = (high_byte <<8) + low_byte; float tempC = (float)temp / 100.0;
I was unable to devise a simple way to make TEMPer handle the two responses properly under its existing framework, so instead I quickly hacked the hid-query.c utility to decode and display the temperatures on its own.
Hi, and thanks for your hack.
To elaborate on my case. I bought this this, also having the rather unknown vendor- and product id 413d:2107
.
./hid-query /dev/hidraw4 0x01 0x86 0xff 0x01 0x00 0x00 0x00 0x00
reports «TEMPerX_V3.1 »
./hid-query /dev/hidraw4 0x01 0x80 0x33 0x01 0x00 0x00 0x00 0x00
gives me 80 40 0a 12 0f 31 00 00
where 0a 12
seems to be temperature and 0f 31
the humidity sensor. With your code (and -3 calibration) i get nice temperature readings (14°C - 40°C) - but the TEMPered's fm75.c oddly gives me 10°C, when there is ~23°C in the room. I have so fare not been able to figure out what would be the correct way to read the humidity sensor. Similar devices uses the sht1x method, but this gives me readings from 80-100% which are far off.
When i press the little button on the thingy it pastes to by computer (as a HID):
caps lockØon-off-`
num lockØoff-on-++
typeØinner-h2
inner-tempinner-huminterval
26.33 åc55.24 å%rh1s
26.33 åc55.61 å%rh1s
26.38 åc55.73 å%rh1s
26.38 åc55.85 å%rh1s
....
I also opened the sensor to see if their where indication of what sensor it used but all that was imprinted on the card was «TEMPerX_P5» and the date «20170901».
This hack worked for me too. Apparently I have the same device; nothing else would work for it but this. Nice, thanks.
I have a temper2 with the ID 413d:2107. The hack works for me when using the command "hid-query /dev/hidraw1 0x01 0x80 0x33 0x01 0x00 0x00 0x00 0x00" to read back the raw data in bytes.
However, when applying the hack so TEMPERed gives back the right data in Celsius I get the internal sensor data repeated twice, ie. no external data!
Here is what I have done.
- change vendor and product id's in temper_type.c
{
.name="TEMPerV1.2 or TEMPer2V1.3",
.vendor_id=0x413d,
.product_id=0x2107,
.interface_number=1,
.open = tempered_type_hid_open,
.close = tempered_type_hid_close,
.get_subtype_id = tempered_type_hid_get_subtype_id,
.get_subtype_data = &(struct tempered_type_hid_subtype_data){
.id_offset = 1,
.query = {
.length = 9,
.data = (unsigned char[]){ 0, 1, 0x82, 0x77, 1, 0, 0, 0, 0 }
}
// Technically I think offset 1 says how many bytes of data follow,
// but it is 1 for TEMPer and 2 for TEMPer2, so it's usable as ID.
// TODO: we may want to use the 82 FF query for initialization.
},
- add a sub block to temper_type.c based on the id = 2 block but with an id = 4 and correct the high and low byte offsets for the 2nd sensor.
(struct temper_subtype*)&(struct temper_subtype_hid){
.base = {
.id = 4,
.name = "TEMPer2V1.3",
.open = tempered_type_hid_subtype_open,
.read_sensors = tempered_type_hid_read_sensors,
.get_sensor_count = tempered_type_hid_get_sensor_count,
.get_temperature = tempered_type_hid_get_temperature,
},
.sensor_group_count = 1,
.sensor_groups = (struct tempered_type_hid_sensor_group[]){
{
.query = {
.length = 9,
.data = (unsigned char[]){ 0, 1, 0x80, 0x33, 1, 0, 0, 0, 0 }
},
.read_sensors = tempered_type_hid_read_sensor_group,
.sensor_count = 2,
.sensors = (struct tempered_type_hid_sensor[]){
{
.get_temperature = tempered_type_hid_get_temperature_fm75,
.temperature_high_byte_offset = 2,
.temperature_low_byte_offset = 3
},
{
.get_temperature = tempered_type_hid_get_temperature_fm75,
.temperature_high_byte_offset = 2,
.temperature_low_byte_offset = 3
}
}
}
}
},
- changed fm75.c calculations to:
*tempC = temp / 100.0;
"However, when applying the hack so TEMPERed gives back the right data in Celsius I get the internal sensor data repeated twice, ie. no external data!"
As a possible clue, in my case the device sends two responses instead of one (yes, not a double-length response, but two responses). I couldn't figure out a straightforward way to modify the TEMPered framework to accomodate this strange case, which is why I hacked hid-query instead. Perhaps your humidity issue is similar?
I'm attaching a copy of my hacked utils/hid-query.c and libtempered/temper_type.c. hack.tar.gz
I also get data repeated twice (also the temp is wrong).
0001:0007:01 0: temperature 9.20 °C
0001:0007:01 1: temperature 9.20 °C
What I am not sure about is that
./hid-query /dev/hidraw0 0x01 0x80 0x33 0x01 00 00 00 0x00
returns
Device not found: /dev/hidraw0
and yet .....
sudo ./read-all
returns
Device 0001:0007:01 : USB IDs 413d:2107, interface 1
Enumeration type name: TEMPerV1.2 or TEMPer2V1.3
Open succeeded.
Device path: 0001:0007:01
Device type name: TEMPer2V1.3
Sensor count: 2
Sensor 0:
Temperature: 8.64°C
Sensor 1:
Temperature: 8.64°
Any pointers in general direction to fix the temp reading, also to be able to read the humidity would be greatly appreciated
If you wanna stop seeing two sensors in the response try this:
(struct temper_subtype*)&(struct temper_subtype_hid){
.base = {
.id = 4,
.name = "TEMPer2V1.3",
.open = tempered_type_hid_subtype_open,
.read_sensors = tempered_type_hid_read_sensors,
.get_sensor_count = tempered_type_hid_get_sensor_count,
.get_temperature = tempered_type_hid_get_temperature,
},
.sensor_group_count = 1,
.sensor_groups = (struct tempered_type_hid_sensor_group[]){
{
.query = {
.length = 9,
.data = (unsigned char[]){ 0, 1, 0x80, 0x33, 1, 0, 0, 0, 0 }
},
.read_sensors = tempered_type_hid_read_sensor_group,
.sensor_count = 1,
.sensors = (struct tempered_type_hid_sensor[]){
{
.get_temperature = tempered_type_hid_get_temperature_fm75,
.temperature_high_byte_offset = 2,
.temperature_low_byte_offset = 3
}
}
}
}
},
That's a modification on the snipped @kenkma shared.
First, thanks all for your previous posts. I managed to read both temperatures from a USB TEMPerX_V3.2. I also tried some changes to function tempered_type_hid_query in common.c to read multiple answers resulting from a query. Here's a snipset (might not be good buffer management) :
size = hid_read_timeout(
hid_dev, result->data, sizeof( result->data ), 1000
);
if ( size < 0 )
{
size = snprintf(
NULL, 0, "Read of data from the sensor failed: %ls",
hid_error( hid_dev )
);
// TODO: check that size >= 0
size++;
char *error = malloc( size );
size = snprintf(
error, size, "Read of data from the sensor failed: %ls",
hid_error( hid_dev )
);
tempered_set_error( device, error );
result->length = 0;
return false;
}
else if ( size == 0 )
{
tempered_set_error(
device, strdup( "No data was read from the sensor (timeout)." )
);
return false;
}
else
{
result->length = 0;
while (size > 0)
{
result->length += size;
size = hid_read_timeout(
hid_dev, &result->data[result->length], sizeof( result->data - result->length), 200
);
}
if (size > 0)
{
result->length += size;
}
}
return true;
Then, update temper_type.c to use the correct offset :
.sensors = (struct tempered_type_hid_sensor[]){
{
.get_temperature = tempered_type_hid_get_temperature_fm75,
.temperature_high_byte_offset = 2,
.temperature_low_byte_offset = 3
},
{
.get_temperature = tempered_type_hid_get_temperature_fm75,
.temperature_high_byte_offset = 10,
.temperature_low_byte_offset = 11
}
}
And finally in tempered_type_hid_get_temperature_fm75 :
*tempC = temp / 100.0;
Thanks guys! I have one of these that reports as "TEMPerGold_V3.1". It has a simple temp sensor and no button. With the patch above it works fine.
@garyemiller please could you share your patched source bundle?
I'm unable to apply the above patches in the right way to get it to build
I'm not sure what has gone wrong with my patching but these are my results for a TEMPerX_V3.2
$ sudo ./TEMPered/build/utils/tempered
/dev/hidraw4 0: temperature 25.87 °C
/dev/hidraw4 1: temperature 25.87 °C
but
$ sudo ./TEMPered/build/utils/hid-query /dev/hidraw4 0x01 0x80 0x33 0x01 0x00 0x00 0x00 0x00
Sensor 1: 25.87 C = 78.57 F
Sensor 2: 18.62 C = 65.52 F
The latter works fine and can be crudely parsed so i'm happy with that.
I was having issues with 413d:2107 and found that https://github.com/mreymann/temperx supports 413d:2107 beatifully.
I have a TemperX232with 413d:2107, but cannot write data to it, as I just described here.
I dockerfied the project in https://github.com/hbt/TEMPered so you only need to type docker-compose run tempered
to build and get the temperature
Tested with 413d:2107 only
This totally fixed my problems: urwen/temper. It's a pure python3 program that makes my device work. The author also describes in the README.md that the access via hidraw does not work and gives errors. Brilliant! I can use my device now!!! The author also has listed a table with different devices.
What brought me on this track: the Firmware version using the Windows software reads as "TEMPerX232_V2.0".
26.33 åc55.24 å%rh1s
You need to switch to a US keyboard layout to fix this output.
Hi guys, In case some prefer the C version, I've grabbed and mixed patches from various github and added some code. The version is available here: https://gitlab.com/mulx/TEMPered/ it support reading both temperature and humidity. I've include also as submobule the link to python version.