Skip to content


Java interface to Tellstick in Snow Leopard

The Tellstick from Telldus is a small little USB dongle that lets you communicate with remote receivers such as wireless power outlets. Even though the Telldus company release their own software for controlling the Tellstick they are really open with their product and lets users access the Tellstick pretty much any way they want.

When interfacing the Tellstick in Java on Mac OS X there is at least three ways of doing this:

1. RXTXcomm, this way you access the device directly. You’ll need to download Virtual COM Port drivers. On the downside you’ll have to implement support for the different receiver protocols on your own.
2. JNI bindings, using Telldus tellstick library. The bindings are very old and haven’t kept up with the development of the Telldus tellstick library.
3. JNA, using Telldus tellstick library but without the need for the JNI bindings.

This post will focus on the third alternative. When using Telldus own library (TelldusCore) you don’t have to deal with the different kinds of protocols used by the receivers. You’ll automatically have access to every protocol supported by Telldus.

As of writing this post, the current Telldus Center 2 release does only come with a 32-bit version of the TelldusCore library. If you’re running a 32-bit version of Java you only have to download and install Telldus Center 2 to get the TelldusCore library. But if you’re like me, running a 64-bit version of Java you need to recompile TelldusCore.

$ java -version
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248-10M3025)
Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode)

Now Download TelldusCore 2.0.2.

In order to compile TelldusCore 2.0.2 you’ll also need:

  • cmake – used to configure the sources.
  • D2XX Direct Drivers – download the latest version (currently 0.1.7). Read the readme file on how to install it properly. It’s fairly simple, especially if you have som terminal knowledge. Be sure to copy from the bin/10.6 directory which contains a 64-bit version of the library.

Untar the TelldusCore sources and (inside telldus-core-2.0.2) run

$ cmake -DBUILD_RFCMD=0 -DSUPPORT_USB=1 -DFTD2XX_LIBRARY=/usr/local/lib/libftd2xx.dylib

This will configure the sources for building TelldusCore without rfcmd. Make sure that FTD2XX_LIBRARY actually points to the library that you copied when installing the D2XX Direct Drivers.

Anyway, your output should look something like this:

$ cmake -DBUILD_RFCMD=0 -DSUPPORT_USB=1 -DFTD2XX_LIBRARY=/usr/local/lib/libftd2xx.dylib
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Checking whether C compiler has -isysroot
-- Checking whether C compiler has -isysroot - yes
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Checking whether CXX compiler has -isysroot
-- Checking whether CXX compiler has -isysroot - yes
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Looking for Q_WS_X11
-- Looking for Q_WS_X11 - not found.
-- Looking for Q_WS_WIN
-- Looking for Q_WS_WIN - not found.
-- Looking for Q_WS_QWS
-- Looking for Q_WS_QWS - not found.
-- Looking for Q_WS_MAC
-- Looking for Q_WS_MAC - found
-- Looking for QT_MAC_USE_COCOA
-- Looking for QT_MAC_USE_COCOA - found
-- Found Qt-Version 4.6.1 (using /usr/bin/qmake)
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/pakerfeldt/telldus-core-2.0.2

Now build TelldusCore by running make:

$ make
Scanning dependencies of target TelldusCore
[  5%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/Device.cpp.o
[ 10%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceBrateck.cpp.o
[ 15%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceEverflourish.cpp.o
[ 21%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceGroup.cpp.o
[ 26%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceIkea.cpp.o
[ 31%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceNexa.cpp.o
[ 36%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceRisingSun.cpp.o
[ 42%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceSartano.cpp.o
[ 47%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceUndefined.cpp.o
[ 52%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceUpm.cpp.o
[ 57%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceWaveman.cpp.o
[ 63%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/DeviceX10.cpp.o
[ 68%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/Controller.cpp.o
[ 73%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/Manager.cpp.o
[ 78%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/Settings.cpp.o
[ 84%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/telldus-core.cpp.o
[ 89%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/SettingsCoreFoundationPreferences.cpp.o
[ 94%] Building CXX object driver/libtelldus-core/CMakeFiles/TelldusCore.dir/win/Device.cpp.o
Linking CXX shared library TelldusCore.framework/Versions/2.0.2/TelldusCore
Copying OS X content driver/libtelldus-core/TelldusCore.framework/Versions/2.0.2/Headers/telldus-core.h
[ 94%] Built target TelldusCore
Scanning dependencies of target tdtool
[100%] Building CXX object tdtool/CMakeFiles/tdtool.dir/main.cpp.o
Linking CXX executable tdtool
[100%] Built target tdtool

The result is placed in telldus-core-2.0.2/driver/libtelldus-core/TelldusCore.framework/.

Create the directory /Library/Frameworks/TelldusCore.framework/Versions/2.0.2/

$ mkdir -p /Library/Frameworks/TelldusCore.framework/Versions/2.0.2/

And copy the result to this directory:

$ cp -Rp driver/libtelldus-core/TelldusCore.framework/* /Library/Frameworks/TelldusCore.framework/Versions/2.0.2/

Also, add a symbolic link named libTelldusCore.dylib in that directory:

$ ln -s /Library/Frameworks/TelldusCore.framework/Versions/2.0.2/TelldusCore /Library/Frameworks/TelldusCore.framework/Versions/2.0.2/libTelldusCore.dylib

You should now be able to access you’re newly built 64-bit TelldusCore using JNA. This is actually quite easy. A JNA binding to TelldusCore could look something like this:

package se.akerfeldt.code.tellstick;

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface TellstickBinding extends Library {

	TellstickBinding INSTANCE = (TellstickBinding) Native.loadLibrary(("TelldusCore"), TellstickBinding.class);

	int tdAddDevice();
	int tdTurnOn(int intDeviceId);
	int tdTurnOff(int intDeviceId);
	int tdGetNumberOfDevices();
	int tdGetDeviceId(int deviceIndex);
	boolean tdSetName(int deviceId, String name);
	String tdGetName(int deviceId);
	boolean tdSetProtocol(int deviceId, String protocol);
	String tdGetProtocol(int deviceId);
	boolean tdSetModel(int deviceId, String model);
	String tdGetModel(int deviceId);
	boolean tdSetDeviceParameter(int deviceId, String name, String value);
	String tdGetDeviceParameter(int deviceId, String name, String defaultValue);
	String tdGetErrorString(int errorNo);
}

Please refer to telldus-core.h for a complete list of native methods. I haven’t paid much attention to the Java class above.

Now, before running your application add -Djna.library.path=/Library/Frameworks/TelldusCore.framework/Versions/2.0.2 to your VM arguments.

In order to turn something on/off you’ll have to add a device for it, just use the JNA binding for that!

int deviceId = TellstickBinding.INSTANCE.tdAddDevice();
TellstickBinding.INSTANCE.tdSetName(deviceId, "Outdoor light");
TellstickBinding.INSTANCE.tdSetProtocol(deviceId, "arctech");
TellstickBinding.INSTANCE.tdSetModel(deviceId, "codeswitch");
TellstickBinding.INSTANCE.tdSetDeviceParameter(deviceId, "house", "A");
TellstickBinding.INSTANCE.tdSetDeviceParameter(deviceId, "unit", "1");

TellstickBinding.INSTANCE.tdTurnOn(deviceId);

I’m still looking for a better source of information regarding the different kinds of protocols and models. In the meantime this Telldus wiki page might give some more information for you.

Share post:
  • Twitter
  • Google Bookmarks
  • Slashdot
  • Facebook
  • Digg

Posted in Article.

Tagged with , , , , , , .

  • Micke
    Great guide. One thing though. The last step where you add a device is unnecessary if you run TelldusCenter. You can configure your devices though there.
  • Both TelldusCenter and the Java interface uses the same configuration file, although looking closely, they don't define the keys the same way.

    The Java interfaces uses format like this:
    device.1.name

    And TelldusCenter uses the following format:
    devices.1.name

    Note the difference between device and devices. Why is that, Micke? Is this a difference between the TelldusCore version? 2.0.2 is used by the Java interface and 2.0.0 by TelldusCenter.
  • Micke
    Yes that is unfortunately correct. This is because the different backends. The non-qt is very old and not updated since 1.x. This is why the behavior differs slightly. The non-qt backend should be updated and maybe not be the default-one on OSX?
  • Sorry, you were right. I had to invoke tdAddDevice() to store it!

    Micke, could you please explain when and how tdAddDevice() is supposed to be called? It doesn't take any arguments at all which might feel a bit strange.
  • Micke
    tdAddDevice() should be called first. It returnes the newly created id which can be used to tdSetName() and the other functions.
  • Telldus Center seems to store its configuration under /Users/[username]/Library/Preferences/com.telldus.Core.plist
    But that's not the file used when running through the Java interface. I haven't yet located that configuration file though.
    So, for some reason they don't seem to share the same configuration file. Which is kind of sad as it would be neat to use TelldusCenter to manage the configuration.
  • Micke
    This is probably because your compiled TelldusCore uses another settings-backend than the official build. There is a switch in cmake called USE_QT_SETTINGS_BACKEND which is set to OFF as default. The one shipped in our dmg uses the QT-one since we already have the qt-dependency.

    Note that this might change for 2.1 so do not depend on where the file is stored!
blog comments powered by Disqus