Skip navigation

I wrote a writeup about the direct-to-Excel feature of the TEMPer devices that the KeyTemper project uses to read the measurements, and figured I’d post a link to it here in case someone’s interested.

Advertisements

Yup, I’ve started another project – which has much the same goal as tempered does (providing the ability to read the sensors), but uses a very different approach, and has different strengths and limitations.

I still intend to work on tempered as well, but I kind of expect that keytemper may end up having more users – at least once it has some of the features tempered already does – because of its easier device support.

This project is a lot newer, it’s only got a few days of work behind it (I started it a bit over a week ago, but I’ve had other things to do as well), but it’s now in a state where it gives fairly useful results, and appears to work with all the devices I have. I expect it to work with a lot of those I don’t have as well, in particular the HID variants – the serial devices are not supported (and won’t be).

The way it achieves this is by its different approach.

Instead of trying to read the sensor (more or less) directly, and then interpreting the binary result (like tempered and the official Windows program do), this program instead takes control of the keyboard interface the device exposes, triggers its direct-to-Excel feature, and then reads and interprets the keypresses the device sends.

Since the program takes control of the keyboard interface (at least per default), those keypresses are not passed on to the input system, so this program can be run in the background while you do other things, and you can run multiple instances to read more than one sensor at a time (I’ve tested with three devices simultaneously).

At the moment, the program just maps the keypresses to characters and prints them on standard output, thus kind of emulating the original feature (except limited to that window).

This approach has several advantages and disadvantages, as compared with tempered.

Chief among the advantages is that it relies on a marketed feature instead of an internal (and ever-changing) ABI, which makes it much easier to support all the HID devices that support that feature. Also, we don’t have to figure out how to turn the binary value from the device into an actual temperature/humidity value, as it’s spelled out for us in decimal.

Among the disadvantages is that we have to parse and interpret the keypresses instead of getting binary numbers that are easier to do math on and reformat, and that it’s rather cumbersome (and slow) to get just one reading – it’s easier to start the process once and then keep reading the measurements the device sends.

Another disadvantage is that this approach cannot possibly work with any devices that do not have the direct-to-Excel feature, which means that the (older) serial devices are impossible to support. Of course, at the moment, tempered doesn’t support those either, but it at least has the chance to do so in the future.

However, I expect the advantages to mostly outweigh the disadvantages, at least for most use cases that need this kind of device.

For one use case in particular, at least one of the disadvantages can be considered an advantage instead – namely the use case where you need to get measurements regularly over a long period of time, as in that case you can just start the device once, and keep the program running as a daemon to receive the measurements it sends.

(In other words, that kind of daemon should be at least as easy to make with this approach as with the approach tempered uses.)

Hi everyone,

This is just a quick note to say I’m sorry for disappearing for so long with no note or anything.

Unfortunately, life happened (as it has a tendency to), and I haven’t had much time to dedicate to this project.

I still don’t, actually, so I can’t promise anything, but I’ll try to set aside a bit – I hope to at least catch up on comments and stuff, and see if I can try to deal with the most pressing issues.

I haven’t written here in a while, but that’s mostly because I haven’t done much with the code for a while, at least not much worth writing about – recently though (about 4 days ago by now), there’s been quite a few changes, that are big enough I feel I should mention them.

First off, I realized that I’ve been conflating two things – I’ve basically been thinking of the tempered program as an example program, but at the same time wanted it to be a useful utility. These things came to a head when I started wanting to add some more complex features (well, complex for example code anyway), yet wanted to keep it simple so people could use its code as an example. I decided that my best bet would be to split it out into separate programs, one useful utility and one or more examples.

So, I’ve now done this – wrote a few examples (mostly by copy-paste) in their own subdir, and added some features to the utility (including a proper options parser).

One of the first features added was the ability to just enumerate the found devices, without reading them – which allowed me to move the enumerate program to the examples dir, and remove it from the list of programs being installed. (I never really liked the name “enumerate” for an installed program, as it’s a bit too generic.)

Next up was the ability to show temperatures in different scales than Celcius – most importantly Fahrenheit, but also Kelvin and a couple others, in a way that should be easy to extend with new scales later, as necessary.

After that came calibration – the ability to adjust the measured temperature before displaying it. I think the way this was implemented makes it both easy to use for simple cases, and flexible enough for most of the more complex ones, but admit I can’t really know yet since it hasn’t seen much use yet (that I know of). For more information about this, see the wiki, where I’ve posted some information including examples.

Both of these latter features were put into a new utility library, along with some supporting code, that the tempered program then uses – as I figured they are features likely to be wanted by other programs using libtempered as well, but do not really belong in libtempered itself. Hence, libtempered-util was born.

The dew point calculation function was also moved to this new library, as it is similarly likely to be wanted by other programs – and I’ll probably add more later, when I come up with other similar features to add.

Come to think of it, I should probably update the readme file, and maybe add some examples for the util lib… Maybe add a readme for the examples… *adds to his TODO list*

As I mentioned in an earlier post, I had ordered three new TEMPer devices to help with my project. Two of them have now arrived, while I cancelled the third (and oldest) – because they didn’t have it in stock despite what the website says, and didn’t know when they would get more of it (I suspect never, since RDing probably isn’t producing them anymore).

So, I now have two more devices, one Gold TEMPer and one Gold TEMPerHUM.

At the moment, this doesn’t help me very much to add support for more devices, though – because both of these turned out to be types that already work.

The Gold TEMPer turned out to be a repackaged TEMPerV1.2 (same hardware inside, just different casing around it) – at least that what it says it is (USB product string), and it works just fine with the existing code. Makes sense, really – why would they spend money on developing new innards when the only thing that needed changing was the container around it?

The Gold TEMPerHUM on the other hand, was a TEMPer2HumiV1.0 – which pjmoreira had already helped me to get working (again, thank you!) in the comments of the earlier post. It’s still somewhat useful to me – as it makes it easier for me to test code changes for regressions, and will allow me to experiment with it if I need to figure something out.

Also, even if nothing else, I now have more information to put into the device info database in my project’s wiki. I haven’t had time to put everything I know in there yet, but I’ll get around to it sooner or later.

As I mentioned in my post about SCons, I’ve now tried to use the CMake build system with my project.

I’m not going to say it’s perfect; it does have its own areas of awkwardness – but all in all, it went much better than my SCons experience, and didn’t really leave me disappointed. That may be in part because I didn’t have as high expectations this time, but unlike with SCons I haven’t really failed to find a decent way to do anything I needed to do yet.

In particular, setting the soname version wasn’t a problem at all, nor was having it find HIDAPI without installing it – and in a way that I believe will still find it when it is installed. It even set the rpath on the executables that use the shared libraries, making it easy to use them without having to set LD_LIBRARY_PATH – and it did so all by itself.

It also has built-in ways of generating configuration options that the user can use to reconfigure the build process – including things like where the libraries are (in case the autodetection fails) – and custom ones, like mine for building static or dynamic libraries, and which variant to link the utilities to.

This area is where most of the awkwardness is; as an example, I haven’t found any good way to have it ask the questions in a specific order, and then using the reponses to include or exclude other questions that depend on the earlier questions. There is functionality for something like that, but it asks all the questions for the default values first (even if some of those questions were disabled by earlier responses), and then reprocesses the config, asking any new questions that popped up due to the earlier answers.

However, none of this is really major, and other systems don’t even have such interactive configuration in the first place, so I don’t really consider this a significant problem.

Another piece of awkwardness is that out-of-source builds require you to change into the build directory and run cmake from there, instead of having it create and use a build directory by itself. Again, this is not a major problem; it was easily fixed by having my top-level Makefile create the build directory and run cmake in it. (I was changing that file anyway, since it wouldn’t be used by CMake, so this was not a problem.)

All in all, I’m pretty satisfied with the results, so I think I’ll go ahead and merge this into my master branch.

I’ve now merged in the new code for supporting devices with multiple sensors.

This means that we should now be able to read all the supported sensors of each device, instead of just the first sensor – so e.g. HidTEMPer2 should now give two temperature readings.

(Note that NTC sensors are not yet supported, so they will give an error message instead of a temperature value.)

Doing this properly required quite a bit of restructuring of the temper type data, and I took the opportunity to do just a bit more of that to also add better support for device subtypes.

As of now, the code assumes that most of the USB IDs used by TEMPer devices are reused by several different subtypes – instead of the earlier assumption that this was the exception – and therefore structures the data and code accordingly, into main types and subtypes.


I would be grateful if people would test whether or not it actually works with their devices now and report back with the results. I believe they should all work (except for the NTC sensors), but haven’t had a chance to test most of them.

I did have a report about a 0c45:7402 device that didn’t work, with the previous code (without multi-sensor support), but the reporter disappeared on me (didn’t respond to my questions) before I could figure out what exactly the problem was – I think it might have been a new device subtype, but it might simply have been a bug in my code too.


In other news, I’ve been moving the device support information into the project’s wiki instead of keeping it in a single DEVICES file. This allows me to include more information on each device, with links to related information, and should make it both more easily accessible and easier to update.

This process is not complete yet, so the DEVICES file is still there, but I’ll probably remove it once I’m done, to avoid confusion.

A while back, I did some trivial things with SCons in an attempt to help someone that was trying to cross-build some software that used it. I’m not sure if I actually helped any, but it involved reading a little bit about SCons, such as what it is and does.

The impression I was left with, was that SCons is a replacement for good-old Make, that does all the autotools things itself (so that it also replaces ./configure etc.) – including some advanced features like automated dependencies – with a simpler basic configuration syntax that is actually much more powerful (really being a Python script with some custom functions – not that I know much Python, but that’s not really required).

Especially the automated dependencies bit sounded really interesting to me, along with the simpler syntax. So, since I’ve been thinking about and looking at build systems recently (due to trying to get HIDAPI to build a shared library on Linux), I decided today to go ahead and try to use SCons for my own project.

This went well enough at first; I had some issues getting things to build initially, but that was obviously caused by needing it to find HIDAPI in a completely non-standard location – so I read some more documentation and figured out how to point it at the directories with the hidapi.h and libhidapi-hidraw.so files, which wasn’t really all that hard – just a couple of parameters to set in the right place.

That let me build my libraries well enough, using a globbing function to list the sources to put into them (it figured out things like -fPIC on its own) – but linking my programs failed. To fix that, I had to not only list the current directory as a library directory (so it could find my library), but also had to tell it explicitly to link against both the tempered library and the hidapi library. At this point, I figured, OK, so its automatic dependencies aren’t quite good enough to figure things out when the libs aren’t installed yet – a little disappointing, though nothing major – but one of my programs still failed to link.

This was where the first big disappointment came, as the problem was the math library – libm – which I also had to list explicitly in the list of libraries to link with. This is a bog standard system library that exists on just about all modern systems, and is very well known – so that the automatic dependencies didn’t catch it stretched my suspension of disbelief past its breaking point, leaving me with the realization that I had completely misunderstood.

Apparently, the automatic dependencies thing is only for the files within a project – meaning that a change to one of the source files makes it rebuild all the objects that depend on it, without me having to explicitly list the dependencies. I had thought it also recognized the standard inclusions and automatically added the necessary libraries to the list of libraries to link that program with.

Oh well, I kept going anyway – not like my project needs all that many libraries, and I still liked the syntax better than that of Make – and this latest addition got it to build.

But when I tried to run the resulting program (well, I ran ldd on it), it didn’t find my library. It did find the HIDAPI library, which was in the same location, which worked fine with my Make-based build. It was looking for libtempered.so instead of libtempered.so.0 … Sigh, SCons isn’t setting the soname on the shared library.

This turned out to be a somewhat worse problem, as I could find no built-in platform-independent way of setting the version for the soname, or indeed the soname itself. I did eventually get it to set the soname, by putting a linker-specific flag into the parameters it sends to the linker, but that’s rather contrary to the spirit of SCons, which is meant to have platform-independent recipies.

At this point, the SConstruct file was starting to approach the size of the Makefile, and while it might have been more platform-independent (I’m not so sure), it didn’t have all the same features (for one, it didn’t build static versions of the utilities).

All these things taken together, and some pointed out by others (like the lack of standard targets, and awkwardness with using it for installation), have lead me to conclude that, basically, my project is at once too small and too complex for SCons to be significantly better than plain Make (too small to need the automatic dependency resolution, yet wanting to build proper shared libraries), so I’m better off not adding the dependency on SCons and instead sticking with Make for now.

While this experiment wasn’t exactly a success, I wouldn’t say it was a failure, either. It didn’t result in my project actually using SCons from now on, but it did disabuse me of some misconceptions, and left me knowing more than I did previously, even if the summary is only that SCons isn’t as good or as useful as I thought.

Oh well.

The next build system I look closer at will probably be CMake, as that seems to be what signal11 wants to use for HIDAPI, and I’ve said I’ll help with that. Hopefully, it’s not as disappointing.

I just ordered three TEMPer devices from DealExtreme. Well, one TEMPer, and two variants of TEMPerHUM, one of them older than the other. They should be here in a few weeks.

I don’t really need them, other than for my project, but they’re cheap enough I figured it’s worth it to be able to test some things more easily than I can with just the one TEMPer type I have now. I’m hoping they’re all different (like they appear to be), but even if they’re not, that’s still useful information (at least for new buyers wondering which type to get).

I’m still considering getting a few more types, this time from PCSensor, since they have some types DX doesn’t (and are running a sale right now) – in particular, TEMPer2 and/or TemperNTC (well, probably the II variant due to stock) are interesting due to the multi-sensor thing and the NTC type sensor(s), to aid with implementing and testing that. (I’m still working on the multi-sensor support. I think I have most of it figured out, and just need to finish implementing it, but there might still be some details that’ll trip me up.)

While I probably wouldn’t get around to them for a while, I might want to order some of the serial devices while I’m at it (to save on shipping) – TEMPer232 for its open protocol, Net TEMPer16 just to have support for it, and the 1wire series (TEMPer1W) simply feels interesting… (I suspect the USB9097 is basically a bus bridge chip, meaning I’d have to deal with each sensor individually, and I think they might be hotpluggable…)

But then again… Buying all of those, just to add support for them, without even knowing if anyone will use that support, isn’t exactly cheap (in total)… And I tend towards being careful with spending money… But then, it’s not really that expensive… So we’ll see. (I wouldn’t mind hearing about which devices people are most interested in seeing support for, it might help me decide what to get, and what to work on next.)

Wow.

I recently got an issue report from opoplawski asking me why I was using HIDAPI instead of libhid. Turns out this question was because he was trying to package TEMPered for his distro (Fedora), and HIDAPI isn’t very well set up for such packaging, while libhid is already packaged.

This rather amazed me, and was more than a bit humbling, that someone wanted to package my little project for their distro – I mean, it’s not even 6 months old yet – so again, wow.

I didn’t really have very much I could tell him about my choice, as my memory is lousy, but as far as I remember, I picked HIDAPI simply because it was the best-looking of the HID implementations I found at the time – without looking too much at packaging.

It’s actively developed, for one thing, while libhid apparently hasn’t been updated since 2008, and is still using libusb0.1. Another thing is that libhid is GPLv2 (admittedly due to some other library they’re using) while HIDAPI is available under several licenses, one of them the BSD license, which I’m using myself for this project.

On the other hand, HIDAPI isn’t even building a shared library at this point (nor a static library, for that matter), which makes it a bit hard to package properly.

I basically ended up directing him at helping get HIDAPI into shape for packaging, which he started looking at, but he found that there’s a 3 month old pull request for adding a shared library build, which signal11 hasn’t even commented on. He added some comments (the request wasn’t perfect), but didn’t seem very hopeful about it getting merged after all this time.

I’m not sure if signal11 is even aware of what the pull request is for, honestly, as it’s not obvious from the title unless you already know what a .so file is, and they haven’t commented on it (so I don’t know if they’ve even seen it).

Since the patch is not perfect (doesn’t set the soname quite right), I’ve been considering redoing it with that fixed, and opening a new pull request, hoping signal11 will notice it and maybe even do something about it. After all, they noticed my last pull request, and even added the code from it… But on the other hand, since there’s already a pull request for this, maybe I should just comment on it there instead? I’m really not sure about the proper etiquette here.

 

Now, since it didn’t seem very likely he’d get the shared library stuff into HIDAPI,¬†opoplawski has actually been considering porting my library to use libhid instead.

I’m not really sure how to feel about that, nor about the legalities surrounding the license differences, but I think it’s feasible to do that in such a way that it’s an alternative backend implementation, only touching one or two files, instead of replacing the implementation I already have – which I *think* would allow me to keep most of this library still under the BSD license, only making it GPLv2 when built/linked with libhid. See the issue for more details on my thoughts on this.

As you may know, I’m currently doing some work on adding support for multiple sensors, and that work includes changes to these same files – so I advised him that he may want to hold off a bit on the port, at least until I’m done with this reworking, to avoid wasting effort. Of course, it’s still up to him, or whoever else wants to do it.

 

Anyway, at least one good thing has come out of this – I’ve finally gotten around to making my project build a shared library of its own.

I’m not completely sure I’ve done it quite the right way, but it seems to work for me, so I’ve also added a way to build the utilities in such a way that they use this library, instead of linking statically. Static is still the default, though, as that’s much easier to use when not installing everything to their “proper” places, which I’m not expecting most people to do yet (including myself).