Linux USB driver for the Arexx TL-500 – Part II

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: 0x2272=8818, 0x22CC=8908, 0x45DA=17882 and 0x4806=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:

data <- read.table("tl500.csv", header=TRUE)

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.

rhdata <- data[data$Sensor %in% c("db45", "0748"),]
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:

static int get_sensor(unsigned char data[64]) {
    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:

printf("From sensor %d we get a raw value %d. We guess this means %3.2f %s. n",
       get_sensor(dataUp), get_value(dataUp), get_measurement(dataUp), get_unit(dataUp));
Found Arexx TL-500.
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…

14 thoughts on “Linux USB driver for the Arexx TL-500 – Part II

  1. Günther

    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.

    Reply
  2. Chris

    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

    Reply
  3. Gavin

    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

    Reply
  4. m68k

    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.

    Reply
  5. Sven Velt

    First: Thank you for your great work!

    “Further investigation shows us that we can calculate the measurements […] temperature sensors TL-3TSN by (Rawdata * 0.0078) °C. ”

    Well, that seems to be true for positive values – but not for negative. This night my TL-3TSN recorded a stalled raw value of “7” for about 5 hours. Other temperature sensors got a temperature of -2.0C.

    The specs of TL-3TSN tell us that they work from -30C to +80C… so there must be an other bit/byte which indicates negative temperatures. I’ll now active a dump data file in my daemon – maybe it could help finding the missing informations. 🙂

    Bye & THX again for your work so far!

    Sven

    Reply
  6. m68k

    According to http://www.arexx.com/forum/viewtopic.php?f=43&t=1060 the conversion from raw value to degrees Celsius is supposed to be T = ((short int)(raw_value)) * 0.0078125.

    The cast to a signed 16 bit int is important for handling temperatures below zero.

    Sensor type can be detected as (0xf000 & sensor_id) which gives 0x2000 for temperature and 0x4000 for humidity sensors.

    The simple logging application described at http://rndhax.blogspot.com/ has been updated with these changes.

    Reply
  7. David

    Hi

    I have recently got a TL-300 and using this code as a base I have integrated it into my monitoring system. I use a combination of hardware – 1-wire, X10, power monitoring, UPS and now Arexx.

    The code has been modded to send the values from the sensors using TCP/IP to a server process which holds all the values.

    This is then interrogated to produce web based graphs. See the website for more details. The temperature link shows 4 temperatures. Outside temp is from a 1-wire sensor, study is from the energy monitor and teh other two are the Arexx sensors.

    Reply
  8. Klaus

    If somebody experience compile errors like
    “undefined reference to `libusb_get_device_descriptor”
    on Debian (Wheezy) / Ubuntu

    try to add -lusb1-0 instead of -lusb :
    g++ -I /usr/include/libusb-1.0/ -L /lib/x86_64-linux-gnu/ -lusb-1.0 -oarexx arexx.cpp

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *