2016-01-13 20:39:06 +00:00
# $Id$
2016-02-03 21:24:08 +00:00
##########################################################################################################################################################################################
2014-12-21 20:34:02 +00:00
#
# Kopp Free Control protocol module for FHEM
# (c) Claus M.
#
# This modul is currenly under construction and will only work if you flashed your CCD device with hexfile from:
# svn+ssh://raspii@svn.code.sf.net/p/culfw/code/branches/raspii/culfw/Devices/CCD/CCD.hex
# which includes support for "K" command
#
# Published under GNU GPL License, v2
#
# Date Who Comment
# ---------- ------------- -------------------------------------------------------------------------------------------------------------------------------
2016-12-21 21:09:41 +00:00
# 2016-12-19 RaspII Test if new repository is working
2016-03-20 00:06:04 +00:00
# 2016-03-20 RaspII Added some information to Commandref, now attrib contains correct information
2016-02-03 21:24:08 +00:00
# 2016-01-30 RaspII Now also Blinds and Switches are implemented (all actuators I have).
# 2016-01-12 RaspII Implemented Dimmer Commands for 1&3 key remote, removed toggle
# 2015-06-02 RaspII Now can also Handle multiple devices with same code, next step: implement all commands (on, off, toggle... for KOPP_FC_Parse)
2016-01-13 20:39:06 +00:00
# Missing is also 2 key commands (e.g. key1=on Key2=off for Dimmmers, key1=up key2=down for blinds)
2016-02-03 21:24:08 +00:00
# 2015-05-21 RaspII Beim FS20 Modul sind die m<> glichen Set Commands abh<62> ngig vom "model" Attribute !! hier weitersuchen
2016-01-13 20:39:06 +00:00
# Seit die Return SerExtensions eingebaut ist, l<> sst sich bei Taste2Rad4 dass Commando Off nicht mehr absetzen (hat was mit dem Modul SerExtensions zu tun)
2016-02-03 21:24:08 +00:00
# 2015-05-02 RaspII Try now to receive Kopp Messages, also
# 2015-04-13 RaspII Modified some typos (help section)
# 2015-02-01 RaspII use small "k" to start Kopp FW, "K" was already used for raw data
# 2014-12-21 RaspII V6 (fits to my FHEM.cfg V6) Removed timeout from define command, will add later to set command (best guess yet).
# 2014-12-13 RaspII first version with command set: "on, off, toggle, dim, stop". Added new Parameter ("N" for do not print)
# 2014-12-08 RaspII direct usage of set command @ FHEM.cfg works fine, but buttoms on/off do not appear, seems to be a setup/initialize issue in this routine
# 2014-09-01 RaspII first Version
2014-12-21 20:34:02 +00:00
#
2016-01-13 20:39:06 +00:00
##########################################################################################################################################################################################
2014-12-21 20:34:02 +00:00
package main ;
use strict ;
use warnings ;
2016-01-13 20:39:06 +00:00
use SetExtensions ; # 2015-05-21 Wird vermutlich ben<65> tig um sp<73> ter die m<> glichen "Set" Commandos zu definieren
2014-12-21 20:34:02 +00:00
2016-01-13 20:39:06 +00:00
sub KOPP_FC_Initialize ($) ; ##### Claus evt. nicht n<> tig
sub KOPP_FC_Parse ($$) ; ##### Claus evt. nicht n<> tig
my % codes = ( # This Sheet contains all allowed codes, indevpendtly from Model type
"01" = > "on" ,
"02" = > "off" ,
"03" = > "toggle" ,
"04" = > "dimm" ,
"05" = > "stop" ,
2016-02-03 21:24:08 +00:00
"06" = > "up" ,
"07" = > "down" ,
"08" = > "top" ,
"09" = > "bottom" ,
2014-12-21 20:34:02 +00:00
) ;
2016-01-13 20:39:06 +00:00
my % sets = ( # Do not know whether this list is needed (guess: no)
"on" = > "" ,
"off" = > "" ,
"stop" = > "" ,
"toggle" = > "" ,
2016-02-03 21:24:08 +00:00
"dimm" = > "" ,
"up" = > "" ,
"down" = > "" ,
"top" = > "" ,
"bottom" = > ""
2016-01-13 20:39:06 +00:00
) ;
my % models = (
2016-02-03 21:24:08 +00:00
Switch_8080_01 = > 'Switch' ,
Switch_8080_01_2Key = > 'Switch_2KeyMode' ,
Blind_8080_02 = > 'Blind' ,
Timer_8080_04 = > 'TimerSwitch' ,
Dimm_8011_00 = > 'Dimmer' ,
Dimm_8011_00_3Key = > 'Dimmer_3KeyMode' ,
2014-12-21 20:34:02 +00:00
) ;
2016-01-13 20:39:06 +00:00
my % kopp_fc_c2b ; # DEVICE_TYPE->hash (reverse of device_codes), ##Claus what does that mean?
2014-12-21 20:34:02 +00:00
#############################
sub KOPP_FC_Initialize ($)
{
my ( $ hash ) = @ _ ;
2016-01-13 20:39:06 +00:00
foreach my $ k ( keys % codes ) { ## Claus needed if we wanna have the codes via commands
$ kopp_fc_c2b { $ codes { $ k } } = $ k ; # both lines not needed yet
}
2014-12-21 20:34:02 +00:00
2016-01-13 20:39:06 +00:00
# $hash->{Match} = "^kr.................."; # evt. sp<73> ter nehmen, damit nur genau 19 Zeichen akzeptiert werden
$ hash - > { Match } = "^kr.*" ;
2014-12-21 20:34:02 +00:00
$ hash - > { SetFn } = "KOPP_FC_Set" ;
$ hash - > { DefFn } = "KOPP_FC_Define" ;
2016-02-03 21:24:08 +00:00
$ hash - > { UndefFn } = "KOPP_FC_Undef" ;
2016-01-13 20:39:06 +00:00
$ hash - > { ParseFn } = "KOPP_FC_Parse" ;
$ hash - > { AttrFn } = "KOPP_FC_Attr" ; # aus SOMFY Beispiel abgeleitet
$ hash - > { AttrList } = "IODev " .
"model:" . join ( "," , sort keys % models ) ;
2014-12-21 20:34:02 +00:00
# . " symbol-length"
# . " enc-key"
# . " rolling-code"
# . " repetition"
# . " switch_rfmode:1,0"
# . " do_not_notify:1,0"
# . " ignore:0,1"
# . " dummy:1,0"
# . " model:somfyblinds"
# . " loglevel:0,1,2,3,4,5,6";
}
#############################
2016-02-03 21:24:08 +00:00
sub KOPP_FC_Define ($$)
{
2014-12-21 20:34:02 +00:00
my ( $ hash , $ def ) = @ _ ;
my @ a = split ( "[ \t][ \t]*" , $ def ) ;
2016-01-13 20:39:06 +00:00
my $ name = $ hash - > { NAME } ; ## neu 14.5.
2014-12-21 20:34:02 +00:00
my $ u = "wrong syntax: define <name> KOPP_FC keycode(Byte) transmittercode1(2Byte) transmittercode2(Byte)" ;
2016-01-13 20:39:06 +00:00
my $ keycode2 = "" ;
my $ keycode3 = "" ;
2014-12-21 20:34:02 +00:00
# fail early and display syntax help
if ( int ( @ a ) < 4 ) {
return $ u ;
}
# check keycode format (2 hex digits)
if ( ( $ a [ 2 ] !~ m/^[a-fA-F0-9]{2}$/i ) ) {
return "Define $a[0]: wrong keycode format: specify a 2 digit hex value "
}
my $ keycode = $ a [ 2 ] ;
$ hash - > { KEYCODE } = uc ( $ keycode ) ;
# check transmittercode1 format (4 hex digits)
if ( ( $ a [ 3 ] !~ m/^[a-fA-F0-9]{4}$/i ) ) {
return "Define $a[0]: wrong transmittercode1 format: specify a 4 digit hex value "
}
my $ transmittercode1 = $ a [ 3 ] ;
$ hash - > { TRANSMITTERCODE1 } = uc ( $ transmittercode1 ) ;
# check transmittercode2 format (2 hex digits)
if ( ( $ a [ 4 ] !~ m/^[a-fA-F0-9]{2}$/i ) ) {
return "Define $a[0]: wrong transmittercode2 format: specify a 2 digit hex value "
}
my $ transmittercode2 = $ a [ 4 ] ;
$ hash - > { TRANSMITTERCODE2 } = uc ( $ transmittercode2 ) ;
2016-01-13 20:39:06 +00:00
# check keycode2 (optional) format (2 hex digits)
if ( defined $ a [ 5 ] ) {
if ( ( $ a [ 5 ] !~ m/^[a-fA-F0-9]{2}$/i ) ) { #Default: Keycode2 is empty
}
else {
$ keycode2 = $ a [ 5 ] ;
$ hash - > { KEYCODE2 } = uc ( $ keycode2 ) ;
}
}
# check keycode3 (optional) format (2 hex digits)
if ( defined $ a [ 6 ] ) {
if ( ( $ a [ 5 ] !~ m/^[a-fA-F0-9]{2}$/i ) ) { #Default: Keycode3 is empty
}
else {
$ keycode3 = $ a [ 6 ] ;
$ hash - > { KEYCODE3 } = uc ( $ keycode3 ) ;
}
}
2014-12-21 20:34:02 +00:00
#Remove check for timeout
# check timeout (5 dec digits)
# if ( ( $a[5] !~ m/^[0-9]{5}$/i ) ) {
# return "Define $a[0]: wrong timeout format: specify a 5 digits decimal value"
# }
# removed next lines, may be will move timeout to set command (on-for-timer) or something like that
# my $timeout = $a[5];
# $hash->{TIMEOUT} = uc($timeout);
2016-01-13 20:39:06 +00:00
$ hash - > { TIMEOUT } = "00000" ; #Default timeout = 0
2014-12-21 20:34:02 +00:00
# group devices by their address
2016-01-13 20:39:06 +00:00
my $ code = uc ( "$transmittercode1 $keycode" ) ;
my $ ncode = 1 ;
# my $name = $a[0]; # see above, already defined
$ hash - > { CODE } { $ ncode + + } = $ code ; ## 6.1.2016: Code jetzt mit Referenz verlinken
# $hash->{CODE} = $code; ## daf<61> r diese Zeile raus
$ modules { KOPP_FC } { defptr } { $ code } { $ name } = $ hash ; ## neu 30.5. mit name vermutlich wird hier<65> ber das Device eindeutig identifiziert
# Noch die 2te Taste definieren, falls vorhanden
if ( $ keycode2 ne "" ) {
my $ code = uc ( "$transmittercode1 $keycode2" ) ;
$ hash - > { CODE } { $ ncode + + } = $ code ;
$ modules { KOPP_FC } { defptr } { $ code } { $ name } = $ hash ; ## neu 30.5. mit name vermutlich wird hier<65> ber das Device eindeutig identifiziert
}
# Noch die 3te Taste definieren, falls vorhanden
if ( $ keycode3 ne "" ) {
my $ code = uc ( "$transmittercode1 $keycode3" ) ;
$ hash - > { CODE } { $ ncode + + } = $ code ;
$ modules { KOPP_FC } { defptr } { $ code } { $ name } = $ hash ; ## neu 30.5. mit name vermutlich wird hier<65> ber das Device eindeutig identifiziert
}
# Noch so, der "Stop Code" = "F7" nach langem Tastendruck bekommt auch noch einen Eintrag
$ code = uc ( "$transmittercode1 F7" ) ;
$ hash - > { CODE } { "stop" } = $ code ;
$ modules { KOPP_FC } { defptr } { $ code } { $ name } = $ hash ; ## neu 30.5. mit name vermutlich wird hier<65> ber das Device eindeutig identifiziert
Log3 $ name , 2 , "KOPP_FC_Define: Modules: $modules{KOPP_FC}{defptr}{$code}{$name} Name: $name a[0]: $a[0] Transmittercode1: $transmittercode1 Keycode: $keycode Keycode2: $keycode2 $keycode Keycode3: $keycode3 Hash: $hash" ; # kann wieder Raus !!!! ### Claus
2014-12-21 20:34:02 +00:00
# $hash->{move} = 'on';
# ohne die folgende Zeile gibts beim Speichern von FHEM.cfg die Fehlermeldung Dimmer2 (wenn Dimmer2 als Name festgelegt werden soll)
AssignIoPort ( $ hash ) ;
}
2016-02-03 21:24:08 +00:00
#############################
sub KOPP_FC_Undef ($$)
{
my ( $ hash , $ name ) = @ _ ;
foreach my $ c ( keys % { $ hash - > { CODE } } )
{
$ c = $ hash - > { CODE } { $ c } ;
# As after a rename the $name my be different from the $defptr{$c}{$n}
# we look for the hash.
foreach my $ dname ( keys % { $ modules { KOPP_FC } { defptr } { $ c } } )
{
delete ( $ modules { KOPP_FC } { defptr } { $ c } { $ dname } ) if ( $ modules { KOPP_FC } { defptr } { $ c } { $ dname } == $ hash ) ;
# No entry to log file (only for test)
# if($modules{KOPP_FC}{defptr}{$c}{$dname} == $hash)
# {
# my $m=$modules{KOPP_FC}{defptr}{$c}{$dname};
# Log3 $name, 3, "KOPP_FC_Undef: Name: $name, Code: $c, $m deleted";
# }
}
}
return undef ;
}
2016-01-13 20:39:06 +00:00
##############################
sub KOPP_FC_Attr (@) {
# write new Attributes to global $attr variable if attribute name is model
my ( $ cmd , $ name , $ aName , $ aVal ) = @ _ ;
my $ hash = $ defs { $ name } ;
return "\"KOPP_FC Attr: \" $name does not exist" if ( ! defined ( $ hash ) ) ;
# $cmd can be "del" or "set"
# $name is device name
# aName and aVal are Attribute name and value
if ( $ cmd eq "set" ) {
if ( $ aName eq 'model' ) {
$ attr { $ name } { $ aName } = $ aVal ;
}
}
return undef ;
}
2014-12-21 20:34:02 +00:00
#####################################
sub KOPP_FC_SendCommand ($@)
{
my ( $ hash , @ args ) = @ _ ;
my $ ret = undef ;
my $ keycodehex = $ args [ 0 ] ;
my $ cmd = $ args [ 1 ] ;
my $ message ;
my $ name = $ hash - > { NAME } ;
my $ numberOfArgs = int ( @ args ) ;
my $ io = $ hash - > { IODev } ;
# return $keycodehex
$ message = "s"
. $ keycodehex
. $ hash - > { TRANSMITTERCODE1 }
. $ hash - > { TRANSMITTERCODE2 }
. $ hash - > { TIMEOUT }
. "N" ; # N for do not print messages (FHEM will write error messages to log files if CCD/CUL sends status info
## Send Message to IODev using IOWrite
2015-02-01 21:30:40 +00:00
IOWrite ( $ hash , "k" , $ message ) ;
2014-12-21 20:34:02 +00:00
return $ ret ;
}
# end sub KOPP_FC_SendCommand
#############################
#############################
sub KOPP_FC_Set ($@)
{
2016-01-13 20:39:06 +00:00
my ( $ hash , $ name , @ args ) = @ _ ; # Aufbau hash: Name, Command
2014-12-21 20:34:02 +00:00
my $ numberOfArgs = int ( @ args ) ;
my $ keycodedez ;
my $ keycodehex ;
2016-01-13 20:39:06 +00:00
my $ lh ;
my $ modl ;
2014-12-21 20:34:02 +00:00
# my $message;
if ( $ numberOfArgs < 1 )
{
return "no set value specified" ;
}
my $ cmd = lc ( $ args [ 0 ] ) ;
2016-01-13 20:39:06 +00:00
my $ c = $ kopp_fc_c2b { $ args [ 0 ] } ;
2016-02-03 21:24:08 +00:00
if ( ! defined ( $ c ) ) # if set command was not yet defined in %codes provide command list
# $c contains the first argument of %codes, "01" for "on", "02" for "off" ..
2016-01-13 20:39:06 +00:00
{
my $ list ;
if ( defined ( $ attr { $ name } ) && defined ( $ attr { $ name } { "model" } ) )
{
2016-02-03 21:24:08 +00:00
my $ mt = $ models { $ attr { $ name } { "model" } } ; # Model specific set arguments will be defined here (maybe move later to variable above)
$ list = "dimm stop on off" if ( $ mt && $ mt eq "Dimmer" ) ; # --------------------------------------------------------------------------------------
$ list = "dimm stop on off" if ( $ mt && $ mt eq "Dimmer_3KeyMode" ) ; # "$mt &&...", damit wird Inhalt von $mt nur gepr<70> ft wenn $mt initialisiert ist
$ list = "on off short" if ( $ mt && $ mt eq "TimerSwitch" ) ; # on means long key presure
$ list = "top bottom up down stop" if ( $ mt && $ mt eq "Blind" ) ; # up/down means long key presure
$ list = "on off" if ( $ mt && $ mt eq "Switch" ) ; # (no difference between long/short preasure)
$ list = "on off" if ( $ mt && $ mt eq "Switch_2KeyMode" ) ; # (no difference between long/short preasure)
2016-01-13 20:39:06 +00:00
}
$ list = ( join ( " " , sort keys % kopp_fc_c2b ) . " Claus" ) if ( ! defined ( $ list ) ) ; # if list not defined model specific, allow whole default list
return "[Kopp_FC_Set] unknown command <$cmd>, choose one of " . join ( " " , $ list ) ; # no more text after "choose one of " allowed
}
2016-02-03 21:24:08 +00:00
if ( defined ( $ attr { $ name } ) && defined ( $ attr { $ name } { "model" } ) ) # Falls Model spezifiziert ist, Model ermitteln -> $mt
2016-01-13 20:39:06 +00:00
{ # ----------------------------------------------------
$ modl = $ models { $ attr { $ name } { "model" } } ;
2016-02-03 21:24:08 +00:00
# Log3 $name, 2, "KOPP_FC_Set: Device Name: $name Index auf codes: $c Model: $modl"; # kann wieder Raus !!!! ### Claus
2016-01-13 20:39:06 +00:00
}
# readingsSingleUpdate($hash, "state","$cmd", 1); # update also Readings
# $hash->{STATE} = $cmd; # update device state
2016-02-03 21:24:08 +00:00
# Look for all devices with the same code, and update readings (state), (timestamp, not yet)
# ------------------------------------------------------------------------------------------------------
# some hints: if same code is used within config file for differen models update of state makes no sense
# and may fail because command is not available for a different model. So we only update devices which are
# of the same model as the original one.
#
2016-01-13 20:39:06 +00:00
# my $tn = TimeNow();
# my $defptr = $modules{KOPP_FC}{defptr}{transmittercode1}{keycode};
# foreach my $n (keys %{ $defptr })
# {
# readingsSingleUpdate($defptr->{$n}, "state","$cmd", 1);
# }
2016-02-03 21:24:08 +00:00
my $ code = $ hash - > { CODE } { 1 } ; # Load Devices code1 (typically key code short preasure)
my $ rhash = $ modules { KOPP_FC } { defptr } { $ code } ; # Load Hash of Devices with same code
2016-01-13 20:39:06 +00:00
2016-02-03 21:24:08 +00:00
# my @list; # Do (Why) I need this @lists (incl. return @list)?
2016-01-13 20:39:06 +00:00
foreach my $ n ( keys % { $ rhash } )
{
$ lh = $ rhash - > { $ n } ;
2016-02-03 21:24:08 +00:00
$ n = $ lh - > { NAME } ; # It may be renamed, n now contains name of defined device, e.g. Dimmer....
# return "" if(IsIgnored($n)); # Little strange.
2016-01-13 20:39:06 +00:00
2016-02-03 21:24:08 +00:00
if ( defined ( $ modl ) && defined ( $ attr { $ n } ) && defined ( $ attr { $ n } { "model" } ) )
{
my $ m = $ models { $ attr { $ n } { "model" } } ;
Log3 $ name , 3 , "KOPP_FC_Set: Device Name: $n, command: $cmd, Model: $m, Transm.-/KeyCode: $code" ;
# Falls auch dieses Model spezifiziert ist und Modell identisch dem Model aus Originalaufruf,
if ( $ m eq $ modl ) # ------------------------------------------------------------------------------------------
{ # dann den Status dieses Devices ebenfalls updaten
# Log3 $name, 2, "KOPP_FC_Set: Orig Model: $modl, Status Update also for Model: $m"; # kann wieder Raus !!!! ### Claus
$ lh - > { STATE } = $ cmd ; # update device state
readingsSingleUpdate ( $ lh , "state" , $ cmd , 1 ) ; # update also Readings
}
else
{
# Log3 $name, 2, "KOPP_FC_Set: Orig Model: $modl, wrong model: $m no Status Update done"; # kann wieder Raus !!!! ### Claus
# Log3 $name, 2, " dont define same remote key for different actuators models"; # kann wieder Raus !!!! ### Claus
}
}
2016-01-13 20:39:06 +00:00
# push(@list, $n);
}
# return @list;
# return"";
2014-12-21 20:34:02 +00:00
2016-02-03 21:24:08 +00:00
if ( $ cmd eq 'stop' ) # command = stop
{ # --------------
$ keycodehex = "F7" ; # Stop means F7 will be sent several times
} # (e.g. to end "dimm" end or "up" / "down" )
elsif ( $ cmd eq 'dimm' ) # independent of Dimmer Type
{ # ---------------------------
$ keycodehex = $ hash - > { KEYCODE } ; # use Keycode+0x80 for long key pressure = dimmer up/down
$ keycodedez = hex $ keycodehex ; # without moving to $keycodehex and addition in second line it does not work !?
$ keycodedez = $ keycodedez + 128 ; #
$ keycodehex = uc sprintf "%x" , $ keycodedez ; #
}
2014-12-21 20:34:02 +00:00
2016-02-03 21:24:08 +00:00
elsif ( $ modl && $ modl eq "Dimmer" ) # if model defined and equal Dimmer
{ # ---------------------------------
if ( $ cmd eq 'on' || $ cmd eq 'off' ) #
{ #
$ keycodehex = $ hash - > { KEYCODE } ; # -> use Keycode to send "on" or "off" command (=toggle)
}
}
2016-01-13 20:39:06 +00:00
2016-02-03 21:24:08 +00:00
elsif ( $ modl && $ modl eq "Dimmer_3KeyMode" ) # if model defined and equal 3-key Dimmer
{ # ---------------------------------------
if ( $ cmd eq 'on' && $ hash - > { KEYCODE2 } ne "" ) # Command = on
{ #
$ keycodehex = $ hash - > { KEYCODE2 } ; # -> use Keycode 2 to send "on" command
} #
if ( $ cmd eq 'off' && $ hash - > { KEYCODE3 } ne "" ) # Command = off
{ #
$ keycodehex = $ hash - > { KEYCODE3 } ; # -> use Keycode 3 to send "on" command
2016-01-13 20:39:06 +00:00
}
2016-02-03 21:24:08 +00:00
}
2016-01-13 20:39:06 +00:00
2016-02-03 21:24:08 +00:00
elsif ( $ modl && $ modl eq "Switch" ) # if model defined and equal Switch
{ # ---------------------------------
if ( $ cmd eq 'on' || $ cmd eq 'off' ) #
{ #
$ keycodehex = $ hash - > { KEYCODE } ; # -> use Keycode to send "on" or "off" command (=toggle)
} #
2014-12-21 20:34:02 +00:00
}
2016-02-03 21:24:08 +00:00
elsif ( $ modl && $ modl eq "Switch_2KeyMode" ) # if model defined and equal Switch controlled by 2 Keys
{ # ------------------------------------------------------
if ( $ cmd eq 'on' ) #
{ #
$ keycodehex = $ hash - > { KEYCODE } ; # -> use Keycode to send "on" or "off" command (=toggle)
} #
elsif ( $ cmd eq 'off' && $ hash - > { KEYCODE2 } ne "" ) #
{ #
$ keycodehex = $ hash - > { KEYCODE2 } ; # -> use Keycode to send "on" or "off" command (=toggle)
}
}
2014-12-21 20:34:02 +00:00
2016-02-03 21:24:08 +00:00
elsif ( $ modl && $ modl eq "Blind" ) # if model defined and equal Blind: #
{ # ----------------------------------------
if ( $ cmd eq 'top' ) #
{ # -> use Keycode to send "top" command
$ keycodehex = $ hash - > { KEYCODE } ; #
} #
elsif ( $ cmd eq 'bottom' && $ hash - > { KEYCODE2 } ne "" ) #
{ # -> use Keycode2 to send "bottom" command
$ keycodehex = $ hash - > { KEYCODE2 } ; #
} #
elsif ( $ cmd eq 'up' ) #
{ #
$ keycodehex = $ hash - > { KEYCODE } ; #
$ keycodedez = hex $ keycodehex ; # -> use Keycode+0x80 to send "up" command
$ keycodedez = $ keycodedez + 128 ; #
$ keycodehex = uc sprintf "%x" , $ keycodedez ; #
#
} #
elsif ( $ cmd eq 'down' && $ hash - > { KEYCODE2 } ne "" ) #
{ # -> use Keycode2+0x80 to send "dowm" command
$ keycodehex = $ hash - > { KEYCODE2 } ; #
$ keycodedez = hex $ keycodehex ; #
$ keycodedez = $ keycodedez + 128 ; #
$ keycodehex = uc sprintf "%x" , $ keycodedez ; #
}
}
2014-12-21 20:34:02 +00:00
2016-02-03 21:24:08 +00:00
elsif ( $ cmd eq 'on' || 'off' || 'toggle' ) # If model not known just allow on, off, toggle
{ # ---------------------------------------------
$ keycodehex = $ hash - > { KEYCODE } ; # -> use Keycode
2014-12-21 20:34:02 +00:00
}
2016-02-03 21:24:08 +00:00
else # should never happen :-)
{ # -----------------------
2014-12-21 20:34:02 +00:00
return "unknown command" ;
}
KOPP_FC_SendCommand ( $ hash , $ keycodehex , @ args ) ;
# KOPP_FC_SendCommand($hash, @args);
2016-01-13 20:39:06 +00:00
2014-12-21 20:34:02 +00:00
# $hash->{STATE} = 'off';
#return SetExtensions($hash,'toggle', @a);
return undef ;
}
# end sub Kopp_FC_setFN
###############################
2016-01-13 20:39:06 +00:00
#############################
#
2016-02-03 21:24:08 +00:00
sub KOPP_FC_Parse ($$) { # wird von fhem.pl dispatch getriggert
# Example receive Message: kr07FA5E7114CC0F02AD
# 07: block length; FA5E: Transmitter Code 1; 71: Key counter(next key pressed); 14: Key Code;
# CC0F: unknown, but always the same;
# 02: Transmiter Code 2; (content depends on transmitter, changed value seems not to change anything; AD: Checksum)
2016-01-13 20:39:06 +00:00
my ( $ hash , $ msg ) = @ _ ;
2016-02-03 21:24:08 +00:00
my $ name = $ hash - > { NAME } ; # Here: Device Hash (e.g. to CUL), e.g. $name = "CUL_0"
my $ state ; # means receive command = new state
2016-01-13 20:39:06 +00:00
my $ keycodedez ;
2016-02-03 21:24:08 +00:00
my $ specialkey = "short" ; # Default: short key
2016-01-13 20:39:06 +00:00
my $ code ;
my $ devicefound ;
2016-02-03 21:24:08 +00:00
if ( $ msg =~ m/^kr/ ) { # if first two char's are "kr" then we are right here (KOPP Message received)
2016-01-13 20:39:06 +00:00
# Msg format:
# kr.. rest to be defined later
# if (substr($msg, 0, 16) eq "krS-ReceiveStart" || substr($msg, 0, 14) eq "krE-ReceiveEnd")
if ( substr ( $ msg , 0 , 2 ) eq "kr" )
{
# get Transtmitter Code 1
2016-02-03 21:24:08 +00:00
my $ transmittercode1 = uc ( substr ( $ msg , 4 , 4 ) ) ; # Example above: FA5E
2014-12-21 20:34:02 +00:00
2016-01-13 20:39:06 +00:00
# get Transtmitter Code 2
2016-02-03 21:24:08 +00:00
my $ transmittercode2 = uc ( substr ( $ msg , 16 , 2 ) ) ; # Example above: 02
2014-12-21 20:34:02 +00:00
2016-01-13 20:39:06 +00:00
# get Key Code
2016-02-03 21:24:08 +00:00
my $ keycode = uc ( substr ( $ msg , 10 , 2 ) ) ; # Example above: 14
$ keycodedez = hex $ keycode ; # If Keycode > 128 and not equal "long key end" (F7) then Long Key pressure
2014-12-21 20:34:02 +00:00
2016-02-03 21:24:08 +00:00
if ( $ keycode eq "F7" ) # If end of long keypressure (stop) we need special handling
{ # ----------------------------------------------------------
2016-01-13 20:39:06 +00:00
$ code = uc ( "$transmittercode1 F7" ) ;
$ specialkey = "stop" ;
}
else
{
if ( $ keycodedez >= 128 && $ keycode ne "F7" )
2016-02-03 21:24:08 +00:00
{ # If long key pressure:
$ keycodedez = ( $ keycodedez - 128 ) ; # ---------------------
2016-01-13 20:39:06 +00:00
$ specialkey = "long" ;
2016-02-03 21:24:08 +00:00
$ keycode = uc sprintf "%02x" , $ keycodedez ; # %02 damit auch eine "0"... zweistellig wird
2016-01-13 20:39:06 +00:00
}
$ code = uc ( "$transmittercode1 $keycode" ) ;
}
2016-02-03 21:24:08 +00:00
my $ rhash = $ modules { KOPP_FC } { defptr } { $ code } ; # neu 30.5. rhash war nicht eindeutig
2016-01-13 20:39:06 +00:00
2016-02-03 21:24:08 +00:00
# my $rname = $rhash->{NAME}; # $rhash is hash to corresponding device as calculated from receive data
2016-01-13 20:39:06 +00:00
2016-02-03 21:24:08 +00:00
Log3 $ name , 2 , "KOPP_FC_Parse: name: $name code: $code Specialkey:$specialkey" ; # kann wieder Raus !!!! ### Claus rname wird m<> ll, da Hash mehrere Namen verlinkt?
# rname funktioniert nur wenn $name in Zeile 149/150 nicht angeh<65> ngt ist
2016-01-13 20:39:06 +00:00
# my $tn = TimeNow();
# Look for all devices with the same code, and set state, (timestamp, not yet)
# ----------------------------------------------------------------------------
if ( $ rhash )
{
my @ list ;
foreach my $ n ( keys % { $ rhash } )
{
my $ lh = $ rhash - > { $ n } ;
$ n = $ lh - > { NAME } ; # It may be renamed, n now contains name of defined device, e.g. Dimmer....
return "" if ( IsIgnored ( $ n ) ) ; # Little strange.
my $ oldstate = ReadingsVal ( $ n , "state" , "" ) ; #
# Je nach Model die Aktion triggern.
# 3 Key Dimmer:
#==============
$ devicefound = 1 ; # Default: wir kennen das Device
if ( $ attr { $ n } { model } && ( $ attr { $ n } { model } eq 'Dimm_8011_00_3Key' ) ) # Wenn Device = 3 Key Dimmer
{ # ==========================
if ( $ specialkey eq 'short' && $ keycode eq $ lh - > { KEYCODE } ) # Taste 1 kurz gedr<64> ckt: dann toggeln
{ # -----------------------------------
if ( $ oldstate eq 'off' ) { $ state = "on" ; } # off -> on
elsif ( $ oldstate eq 'on' ) { $ state = "off" ; } # on -> off
elsif ( $ oldstate eq 'stop' ) { $ state = "off" ; } # stop -> off
else { $ state = "on" ; } # Weder noch? dann Neuer Zustand = on (wird dann wohl aus gewesen sein)
}
elsif ( $ specialkey eq "long" && $ keycode eq $ lh - > { KEYCODE } ) # Taste 1 lang gedr<64> ckt: dann dimmen
{ # ----------------------------------
$ state = "dimm" ;
}
elsif ( $ specialkey eq "stop" ) # Ende der lang gedr<64> ckten Taste dann dimmen stoppen
{ # --------------------------------------------------
$ state = "stop" if ( $ oldstate eq 'dimm' || $ oldstate eq 'stop' ) ; # falls dimmen aktiv war oder bereits gestoppt wurde
}
elsif ( $ keycode eq $ lh - > { KEYCODE2 } ) { $ state = "on" ; } # Taste 2: (kurz oder lang) -> On
elsif ( $ keycode eq $ lh - > { KEYCODE3 } ) { $ state = "off" ; } # Taste 3: (kurz oder lang) -> Off
else { }
}
2016-02-03 21:24:08 +00:00
# 1 Key Dimmer:
#==============
2016-01-13 20:39:06 +00:00
elsif ( $ attr { $ n } { model } && ( $ attr { $ n } { model } eq 'Dimm_8011_00' ) ) # Wenn Device = 1 Key Dimmer
{ # ==========================
if ( $ specialkey eq 'short' && $ keycode eq $ lh - > { KEYCODE } ) # Taste 1 kurz gedr<64> ckt: dann toggeln
{ # -----------------------------------
if ( $ oldstate eq 'off' ) { $ state = "on" ; } # off -> on
elsif ( $ oldstate eq 'on' ) { $ state = "off" ; } # on -> off
elsif ( $ oldstate eq 'stop' ) { $ state = "off" ; } # stop -> off
else { $ state = "on" ; } # Weder noch? dann Neuer Zustand = on (wird dann wohl aus gewesen sein)
}
elsif ( $ specialkey eq "long" && $ keycode eq $ lh - > { KEYCODE } ) # Taste 1 lang gedr<64> ckt: dann dimmen
{ # ----------------------------------
$ state = "dimm" ;
}
elsif ( $ specialkey eq "stop" ) # Ende der lang gedr<64> ckten Taste dann dimmen stoppen
{ # --------------------------------------------------
$ state = "stop" if ( $ oldstate eq 'dimm' || $ oldstate eq 'stop' ) ; # falls dimmen aktiv war oder bereits gestoppt wurde
}
}
2016-02-03 21:24:08 +00:00
# Blind:
#=======
elsif ( $ attr { $ n } { model } && ( $ attr { $ n } { model } eq 'Blind_8080_02' ) ) # Wenn Device = Blind/Rolladen
{ # ============================
if ( $ specialkey eq 'short' && $ keycode eq $ lh - > { KEYCODE } ) # Taste 1 kurz gedr<64> ckt: dann Endzustand top/oben anfahren
{ # --------------------------------------------------------
$ state = "top" ; #
}
elsif ( $ specialkey eq "long" && $ keycode eq $ lh - > { KEYCODE } ) # Taste 1 lang gedr<64> ckt: dann nach oben fahren (bis zu stop)
{ # ----------------------------------------------------------
$ state = "up" ;
}
if ( $ specialkey eq 'short' && $ keycode eq $ lh - > { KEYCODE2 } ) # Taste 2 kurz gedr<64> ckt: dann Endzustand bottom/unten anfahren
{ # ------------------------------------------------------------
$ state = "bottom" ; #
}
elsif ( $ specialkey eq "long" && $ keycode eq $ lh - > { KEYCODE2 } ) # Taste 2 lang gedr<64> ckt: dann nach runter fahren (bis zu stop)
{ # -----------------------------------------------------------
$ state = "down" ;
}
elsif ( $ specialkey eq "stop" ) # Ende der lang gedr<64> ckten Taste dann Fahrt stoppen
{ # --------------------------------------------------
$ state = "stop" if ( $ oldstate eq 'up' || $ oldstate eq 'down' || $ oldstate eq 'stop' ) ; # falls fahrt aktiv war oder bereits gestoppt wurde
}
else { }
}
2016-01-13 20:39:06 +00:00
2016-02-03 21:24:08 +00:00
# 2 Key Switch:
#==============
elsif ( $ attr { $ n } { model } && ( $ attr { $ n } { model } eq 'Switch_8080_01_2Key' ) ) # Wenn Device = 2 Key Switch
{ # ==============================
if ( $ keycode eq $ lh - > { KEYCODE } ) # Taste 1 gedr<64> ckt (no matter if short or long) -> State = on
{ # -----------------------------------------------------------
$ state = "on" ; #
}
elsif ( $ keycode eq $ lh - > { KEYCODE2 } ) # Taste 2 gedr<64> ckt (no matter if short or long) -> State = off
{ # ------------------------------------------------------------
$ state = "off" ; #
}
else { }
}
# F<> r 1 Key Switch und alle anderen Modelle gilt: egal ob kurz oder langer Tastendruck: toggeln zwischen on und off !
# ===================================================================================================================
elsif ( $ specialkey ne 'stop' ) # Bei Ende der lang gedr<64> ckten Taste: nothing to do in this case
2016-01-13 20:39:06 +00:00
{
if ( $ oldstate eq 'off' ) { $ state = "on" ; } # off -> on
elsif ( $ oldstate eq 'on' ) { $ state = "off" ; } # on -> off
else { $ state = "on" ; } # Weder noch? dann Neuer Zustand = on (wird dann wohl aus gewesen sein)
}
else # Bei unbekanntem Device/Aktion keine weitere Aktion
{
$ devicefound = 0 ; # das Device ist nicht bekannt
}
if ( $ devicefound == 1 ) # Update Readings if Device/Action found
{
# Log3 $name, 2, "KOPP_FC_Parse: Model $attr{$n}{model} gefunden "; # kann wieder Raus !!!! ### Claus
# Log3 $name, 2, "KOPP_FC_Parse: Code1: $lh->{CODE}{1} "; # kann wieder Raus !!!! ### Claus
# Log3 $name, 2, "KOPP_FC_Parse: Code2: $lh->{CODE}{2} "; # kann wieder Raus !!!! ### Claus
# Log3 $name, 2, "KOPP_FC_Parse: Code3: $lh->{CODE}{3} "; # kann wieder Raus !!!! ### Claus
# Log3 $name, 2, "KOPP_FC_Parse: KeyCode1: $lh->{KEYCODE} "; # kann wieder Raus !!!! ### Claus
# Log3 $name, 2, "KOPP_FC_Parse: KeyCode2: $lh->{KEYCODE2} "; # kann wieder Raus !!!! ### Claus
# Log3 $name, 2, "KOPP_FC_Parse: KeyCode3: $lh->{KEYCODE3} "; # kann wieder Raus !!!! ### Claus
readingsSingleUpdate ( $ lh , "state" , $ state , 1 ) ; # $state mit "" oder ohne?
# Log3 $name, 2, "KOPP_FC_Parse lh: $lh n: $n oldstate: $oldstate state: $state"; # kann wieder Raus !!!! ### Claus
push ( @ list , $ n ) ;
}
}
return @ list ;
}
else
{
2016-02-03 21:24:08 +00:00
Log3 $ name , 2 , "KOPP_FC_Parse: Device not defined for message $msg" ;
2016-01-13 20:39:06 +00:00
}
}
else
{
Log3 $ name , 2 , "$name: KOPP_FC_Parse: nicht gefunden 01 $msg" ; # kann wieder Raus !!!! ### Claus
return "KOPP_Parse: Command not known" ;
}
} else {
DoTrigger ( $ name , "UNKNOWNCODE $msg" ) ;
Log3 $ name , 2 , "$name: KOPP_FC.PM Kopp nicht gefunden 02 $msg" ; # kann wieder Raus !!!! ### Claus
Log3 $ name , 3 , "$name: Unknown code $msg, help me [KOPP_FC]!" ;
return undef ;
}
}
# end sub Kopp_FC_Parse
###############################
2014-12-21 20:34:02 +00:00
1 ;
= pod
2016-12-21 21:09:41 +00:00
= item device
= item summary controls "Kopp Free Control" Devices via 868 Mhz CUL , CCD ...
= item summary_DE steuert "Kopp Free Control" Devices via 868 Mhz CULs , CCD ...
2014-12-21 20:34:02 +00:00
= begin html
< a name = "KOPP_FC" > </a>
<h3> Kopp Free Control protocol </h3>
<ul>
2016-02-03 21:24:08 +00:00
<b> Please take into account: this protocol is under construction . Commands may change </b>
2014-12-21 20:34:02 +00:00
<br> <br>
The Kopp Free Control protocol is used by Kopp receivers / actuators and senders .
2016-02-03 21:24:08 +00:00
This module is able to send commands to Kopp actuators and receive commands from Kopp transmitters . Currently supports devices: dimmers , switches and blinds .
The communication is done via a < a href = "#CUL" > CUL </a> or compatible device ( e . g . CCD ... ) .
2016-03-20 00:06:04 +00:00
This devices must be defined before using this protocol .
2014-12-21 20:34:02 +00:00
<br> <br>
2016-03-20 00:06:04 +00:00
<b> Assign the Kopp Free Control protocol to a CUL or compatible device </b>
<ul>
<code> define CUL_0 CUL /dev/ ttyAMA0 @ 38400 1234 </code> <br>
<code> attr CUL_0 rfmode KOPP_FC </code>
<br>
This attribute ( "rfmode KOPP_FC" ) assigns the Kopp protocol to device CUL_0 <br>
You may <b> not </b> assign / use a second protocol on this device
<br>
</ul>
<br>
2014-12-21 20:34:02 +00:00
< a name = "KOPP_FCdefine" > </a>
<b> Define </b>
<ul>
2016-01-13 20:39:06 +00:00
<code> define & lt ; name & gt ; KOPP_FC & lt ; Keycode & gt ; & lt ; Transmittercode1 & gt ; & lt ; Transmittercode2 & gt ; [ & lt ; Keycode2 & gt ] [ & lt ; Keycode3 & gt ] </code>
2014-12-21 20:34:02 +00:00
<br>
<br> <li> <code> & lt ; name & gt ; </code> </li>
2016-02-03 21:24:08 +00:00
name is the identifier ( name ) you plan to assign to your specific device ( actuator ) as done for any other FHEM device
2014-12-21 20:34:02 +00:00
<br> <br> <li> <code> & lt ; Keycode & gt ; </code> </li>
Keycode is a 2 digit hex code ( 1 Byte ) which reflects the transmitters key
<br> <br> <li> <code> & lt ; Transmittercode1 & gt ; </code> </li>
Transmittercode1 is a 4 digit hex code . This code is specific for the transmitter itself .
<br> <br> <li> <code> & lt ; Transmittercode2 & gt ; </code> </li>
Transmittercode2 is a 2 digit hex code and also specific for the transmitter , but I didn ' t see any difference while modifying this code .
( seems this code don ' t matter the receiver ) .
2016-01-13 20:39:06 +00:00
<br> Both codes ( Transmittercode1 / 2 ) are also used to pair the transmitter with the receivers ( remote switch , dimmer , blind .. )
<br> <br> <li> <code> [ & lt ; Keycode2 & gt ; ] </code> </li>
Keycode2 is an opional 2 digit hex code ( 1 Byte ) which reflects a second transmitters key
<br> <br> <li> <code> [ & lt ; Keycode3 & gt ; ] </code> </li>
Keycode3 is an opional 2 digit hex code ( 1 Byte ) which reflects a third transmitters key
2014-12-21 20:34:02 +00:00
<br>
2016-01-13 20:39:06 +00:00
Some receivers like dimmers can be paired with two addional keys , which allow to switch the dimmer directly on or off .
That means FHEM will always know the current state , which is not the case in one key mode ( toggling between on and off )
<br> <br>
2014-12-21 20:34:02 +00:00
Pairing is done by setting the receiver in programming mode by pressing the program button at the receiver <br>
( small buttom , typically inside a hole ) . <br>
2016-01-13 20:39:06 +00:00
Once the receiver is in programming mode send a command ( or two , see dimmer above ) from within FHEM to complete the pairing .
2014-12-21 20:34:02 +00:00
For more details take a look to the data sheet of the corresponding receiver type .
<br>
2016-01-13 20:39:06 +00:00
You are now able to control the receiver from FHEM , the receiver handles FHEM just linke another remote control .
</ul>
2014-12-21 20:34:02 +00:00
2016-03-20 00:06:04 +00:00
<br>
2014-12-21 20:34:02 +00:00
< a name = "KOPP_FCset" > </a>
<b> Set </b>
<ul>
<code> set & lt ; name & gt ; & lt ; value & gt </code>
<br>
<br> <li> <code> & lt ; value & gt ; </code> </li>
value is one of:
<ul>
<code> on </code> <br>
<code> off </code> <br>
<code> dimm </code> <br>
2016-01-13 20:39:06 +00:00
<code> stop </code> <br>
2014-12-21 20:34:02 +00:00
</ul>
<pre> Examples:
2016-03-20 00:06:04 +00:00
<code> set Dimmer on </code> # will toggle dimmer device on/off for 1Key remote control,
<code> </code> will switch on for 3 key remote control
<code> set Dimmer off </code> # will switch dimmer device off (3 key remote control)
<code> set Dimmer dimm </code> # will start dimming process
<code> set Dimmer stop </code> # will stop dimming process
2014-12-21 20:34:02 +00:00
</pre>
</ul>
2016-02-03 21:24:08 +00:00
< a name = "KOPP_FCattrib" > </a>
<b> Attributes </b>
<ul>
2016-03-20 00:06:04 +00:00
<code> attr & lt ; name & gt ; model & lt ; value & gt </code>
2016-02-03 21:24:08 +00:00
<br>
2016-03-20 00:06:04 +00:00
<br> <li> <code> & lt ; value & gt ; </code> </li>
value is one of:
<ul>
<code> Switch_8080_01 </code> <br>
<code> Switch_8080_01_2Key </code> <br>
<code> Blind_8080_02 </code> <br>
<code> Timer_8080_04 </code> <br>
<code> Dimm_8011_00 </code> <br>
<code> Dimm_8011_00_3Key </code> <br>
</ul>
2016-02-03 21:24:08 +00:00
</ul>
2014-12-21 20:34:02 +00:00
<br>
2016-03-20 00:06:04 +00:00
<b> Examples </b>
2016-02-03 21:24:08 +00:00
<ul>
2016-03-20 00:06:04 +00:00
<br> FHEM Config for Dimmer via 1 Key remote control:
<ul>
2016-02-03 21:24:08 +00:00
<code> define Dimmer KOPP_FC 65 FA5E 02 </code> <br>
2016-03-20 00:06:04 +00:00
<code> attr Dimmer IODev CUL_0 </code> <br>
2016-02-03 21:24:08 +00:00
<code> attr Dimmer devStateIcon OnOff:toggle:dimm dimm:dim50 % :stop stop:on:dimm off:toggle:dimm </code> <br>
<code> attr Dimmer eventMap on:OnOff dimm:dimm stop:stop </code> <br>
2016-03-20 00:06:04 +00:00
<code> attr Dimmer group TestGroup </code> <br>
2016-02-03 21:24:08 +00:00
<code> attr Dimmer model Dimm_8011_00 </code> <br>
2016-03-20 00:06:04 +00:00
<code> attr Dimmer room TestRoom </code> <br>
2016-02-03 21:24:08 +00:00
<code> attr Dimmer webCmd OnOff:dimm:stop </code> <br>
2016-03-20 00:06:04 +00:00
</ul>
2016-02-03 21:24:08 +00:00
2016-03-20 00:06:04 +00:00
<br> FHEM Config for Dimmer via 3 Key remote control:
<ul>
<code> define SDimmer KOPP_FC 65 FA5E 02 55 75 </code> <br>
<code> attr SDimmer IODev CUL_0 </code> <br>
<code> attr SDimmer devStateIcon dimm:dim50 % :stop stop:on:off on:on:off off:off:on </code> <br>
<code> attr SDimmer group TestGroup </code> <br>
<code> attr SDimmer icon light_pendant_light </code> <br>
<code> attr SDimmer model Dimm_8011_00_3Key </code> <br>
<code> attr SDimmer room TestRoom </code> <br>
<code> attr SDimmer webCmd on:dimm:stop:off </code> <br>
</ul>
</ul>
<br> <br>
<b> Additional Information you can find in corresponding FHEM Wiki </b>
<ul> <li> < a href = "http://www.fhemwiki.de/w/index.php?title=Kopp_Allgemein&redirect=no" > Kopp Allgemein </a> </li> </ul>
<br> <br>
</ul>
2014-12-21 20:34:02 +00:00
= end html
= cut