Last time we started communicating with the TL-500. This time we want to find out the meaning of the data rows from the IN endpoint.
Therefore we start the USB Sniffer SnoopyPro again and observe the data flow under Windows while the logger is working. We then export the USB log as XML and grep for “000a”. Now we can compare the raw data from the USB device with the recorded measurements. The first surprising thing is that in some cases SnoopyPro seems to miss some incoming data events (ca. 5% of the total events). (The other possibility is that the Windows software is interpolating data points when you export them – but I disbelieve this, since this would be rather stupid, wouldn’t it?)
By only using one sensor at a time one is able to distinguish the data for each sensor. I have the following sensors and the respective data has the following values as hexadecimal digits in the 5th-8th position:
| 8818: | 72 22 |
| 8908: | cc 22 |
| 17882: | da 45 |
| 17882RH: | db 45 |
| 18438: | 06 48 |
| 18438RH: | 07 48 |
After changing the order of the two halfs, the temperature sensors translate directly: 0×2272=8818, 0x22CC=8908, 0x45DA=17882 and 0×4806=18438. Also if the last bit of the first half is 0, we have a RH sensor, otherwise a temperature sensor. This would imply that all sensors have even numbers. RH sensors would have the same id incremented by 1. Is this always the case?
Just by looking at the raw data rows and exposing the sensors to different conditions, I suspect the 9-14 hexadecimal digits to contain the temperature and RH data.
Let’s look at a sample data set: tl500.csv. We load it into R and start investigating:
hex2int <- Vectorize(function(x) {
v <- 0
for (i in 1:nchar(x)) {
w <- ifelse(substr(x,i,i)==c(as.character(0:9), letters[1:6]), 0:15, NA)
w <- ifelse(!all(is.na(w)), w <- w[!is.na(w)], NA)
v <- v + w*16**(nchar(x)-i)
}
return(v)
})
data$Sensor <- substr(data$Rawdata,5,8)
data$RawValue <- hex2int(substr(data$Rawdata,9,12))
plot(data$RawValue, data$Value)

There are obviously subgroups and in these groups a linear relationship exists between the 5th and 6th byte (9-12 hexadecimal digits) of the raw data and the measurements. Adding the 7th byte does not improve the linear correlation. (Weee! No floating point data!) Further investigation shows us that we can calculate the measurements from RH sensors by (0.6 + Rawdata * 0.03328) RH%, from temperature sensors TSN-TH70E by (-39.58 + Rawdata * 0.01) °C and from temperature sensors TL-3TSN by (Rawdata * 0.0078) °C. These coefficients are based on the the following linear regressions. With more data they will slightly change, but given the accuracy and that you need to calibrate your sensors either way, it’s a sufficient translation of uncalibrated sensor data.
t1data <- data[data$Sensor %in% c("da45", "0648"),]
t2data <- data[data$Sensor %in% c("7222", "cc22"),]
lm(Value~RawValue,data=rhdata)
lm(Value~RawValue,data=t1data)
lm(Value~RawValue,data=t2data)
Let’s update the C program from the last time with the new results:
return (data[3])*(256)+(data[2]);
}
static int get_value(unsigned char data[64]) {
int value = 0;
// We use a loop since it is not clear whether we want to use also data[6] someday.
for (int i=4; i<=5; i++) {
value += data[i]*pow(16,2*(5-i));
}
return value;
}
/**
* We assume that all TSN-TH70E sensors have ids bigger than 10000.
* If the id is then odd we have a humidity sensor.
* Has anyone more information about this?
*/
static double get_measurement(unsigned char data[64]) {
double value = get_value(data);
int sensor = get_sensor(data);
if (sensor < 10000) {
return value * 0.0078;
} else {
if (sensor%2==0) {
return -39.58 + value * 0.01;
} else {
return 0.6 + value * 0.03328;
}
}
}
/**
* We assume that all TSN-TH70E sensors have ids bigger than 10000.
* If the id is then odd we have a humidity sensor.
* Has anyone more information about this?
*/
const char* get_unit(unsigned char data[64]) {
int sensor = get_sensor(data);
if (sensor > 10000 && sensor%2!=0) {
return "%RH";
} else {
return "°C";
}
}
If we now add the following line into the data reading loop we get a usefull result:
get_sensor(dataUp), get_value(dataUp), get_measurement(dataUp), get_unit(dataUp));
Data: 00 0a 72 22 0c 17 05 00 00 00 15 00 ff 04 ed 1e 06 00 00 00 ff ff ff ff ff ff ff ff ff ff ff 0b ff af 05 00 00 09 07 48 04 ec c9 05 00 00 09 72 22 0b ff df 05 00 00 00 06 48 48 ed 31 2e 3f 09
From sensor 8818 we get a raw value 3095. We guess this means 24.14 °C.
Data: 00 0a 07 48 04 f5 17 00 00 00 06 00 ff 04 ed 1e 06 00 00 00 ff ff ff ff ff ff ff ff ff ff ff 0b ff af 05 00 00 09 07 48 04 ec c9 05 00 00 09 72 22 0b ff df 05 00 00 00 06 48 48 ed 31 2e 3f 09
From sensor 18439 we get a raw value 1269. We guess this means 42.83 %RH.
Data: 00 0a 72 22 0c 0f 39 00 00 00 0c 00 ff 04 ed 1e 06 00 00 00 ff ff ff ff ff ff ff ff ff ff ff 0b ff af 05 00 00 09 07 48 04 ec c9 05 00 00 09 72 22 0b ff df 05 00 00 00 06 48 48 ed 31 2e 3f 09
From sensor 8818 we get a raw value 3087. We guess this means 24.08 °C.
Data: 00 0a 06 48 18 dd 51 00 00 00 06 00 ff 04 ed 1e 06 00 00 00 ff ff ff ff ff ff ff ff ff ff ff 0b ff af 05 00 00 09 07 48 04 ec c9 05 00 00 09 72 22 0b ff df 05 00 00 00 06 48 48 ed 31 2e 3f 09
From sensor 18438 we get a raw value 6365. We guess this means 24.07 °C.
You can download the updated C file here. Now we can create our first applications for Linux.
P.S.: The connection quality is in the 21th and 22th hexadecimal digits and further blog posts will follow…
Hi Kornelius,
thanks for publishing your work. I just read your posts and your information will help me to write my own program. I checked the numbers of my sensors and it appears that one of my temperature sensors (8735) is odd numbered. All of my temperature/humidity sensors are even numbered.
I will keep you updated on the progress of my work.
Thanks again!
Günther.
Hi Kornelius,
many thanks for your great work!
This will help a lot to develop a linux driver for the Arexx system.
…and for sure we will be much faster than the people from Arexx (which-I think-I can promise easily).
Thanks again!!!
Chris
Hi;
First off , thanks for all your hard work. I’ve been looking for a low cost remote temperature recording system for linux for some time and with your work this might just be it!
Does anyone know if the slightly cheaper TL-300 version without the built in datalogger would also work with this driver?
Cheers
Gavin
Hi Galvin,
the ID will of course be different, but I bet the protocol will be similar. But no guarantee.
Cheers, Kornel.
Hi Kornelius,
many thanks for your Work.
Stefan
Hi Kornelius,
I just received two TL-3TSN revision 059 sensors with ID 11600 and 11639 respectively, as well as a waterproof TSN-33MN with ID 11807.
This would mean that both assumptions regarding ID numbers are incorrect.
TSN-33MN seems to use the same 0.0078 calibration factor as TL-3TSN.
Example of a temperature logging application based on Kornelius work:
http://rndhax.blogspot.com/2010/03/friendlyarm-mini2440-arexx-tl-500.html