2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-12 16:46:35 +00:00

SOMFY: added support for exact positioning (by Elektrolurch) - requires one-time setup of run times.

SOMFY: support for parse() function, requires newest CULFW.


git-svn-id: https://svn.fhem.de/fhem/trunk@6634 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
thomyd 2014-09-30 13:56:19 +00:00
parent ac0e3ccde5
commit c4a575cfb3
2 changed files with 421 additions and 82 deletions

View File

@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it. # Do not insert empty lines here, update check depends on it.
- feature: SOMFY: support for exact positioning (one-time setup of run times required)
support for parse()-function, requires newest CULFW.
- feature: userattr is now also device attribute - feature: userattr is now also device attribute
- feature: ZWave: Fibaro_FGRM222 MANUFACTURER_PROPRIETARY class - feature: ZWave: Fibaro_FGRM222 MANUFACTURER_PROPRIETARY class
- feature: sequence: reportEvents attribtue added - feature: sequence: reportEvents attribtue added

View File

@ -8,6 +8,23 @@
# the newest culfw (support for "Y" command). # the newest culfw (support for "Y" command).
# #
# Published under GNU GPL License, v2 # Published under GNU GPL License, v2
#
# History:
# 1.0 thomyd initial implementation
#
# 1.1 Elektrolurch state changed to open,close,pos <x>
# for using "set device pos <value> the attributes
# drive-down-time-to-100, drive-down-time-to-close,
# drive-up-time-to-100 and drive-up-time-to-open must be set
# Hardware section seperated to SOMFY_SetCommand
#
# 1.2 Elektrolurch state is now set after reaching the position of the blind
# preparation for receiving signals of Somfy remotes signals,
# associated with the blind
#
# 1.3 thomyd Basic implementation of "parse" function, requires updated CULFW
# Removed open/close as the same functionality can be achieved with an eventMap.
###################################################### ######################################################
package main; package main;
@ -20,9 +37,21 @@ my %codes = (
"11" => "stop", # stop the current movement "11" => "stop", # stop the current movement
"20" => "off", # go "up" "20" => "off", # go "up"
"40" => "on", # go "down" "40" => "on", # go "down"
"80" => "prog", # enter programming mode "80" => "prog", # finish pairing
"100" => "on-for-timer", "100" => "on-for-timer",
"101" => "off-for-timer", "101" => "off-for-timer",
"XX" => "z_custom", # custom control code
);
my %sets = (
"off" => "",
"on" => "",
"stop" => "",
"go-my" => "",
"on-for-timer" => "textField",
"off-for-timer" => "textField",
"z_custom" => "textField",
"pos" => "0,10,20,30,40,50,60,70,80,90,100"
); );
my %somfy_c2b; my %somfy_c2b;
@ -32,6 +61,14 @@ my $somfy_defrepetition = 6; # Default Somfy frame repeat counter
my %models = ( somfyblinds => 'blinds', ); # supported models (blinds only, as of now) my %models = ( somfyblinds => 'blinds', ); # supported models (blinds only, as of now)
#############################
sub myUtilsSOMFY_Initialize($) {
$modules{SOMFY}{LOADED} = 1;
my $hash = $modules{SOMFY};
SOMFY_Initialize($hash);
} # end sub myUtilsSomfy_initialize
############################# #############################
sub SOMFY_Initialize($) { sub SOMFY_Initialize($) {
my ($hash) = @_; my ($hash) = @_;
@ -41,15 +78,20 @@ sub SOMFY_Initialize($) {
$somfy_c2b{ $codes{$k} } = $k; $somfy_c2b{ $codes{$k} } = $k;
} }
# YsKKC0RRRRAAAAAA # YsKKC0RRRRAAAAAA
# $hash->{Match} = "^YsA..0..........\$"; # $hash->{Match} = "^YsA..0..........\$";
$hash->{SetFn} = "SOMFY_Set"; $hash->{SetFn} = "SOMFY_Set";
#$hash->{StateFn} = "SOMFY_SetState"; #$hash->{StateFn} = "SOMFY_SetState";
$hash->{DefFn} = "SOMFY_Define"; $hash->{DefFn} = "SOMFY_Define";
$hash->{UndefFn} = "SOMFY_Undef"; $hash->{UndefFn} = "SOMFY_Undef";
$hash->{ParseFn} = "SOMFY_Parse";
$hash->{AttrFn} = "SOMFY_Attr";
# $hash->{ParseFn} = "SOMFY_Parse"; $hash->{AttrList} = " drive-down-time-to-100"
$hash->{AttrList} = "IODev" . " drive-down-time-to-close"
. " drive-up-time-to-100"
. " drive-up-time-to-open "
. " IODev"
. " symbol-length" . " symbol-length"
. " enc-key" . " enc-key"
. " rolling-code" . " rolling-code"
@ -63,6 +105,21 @@ sub SOMFY_Initialize($) {
} }
#############################
sub SOMFY_StartTime($) {
my ($d) = @_;
my ($s, $ms) = gettimeofday();
my $t = $s + ($ms / 1000000); # 10 msec
my $t1 = 0;
$t1 = $d->{'starttime'} if(exists($d->{'starttime'} ));
$d->{'starttime'} = $t;
my $dt = sprintf("%.2f", $t - $t1);
return $dt;
} # end sub SOMFY_StartTime
############################# #############################
sub SOMFY_Define($$) { sub SOMFY_Define($$) {
my ( $hash, $def ) = @_; my ( $hash, $def ) = @_;
@ -124,7 +181,7 @@ sub SOMFY_Define($$) {
my $ncode = 1; my $ncode = 1;
$hash->{CODE}{ $ncode++ } = $code; $hash->{CODE}{ $ncode++ } = $code;
$modules{SOMFY}{defptr}{$code}{$name} = $hash; $modules{SOMFY}{defptr}{$code}{$name} = $hash;
$hash->{move} = 'stop';
AssignIoPort($hash); AssignIoPort($hash);
} }
@ -147,59 +204,26 @@ sub SOMFY_Undef($$) {
} }
##################################### #####################################
sub SOMFY_Extension_Fn($) sub SOMFY_SendCommand($@)
{ {
my (undef, $name, $cmd) = split(" ", shift, 3); my ($hash, @args) = @_;
return if(!defined($defs{$name}));
if($cmd eq "on-for-timer") {
DoSet($name, "stop"); # send the stop-command
} elsif($cmd eq "off-for-timer") {
DoSet($name, "stop");
}
}
#############################
sub SOMFY_Do_For_Timer($@)
{
my ($hash, $name, $cmd, $param) = @_;
my $cmd1 = ($cmd =~ m/on.*/ ? "on" : "off");
RemoveInternalTimer("SOMFY $name $cmd");
return "$cmd requires a number as argument" if($param !~ m/^\d*\.?\d*$/);
if($param) {
# send the on/off command first
DoSet($name, $cmd1);
# schedule the stop command for later
InternalTimer(gettimeofday()+$param,"SOMFY_Extension_Fn","SOMFY $name $cmd",0);
}
return
}
###################################
sub SOMFY_Set($@) {
my ( $hash, $name, @args ) = @_;
my $ret = undef; my $ret = undef;
my $numberOfArgs = int(@args); my $cmd = $args[0];
my $message; my $message;
my $name = $hash->{NAME};
my $numberOfArgs = int(@args);
if ( $numberOfArgs < 1 ) {
return "no set value specified" ;
}
return SOMFY_Do_For_Timer($hash, $name, @args) if($args[0] =~ m/[on|off]-for-timer$/); # custom control needs 2 digit hex code
return "Bad time spec" if($numberOfArgs == 2 && $args[1] !~ m/^\d*\.?\d+$/); return "Bad custom control code, use 2 digit hex codes only" if($args[0] eq "z_custom"
&& ($numberOfArgs == 1
|| ($numberOfArgs == 2 && $args[1] !~ m/^[a-fA-F0-9]{2}$/)));
my $command = $somfy_c2b{ $args[0] }; my $command = $somfy_c2b{ $cmd };
# eigentlich überflüssig, da oben schon auf Existenz geprüft wird -> %sets
if ( !defined($command) ) { if ( !defined($command) ) {
return "Unknown argument $args[0], choose one of " return "Unknown argument $cmd, choose one of "
. join( " ", sort keys %somfy_c2b ); . join( " ", sort keys %somfy_c2b );
} }
@ -221,8 +245,8 @@ sub SOMFY_Set($@) {
if ( defined( $attr{ $name } ) if ( defined( $attr{ $name } )
&& defined( $attr{ $name }{"symbol-length"} ) ) && defined( $attr{ $name }{"symbol-length"} ) )
{ {
$message = "Yt" . $attr{ $name }{"symbol-length"}; $message = "t" . $attr{ $name }{"symbol-length"};
CUL_SimpleWrite( $io, $message ); IOWrite( $hash, "Y", $message );
Log GetLogLevel( $name, 4 ), Log GetLogLevel( $name, 4 ),
"SOMFY set symbol-length: $message for $io->{NAME}"; "SOMFY set symbol-length: $message for $io->{NAME}";
} }
@ -232,8 +256,8 @@ sub SOMFY_Set($@) {
if ( defined( $attr{ $name } ) if ( defined( $attr{ $name } )
&& defined( $attr{ $name }{"repetition"} ) ) && defined( $attr{ $name }{"repetition"} ) )
{ {
$message = "Yr" . $attr{ $name }{"repetition"}; $message = "r" . $attr{ $name }{"repetition"};
CUL_SimpleWrite( $io, $message ); IOWrite( $hash, "Y", $message );
Log GetLogLevel( $name, 4 ), Log GetLogLevel( $name, 4 ),
"SOMFY set repetition: $message for $io->{NAME}"; "SOMFY set repetition: $message for $io->{NAME}";
} }
@ -258,7 +282,12 @@ sub SOMFY_Set($@) {
my $enckey = uc(ReadingsVal($name, "enc_key", "A0")); my $enckey = uc(ReadingsVal($name, "enc_key", "A0"));
my $rollingcode = uc(ReadingsVal($name, "rolling_code", "0000")); my $rollingcode = uc(ReadingsVal($name, "rolling_code", "0000"));
$message = "Ys" if($command eq "XX") {
# use user-supplied custom command
$command = $args[1];
}
$message = "s"
. $enckey . $enckey
. $command . $command
. $rollingcode . $rollingcode
@ -268,15 +297,8 @@ sub SOMFY_Set($@) {
Log GetLogLevel( $name, 2 ), "SOMFY set $value: $message"; Log GetLogLevel( $name, 2 ), "SOMFY set $value: $message";
( undef, $value ) = split( " ", $value, 2 ); # Not interested in the name... ( undef, $value ) = split( " ", $value, 2 ); # Not interested in the name...
## Send Message to IODev and wait for correct answer ## Send Message to IODev using IOWrite
my $msg = CallFn( $io->{NAME}, "GetFn", $io, ( " ", "raw", $message ) ); IOWrite( $hash, "Y", $message );
if ( $msg =~ m/raw => Ys$enckey.*/ ) {
Log 4, "Answer from $io->{NAME}: $msg";
}
else {
Log 2, "SOMFY IODev device didn't answer Ys command correctly: $msg";
}
# increment encryption key and rolling code # increment encryption key and rolling code
my $enc_key_increment = hex( $enckey ); my $enc_key_increment = hex( $enckey );
@ -293,8 +315,8 @@ sub SOMFY_Set($@) {
if ( defined( $attr{ $name } ) if ( defined( $attr{ $name } )
&& defined( $attr{ $name }{"symbol-length"} ) ) && defined( $attr{ $name }{"symbol-length"} ) )
{ {
$message = "Yt" . $somfy_defsymbolwidth; $message = "t" . $somfy_defsymbolwidth;
CUL_SimpleWrite( $io, $message ); IOWrite( $hash, "Y", $message );
Log GetLogLevel( $name, 4 ), Log GetLogLevel( $name, 4 ),
"SOMFY set symbol-length back: $message for $io->{NAME}"; "SOMFY set symbol-length back: $message for $io->{NAME}";
} }
@ -303,8 +325,8 @@ sub SOMFY_Set($@) {
if ( defined( $attr{ $name } ) if ( defined( $attr{ $name } )
&& defined( $attr{ $name }{"repetition"} ) ) && defined( $attr{ $name }{"repetition"} ) )
{ {
$message = "Yr" . $somfy_defrepetition; $message = "r" . $somfy_defrepetition;
CUL_SimpleWrite( $io, $message ); IOWrite( $hash, "Y", $message );
Log GetLogLevel( $name, 4 ), Log GetLogLevel( $name, 4 ),
"SOMFY set repetition back: $message for $io->{NAME}"; "SOMFY set repetition back: $message for $io->{NAME}";
} }
@ -328,25 +350,307 @@ sub SOMFY_Set($@) {
foreach my $n ( keys %{ $modules{SOMFY}{defptr}{$code} } ) { foreach my $n ( keys %{ $modules{SOMFY}{defptr}{$code} } ) {
my $lh = $modules{SOMFY}{defptr}{$code}{$n}; my $lh = $modules{SOMFY}{defptr}{$code}{$n};
$lh->{CHANGED}[0] = $value;
$lh->{STATE} = $value;
$lh->{READINGS}{state}{TIME} = $tn;
$lh->{READINGS}{state}{VAL} = $value;
$lh->{READINGS}{enc_key}{TIME} = $tn; $lh->{READINGS}{enc_key}{TIME} = $tn;
$lh->{READINGS}{enc_key}{VAL} = $new_enc_key; $lh->{READINGS}{enc_key}{VAL} = $new_enc_key;
$lh->{READINGS}{rolling_code}{TIME} = $tn; $lh->{READINGS}{rolling_code}{TIME} = $tn;
$lh->{READINGS}{rolling_code}{VAL} = $new_rolling_code; $lh->{READINGS}{rolling_code}{VAL} = $new_rolling_code;
} }
return $ret; return $ret;
} } # end sub SOMFY_SendCommand
###################################
sub SOMFY_CalcNewPos($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $dt = SOMFY_StartTime($hash);
my $move = $hash->{move};
my $oldpos = $hash->{oldpos};
my $newpos = ($move eq 'up')?0:100; # it works anyway
my $timestamp = TimeNow();
# Attributes for calulation
my $t1down100 = AttrVal($name,'drive-down-time-to-100',undef);
my $t1downclose = AttrVal($name,'drive-down-time-to-close',undef);
my $t1upopen = AttrVal($name,'drive-up-time-to-open',undef);
my $t1up100 = AttrVal($name,'drive-up-time-to-100',undef);
if(defined($t1down100) && defined($t1downclose) && defined($t1up100) && defined($t1upopen)) {
# attributes are set
if($move eq 'down') {
$newpos = $oldpos + (100 * $dt / $t1down100);
} elsif($move eq 'up') {
if($oldpos > 100) {
$dt = $dt - $t1up100;
$newpos = $oldpos - (100 * $dt / ($t1upopen - $t1up100));
$newpos = 100 if($newpos > 100), # driven only short between close and pos 100!
} else {
$newpos = $oldpos - (100 * $dt / ($t1upopen - $t1up100));
}
$newpos = 0 if($newpos < 0);
} else {
Log3($name,1,"SOMFY_CalcNewPos: $name move wrong $move");
} # error
} else {
# no attributes set
Log3($name,1,"SOMFY_CalcNewPos $name drive-down-time... attributes not set");
}
# update state
my $value;
if($newpos == 0) {
$value = 'off';
} elsif($newpos > 100) {
$value = 'on';
} else {
$value = 'pos '.SOMFY_Runden($newpos); # for using icons in state
}
$hash->{CHANGED}[0] = $value;
$hash->{STATE} = $value;
$hash->{READINGS}{state}{TIME} = $timestamp;
$hash->{READINGS}{state}{VAL} = $value;
setReadingsVal($hash,'position',$newpos,$timestamp);
# finish move
$hash->{move} = 'stop';
return undef;
} # end sub SOMFY_CalcNewPos
###################################
sub SOMFY_SendStop($) {
my ($hash) = @_;
SOMFY_SendCommand($hash,'stop');
SOMFY_CalcNewPos($hash);
} # end sub SOMFY_SendStop
###################################
sub SOMFY_Runden($) {
my ($v) = @_;
return sprintf("%d", ($v + 5) /10) * 10;
} # end sub SOMFY_Runden
###################################
sub SOMFY_Set($@) {
my ( $hash, $name, @args ) = @_;
my $numberOfArgs = int(@args);
if ( $numberOfArgs < 1 ) {
return "no set value specified" ;
}
my $cmd = lc($args[0]);
my $drivetime = 0; # on/off-for-timer and pos <value> -> move by time
my $updatetime = 0; # move to endpos or go-my / stop -> assume stop = pos 100
my $oldpos = ReadingsVal($name,'position',0);
$hash->{oldpos} = $oldpos; # store it for later recalculation
my $newpos = $args[1];
return "Bad time spec" if($cmd =~m/(on|off)-for-timer/ && $numberOfArgs == 2 && $args[1] !~ m/^\d*\.?\d+$/);
if(($cmd =~m/off/) || ($cmd eq 'pos' && $args[1] == 0)) {
$cmd = 'off';
$hash->{move} = 'up';
$newpos = 0;
$updatetime = (AttrVal($name,'drive-up-time-open',25) - AttrVal($name,'drive-up-time-100',0)) * $oldpos / 100;
} elsif ($cmd =~m/on/) {
$cmd = 'on';
$hash->{move} = 'down';
my $t1 = AttrVal($name,'drive-down-time-to-100',100);
my $t2 = AttrVal($name,'drive-down-time-to-close',100);
$newpos = sprintf("%d",100 * $t2/$t1);
$updatetime = $t1* (1 - ($oldpos / 100)) + ($t2 - $t1);
} elsif($cmd eq 'pos') {
return "bad pos specification" if(!defined($newpos));
return "SOMFY_set: oldpos eq newpos ($newpos" if($newpos == $oldpos);
return "SOMFY_set: $newpos must be > 0 and < 100" if($newpos < 0 || $newpos > 100);
my $t1down = AttrVal($name,'drive-down-time-to-100',undef);
my $t1upopen = AttrVal($name,'drive-up-time-to-open',undef);
my $t1up100 = AttrVal($name,'drive-up-time-to-100',undef);
return "Please set attr drive-down-time-to-100, drive-down-time-to-close, "
. "drive-up-time-to-100 and drive-up-time-to-open before using the pos <value> extension" if(!defined($t1down) || !defined($t1upopen) || !defined($t1up100));
if($newpos > $oldpos) { # down
$cmd = 'on';
$hash->{move} = 'down';
$drivetime = ($t1down * ($newpos - $oldpos) / 100);
} else { # up
$cmd = 'off';
$hash->{move} = 'up';
my $t1 = $t1upopen - $t1up100;
$drivetime = ($t1 * ($oldpos - $newpos) / 100);
}
Log3($name,3,"somfy_set: cmd $cmd newpos $newpos drivetime $drivetime");
} elsif($cmd =~m/stop|go_my/) { # assuming stop = pos 100
$newpos = 100;
$hash->{move} = 'stop';
$hash->{READINGS}{position}{VAL} = 100;
Log3($name,1,"SOMFY_set: Warning: go-my/stop will mess up correct positioning! Please use pos <value> instead.");
} elsif($cmd eq 'on-for-timer') {
$cmd = 'on';
$hash->{move} = 'down';
$drivetime = $args[1];
my $tclose = AttrVal($name,'drive-down-time-to-close',25);
my $tmax = ($oldpos / 100) * $tclose;
if(($tmax + $drivetime) > $tclose) { # limit ?
$drivetime = 0;
$updatetime = $tmax;
}
} elsif($cmd eq 'off-for-timer') {
$cmd = 'off';
$hash->{move} = 'up';
$drivetime = $args[1];
my $topen = AttrVal($name,'drive-up-time-to-open',25);
my $t100 = AttrVal($name,'drive-up-time-to-100',0);
my $tpos = $topen * ($topen / ($topen - $t100)) - ($oldpos / 100);
if(($tpos + $drivetime) > $topen) { # limit ?
$drivetime = 0;
$updatetime = $tpos;
}
} elsif(!exists($sets{$cmd})) {
my @cList;
foreach my $k (sort keys %sets) {
my $opts = undef;
$opts = $sets{$k};
if (defined($opts)) {
push(@cList,$k . ':' . $opts);
} else {
push (@cList,$k);
}
} # end foreach
return "Unknown argument $cmd, choose one of " . join(" ", @cList);
} # error and ? handling
$args[0] = $cmd;
if($drivetime > 0) {
# timer fuer stop starten
RemoveInternalTimer($hash);
Log3($name,3,"SOMFY_set: $name -> stopping in $drivetime sec");
InternalTimer(gettimeofday()+$drivetime,"SOMFY_SendStop",$hash,0);
} elsif($updatetime > 0) {
# timer fuer Update state starten
RemoveInternalTimer($hash);
Log3($name,3,"SOMFY_set: $name -> state update in $updatetime sec");
InternalTimer(gettimeofday()+$updatetime,"SOMFY_CalcNewPos",$hash,0);
} else {
Log3($name,1,"SOMFY_set: Error - drivetime and updatetime = 0");
}
SOMFY_SendCommand($hash,@args);
SOMFY_StartTime($hash);
return undef;
} # end sub SOMFY_setFN
###############################
############################# #############################
sub SOMFY_Parse($$) { sub SOMFY_Parse($$) {
my ($hash, $msg) = @_;
# not implemented yet, since we only support SENDING of somfy commands # Msg format:
# Ys AB 2C 004B 010010
# address needs bytes 1 and 3 swapped
if (substr($msg, 0, 2) eq "Yr" || substr($msg, 0, 2) eq "Yt") {
# changed time or repetition, just return the name
return $hash->{NAME};
}
# get address
my $address = uc(substr($msg, 14, 2).substr($msg, 12, 2).substr($msg, 10, 2));
# get command and set new state
my $cmd = sprintf("%X", hex(substr($msg, 4, 2)) & 0xF0);
if ($cmd eq "10") {
$cmd = "11"; # use "stop" instead of "go-my"
}
my $newstate = $codes{ $cmd };
my $def = $modules{SOMFY}{defptr}{$address};
if($def) {
my @list;
foreach my $name (keys %{ $def }) {
my $lh = $def->{$name};
$name = $lh->{NAME}; # It may be renamed
return "" if(IsIgnored($name)); # Little strange.
# update the state and log it
readingsSingleUpdate($lh, "state", $newstate, 1);
Log3 $name, 4, "SOMFY $name $newstate";
push(@list, $name);
}
# return list of affected devices
return @list;
} else {
Log3 $hash, 3, "SOMFY Unknown device $address, please define it";
return "UNDEFINED SOMFY_$address SOMFY $address";
}
} }
##############################
sub SOMFY_Attr(@) {
my ($cmd,$name,$aName,$aVal) = @_;
my $hash = $defs{$name};
return "\"SOMFY 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 =~/drive-(down|up)-time-to.*/) {
# check name and value
return "SOMFY_attr: value must be >0 and <= 100" if($aVal <= 0 || $aVal > 100);
}
if ($aName eq 'drive-down-time-to-100') {
$attr{$name}{'drive-down-time-to-100'} = $aVal;
$attr{$name}{'drive-down-time-to-close'} = $aVal if(!defined($attr{$name}{'drive-down-time-to-close'}) || ($attr{$name}{'drive-down-time-to-close'} < $aVal));
} elsif($aName eq 'drive-down-time-to-close') {
$attr{$name}{'drive-down-time-to-close'} = $aVal;
$attr{$name}{'drive-down-time-to-100'} = $aVal if(!defined($attr{$name}{'drive-down-time-to-100'}) || ($attr{$name}{'drive-down-time-to-100'} > $aVal));
} elsif($aName eq 'drive-up-time-to-100') {
$attr{$name}{'drive-up-time-to-100'} = $aVal;
} elsif($aName eq 'drive-up-time-to-open') {
$attr{$name}{'drive-up-time-to-open'} = $aVal;
$attr{$name}{'drive-up-time-to-100'} = 0 if(!defined($attr{$name}{'drive-up-time-to-100'}) || ($attr{$name}{'drive-up-time-to-100'} > $aVal));
}
}
return undef;
}
############################# #############################
1; 1;
@ -358,8 +662,8 @@ sub SOMFY_Parse($$) {
<ul> <ul>
The Somfy RTS (identical to Simu Hz) protocol is used by a wide range of devices, The Somfy RTS (identical to Simu Hz) protocol is used by a wide range of devices,
which are either senders or receivers/actuators. which are either senders or receivers/actuators.
As we right now are only able to SEND Somfy commands, but CAN'T receive them, this module currently only Right now only SENDING of Somfy commands is implemented in the CULFW, so this module currently only
supports devices like blinds, dimmers, etc. through a <a href="#CUL">CUL</a> device, so this must be defined first. supports devices like blinds, dimmers, etc. through a <a href="#CUL">CUL</a> device (which must be defined first).
<br><br> <br><br>
@ -416,16 +720,18 @@ sub SOMFY_Parse($$) {
off off
go-my go-my
stop stop
pos value (0..100) # see note
prog # Special, see note prog # Special, see note
on-for-timer on-for-timer
off-for-timer off-for-timer
</pre> </pre>
Examples: Examples:
<ul> <ul>
<code>set rollo_1 on</code><br> <code>set rollo_1 on</code><br>
<code>set rollo_1,rollo_2,rollo_3 on</code><br> <code>set rollo_1,rollo_2,rollo_3 on</code><br>
<code>set rollo_1-rollo_3 on</code><br> <code>set rollo_1-rollo_3 on</code><br>
<code>set rollo_1 off</code><br> <code>set rollo_1 off</code><br>
<code>set rollo_1 pos 50</code><br>
</ul> </ul>
<br> <br>
Notes: Notes:
@ -439,6 +745,12 @@ sub SOMFY_Parse($$) {
instead of reversing the blind.<br> instead of reversing the blind.<br>
This can be used to go to a specific position by measuring the time it takes to close the blind completely. This can be used to go to a specific position by measuring the time it takes to close the blind completely.
</li> </li>
<li>pos value<br>
The position must be between 0 and 100 and the appropriate
attributes drive-down-time-to-100, drive-down-time-to-close,
drive-up-time-to-100 and drive-up-time-to-open must be set.<br>
pos 100 means the blind covers the window (but is not completely shut), 0 means it is completely open.
</li>
</ul> </ul>
</ul> </ul>
<br> <br>
@ -512,6 +824,31 @@ sub SOMFY_Parse($$) {
"ignored=1" special devspec. "ignored=1" special devspec.
</li><br> </li><br>
<a name="drive-down-time-to-100"></a>
<li>drive-down-time-to-100<br>
The time the blind needs to drive down from "open" (pos 0) to pos 100.<br>
In this position, the lower edge touches the window frame, but it is not completely shut.<br>
For a mid-size window this time is about 12 to 15 seconds.
</li><br>
<a name="drive-down-time-to-close"></a>
<li>drive-down-time-to-close<br>
The time the blind needs to drive down from "open" (pos 0) to "close", the end position of the blind.<br>
This is about 3 to 5 seonds more than the "drive-down-time-to-100" value.
</li><br>
<a name="drive-up-time-to-100"></a>
<li>drive-up-time-to-100<br>
The time the blind needs to drive up from "close" (endposition) to "pos 100".<br>
This usually takes about 3 to 5 seconds.
</li><br>
<a name="drive-up-time-to-open"></a>
<li>drive-up-time-to-open<br>
The time the blind needs drive up from "close" (endposition) to "open" (upper endposition).<br>
This value is usually a bit higher than "drive-down-time-to-close", due to the blind's weight.
</li><br>
</ul> </ul>
<br> <br>