Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A hack to support TEMPer2 / TEMPerX_V3.2 / 413d:2107 #51

Open
digiboule opened this issue Dec 22, 2017 · 16 comments
Open

A hack to support TEMPer2 / TEMPerX_V3.2 / 413d:2107 #51

digiboule opened this issue Dec 22, 2017 · 16 comments

Comments

@digiboule
Copy link

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.

@digiboule digiboule changed the title TEMPer2 / TEMPerX_V3.2 / 413d:2107 A hack to support TEMPer2 / TEMPerX_V3.2 / 413d:2107 Dec 22, 2017
@torvald
Copy link

torvald commented Jan 11, 2018

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

@jmread
Copy link

jmread commented Jan 13, 2018

This hack worked for me too. Apparently I have the same device; nothing else would work for it but this. Nice, thanks.

@kenkma
Copy link

kenkma commented Jan 25, 2018

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;

@digiboule
Copy link
Author

"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

@paulrollings
Copy link

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

@openswap
Copy link

openswap commented Mar 13, 2018

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.

@Dantrej
Copy link

Dantrej commented Mar 14, 2018

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;

@garyemiller
Copy link

garyemiller commented Mar 30, 2018

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.

@robshep
Copy link

robshep commented Mar 30, 2018

@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

@robshep
Copy link

robshep commented Mar 30, 2018

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.

hughesr added a commit to hughesr/TEMPered that referenced this issue Apr 25, 2018
@apsf2
Copy link

apsf2 commented May 22, 2018

I was having issues with 413d:2107 and found that https://github.com/mreymann/temperx supports 413d:2107 beatifully.

@schniepp
Copy link

schniepp commented Jun 19, 2018

I have a TemperX232with 413d:2107, but cannot write data to it, as I just described here.

@hbt
Copy link

hbt commented Sep 28, 2018

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

@schniepp
Copy link

schniepp commented Oct 16, 2018

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

@da2x
Copy link

da2x commented Jul 30, 2019

26.33 åc55.24 å%rh1s

You need to switch to a US keyboard layout to fix this output.

@aplufr
Copy link

aplufr commented Dec 4, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests