This page will show how you can use a Tellstick USB adapter with VSCP. The instruction should work well on all Linux boxes including Raspberry Pi and Beaglebone. Credits to this Swedish page. from which most of the information is fetched from.
Only version 2.1.1 appears to work with olders sticks.
Two general setup instruction are here http://forum.telldus.com/viewtopic.php?f=15&t=4366 and here http://raspberry.arctics.se/2015/05/03/uppdaterad-artikel-om-tellstick-pa-raspberry-pi
Install the ftdi libraries.
sudo apt-get install libftdi1 libftdi-dev
may already be installed on some machines.
Install som elibs used by the Tellstick software
sudo apt-get install libconfuse0 libconfuse-dev
Check if your Tellstick has been found by the OS with
lsusb
if you see a line that looks like
Bus 001 Device 004: ID 1781:0c30 Multiple Vendors Telldus TellStick
the adapter is found and everything is OK
Now load the kernel module with
sudo modprobe ftdi_sio vendor=0x1781 product=0x0c30
check that it has been loaded with
lsmod | grep ftdi
you should see a line
usbserial 27365 1 ftdi_sio
if it is loaded. To have the driver start automagically when you restart the system add
ftdi_sio vendor=0x1781 product=0x0c30
into /etc/modules
The Tellstick software needs cmake so install it
sudo apt-get install cmake
and fetch the Tellstick software
wget http://download.telldus.se/TellStick/Software/telldus-core/telldus-core-2.1.1.tar.gz
You can check here to see if any later version is available. If it is use that version instead.
Unpack it
tar xfz telldus-core-2.1.1.tar.gz
Go into the folder
cd telldus-core-2.1.1
generate makefiles
cmake .
then run
make
if all goes well and you don't see any error messages install the software with
sudo make install
on a Linux box issue
sudo ldconfig
to configure installed libraries.
On mu Debian system I got the error
/root/telldus-core-2.1.1/common/Socket_unix.cpp:44:18: error: ‘close’ was not declared in this scope
when I built the package. I solved this by adding
#include <unistd.h>
to the
common/Socket_unix.cpp
file as of below
#include <stdio.h> #include <sys/socket.h> #include <unistd.h> #include <sys/un.h> #include <math.h>
Now create a startup script /etc/init.d/telldusd with the following content
#! /bin/sh ### BEGIN INIT INFO # Provides: telldusd # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Tellstick service daemon # Description: Tellstick service daemon controlling remove switches ### END INIT INFO # Author: Kjell Haveskold (nimmis) <kjell.havneskold@gmail.com> # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin DESC="Tellstick service daemon" NAME=telldusd DAEMON=/usr/local/sbin/$NAME DAEMON_ARGS="" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.2-14) to ensure that this file is present # and status_of_proc is working. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS \ || return 2 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } # # Function that sends a SIGHUP to the daemon/service # do_reload() { # # If the daemon can reload its configuration without # restarting (for example, when it is sent a SIGHUP), # then implement that here. # start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME return 0 } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; #reload|force-reload) # # If do_reload() is not implemented then leave this commented out # and leave 'force-reload' as an alias for 'restart'. # #log_daemon_msg "Reloading $DESC" "$NAME" #do_reload #log_end_msg $? #;; restart|force-reload) # # If the "reload" option is implemented then remove the # 'force-reload' alias # log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac
Make the file executable with
sudo chmod +x /etc/init.d/telldusd
install the startup script with
sudo update-rc.d telldusd defaults
Start the Telldus service with
/etc/init.d/telldusd start
Now the Telldus subsystem is in place. To make it do something one have to put some info intio the configuration file /etc/tellstick.conf Remember to restart the Telldus daemon with
/etc/init.d/telldusd restart
every time you make changes into this file. You can find documentation for the configuration file here.
My testfile looks like this
user = "nobody" group = "plugdev" ignoreControllerConfirmation = "false" device { id = 1 name = "switch1" protocol = "arctech" model = "codeswitch:nexa" parameters { house = "A" unit = "1" } } device { id = 2 name = "switch2" protocol = "arctech" model = "codeswitch:nexa" parameters { house = "A" unit = "2" } } device { id = 3 name = "switch3" protocol = "arctech" model = "codeswitch:nexa" parameters { house = "A" unit = "3" } }
as I use Nexa devices bur as a lot of other protocols such as X10 is supported you can use that instead for your setup.
To turn on one of the devices use
tdtool --on switch1
or
tdtool --on 1
To turn off one of the devices use
tdtool --off switch1
or
tdtool --off 1
The decision matrix of the VSCP daemon is a powerful tool and can among other things be used as a scheduler to turn on/off devices at certain times. To use it first follow the instructions here Setup your system on Linux or Setup your system on Raspberry Pi or some of the other getting started descriptions that describes your system, to install and get VSCP & Friends ready for use on your system.
First suppose that we want switch1 to come on in the evening and off in the morning. Typical scenario in a home or in an office for windows lamps or similar. We can do this in two ways. Either we edit the dm configuration file directly in its default location /etc/vscp/dm.xml) or we can use the build in web interface of the VSCP daemon to do the same thing. We do it the hard way first.
Suppose we want switch1 to be turned on at 07:00 and be turned of at 03:00. To turn it on we add this code to the decision matrix configuration file
<row enabled="true" groupid="nightlight"> <!-- Mask - We just care for class and type --> <mask priority="0" class="0xffff" type="0xff" guid="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"></mask> <!-- Event we are interested in is internal minute event --> <filter priority="0" class="0xffff" type="6" guid="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"></filter> <!-- Allowed historical --> <allowed_from>1977-01-01 00:00:00</allowed_from> <!-- Allowed also far into the future --> <allowed_to>2099-12-31 23:59:59</allowed_to> <!-- Allowed every day in the week --> <allowed_weekdays>mtwtfss</allowed_weekdays> <!-- Execute command at 20:00 --> <allowed_time>*-*-* 20:00:*</allowed_time> <!-- Control code - --> <control>0x80000000</control> <!-- Action code == Execute command --> <action>0x00000010</action> <!-- Action parameter --> <param>/usr/local/bin/tdtool --on switch1</param> <!-- Comment for decision matrix row --> <comment>Turn on night lamp(s)</comment> </row>
and to turn off we add this row
<row enabled="true" groupid="nightlight"> <!-- Mask - We just care for class and type --> <mask priority="0" class="0xffff" type="0xff" guid="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"></mask> <!-- Event we are interested in is internal minute event --> <filter priority="0" class="0xffff" type="6" guid="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"></filter> <!-- Allowed historical --> <allowed_from>1977-01-01 00:00:00</allowed_from> <!-- Allowed also far into the future --> <allowed_to>2099-12-31 23:59:59</allowed_to> <!-- Allowed every day in the week --> <allowed_weekdays>mtwtfss</allowed_weekdays> <!-- Execute command at 03:00 --> <allowed_time>*-*-* 03:00:*</allowed_time> <!-- Control code - --> <control>0x80000000</control> <!-- Action code == Execute command --> <action>0x00000010</action> <!-- Action parameter --> <param>/usr/local/bin/tdtool --off switch1</param> <!-- Comment for decision matrix row --> <comment>Turn off night lamp(s)</comment> </row>
OK lets look at what this means.
First we have the group which i set to nightlight. This is a way to group rows that belong to each other together. We also have enable which is set to true which means the row will be active. Just set to false to inactivate a row.
Then we have the mask and the filter. In short they say we are interested in a VSCP daemon event that is feed to the decision matrix every minute (CLASS2.VSCPD, Type=6). The event is guarantied to be feed to the dm once each minute.There are plenty of other events, seconds/hour/week/random etc that can be used. See the VSCP specification document 13.8. How filter/mask works is explained here How filter/masks work and what they are.
Next we have allowed_from which is set to a date far back in history and allowed_to which is set to a date far in the future meaning this should be done “always”. This is a perfect place to handle summer/winter time scenarios and/or when different settings are needed between different dates.
allowed_weekdays says which weekdays the the action is allowed. Perfect if you want different scenarios for different days. Replace the day with a dash for a non allowed day.
In allowed_time we set the time we want the action to occur. Notice the setting for switch1 turnon *-*-* 20:00:* which means any year, any month, any day, at hour=20, at minute=0, any second. Any second is important here as we don't know this value when the minute event is feed to the decision matrix. The same is used for switch1 turn off
control is not needed here but is here to make the sample complete.
Then we have action which tells which action that should be done if the criterias above are fulfilled. In this case 0x10 = 16 meaning execute external program is used.
param is the the program we should execute and possibly any parameters needed.IN our case /usr/local/bin/tdtool –on switch1 and /usr/local/bin/tdtool –off switch1
Then last is the comment which is is a description of what we do.
The decision matrix and all its parameters, actions etc is described in the VSCP specification document section 14.7
A much easier way to add/edit/delet DM entries is to use the built in web interface of the VSCP daemon. Just point your browser at
http://host:8080/vscp
where host is the host where you have the VSCP daemon installed. Change 8080 to another port if you have changed this in the configuration file.
Now to add a new dm entry go to menu
/Configuration/DM - New element
and input the information as of above. To turn on at 21:30
and to turn off at 03:00
when save you have them in the list
Just click on one of the rows to edit it's content. There is no need to restart the VSCP daemon after you change a value.
The typical command that is sent to turn on a something in VSCP is CLASS1.CONTROL, Type=5, TurnOn (Specifiation 12.7.6) and to turn off something CLASS1.CONTROL, Type=6, TurnOff (Specifiation 12.7.67). Both use zone/subzone to tell what should be turned on/off. So if we also want to handle these buttons we can add a decision matrix entry for each just as above. One for class=30, Type=5 and one for Class=30, Type=6
In VSCP all devices that do something should report back that they have done what was requested from them. For this CLASS1.INFORMATION, Type=2, ON and CLASS1.INFORMATION, Type=3, OFF should be sent in this case for switch1 on and switch1 off respectively. But Tellstick does not return this information so we need to add decision matrix entries for this to.
One extra thing you should do here is to also check zone and subzone so check these values and also enter valid values.
See the Websockets guide and the vscpws_stateButton. All you have to do is to program a button to send the CLASS1.CONTROL, TurnOn/TurnOff event to the zone/subzone you have set up in the decision matrix as described above.