############################################## # $Id$ # # FS10 basierend auf dem FS20 Modul angepasst fuer SIGNALduino, elektron-bbs # # 2020-06-06 Ueberarbeitung PBP # 2020-04-28 Einschraenkung bei Kommando "attr FS10_x_xx repetition x" auf gueltige Werte 1 - 9 # 2019-03-23 Forward declarations and rename subs # 2018-04-28 FS10_Define IO-Device kann angegeben werden # 2017-11-25 FS10_Set Checksumme fuer Wiederholung wurde falsch berechnet # Pause zwischen Wiederholung jetzt immer 200 mS # SignalRepeats jetzt auch im Abstand von 200 mS # Anzahl Wiederholungen bei Dimm-Befehlen korrigiert # Anzahl Dimup/Dimdown auf 1-10 begrenzt # FS10_Initialize Anzahl Wiederholungen auf 1 bis 9 begrenzt package FS10; use strict; use warnings; use GPUtils qw(GP_Import GP_Export); our $VERSION = '1.1'; # Export to main context with different name GP_Export(qw( Initialize ) ); # Import der FHEM Funktionen BEGIN { GP_Import(qw( AssignIoPort AttrVal attr CommandDefine CommandDelete IOWrite IsDummy IsIgnored Log3 modules SetExtensions readingsSingleUpdate )) }; # Forward declarations sub nibble2dec; sub dec2nibble; my %fs10_c2b; # reverse codes my %codes = ( '0' => 'off_1', '2' => 'off_2', '1' => 'on_1', '3' => 'on_2', '8' => 'dimdown_1', # 0 | 8 = 8 '4' => 'dimdown_2', '9' => 'dimup_1', # 1 | 8 = 9 '5' => 'dimup_2', ); my %models = ( FS10_ST => 'simple', FS10_DI => 'dimmer', FS10_HD => 'dimmer', FS10_SA => 'timer', FS10_MS => 'simple', FS10_S4 => 'remote', FS10_S8 => 'remote', ); sub Initialize { my ($hash) = @_; for my $k (keys %codes) { $fs10_c2b{$codes{$k}} = $k; # reverse codes } $hash->{Match} = '^P61#[a-fA-F0-9]{8,12}'; $hash->{SetFn} = \&Set; $hash->{DefFn} = \&Define; $hash->{UndefFn} = \&Undef; $hash->{ParseFn} = \&Parse; $hash->{AttrFn} = \&Attr; $hash->{AttrList} = 'IODev follow-on-for-timer:1,0 follow-on-timer '. 'do_not_notify:1,0 repetition:1,2,3,4,5,6,7,8,9 '. 'ignore:1,0 dummy:1,0 showtime:1,0 '. "$main::readingFnAttributes " . 'model:'.join q{,} , sort keys %models; $hash->{AutoCreate} = {'FS10.*' => {FILTER => '%NAME', autocreateThreshold => '5:180', GPLOT => q{}}}; return } sub Attr { my ( $cmd, $name, $attrName, $attrValue ) = @_; # $cmd - Vorgangsart, kann die Werte "del" (loeschen) oder "set" (setzen) annehmen # $name - Geraetename # $attrName - Attribut-Name # $attrValue - Attribut-Wert if ($cmd eq 'set') { if ($attrName eq 'repetition') { if ($attrValue !~ m/^[1-9]$/xms) { return "$name: Unallowed value $attrValue for the attribute repetition (must be 1 - 9)!" }; } } return; } sub Set { my ($hash, $name, @a) = @_; my $ioname = $hash->{IODev}{NAME}; my $ret = undef; my $na = int @a; # Anzahl in Array return 'no set value specified' if ($na < 1); # if ($na < 2 || $na > 3); return "Dummydevice $hash->{NAME}: will not set data" if (IsDummy($hash->{NAME})); my $model = AttrVal($name, 'model', 'FS10_ST'); my $modelType = $models{$model}; my $alias = AttrVal($name, 'alias', q{}); my $list; if ($modelType ne 'remote') { $list .= 'off:noArg on:noArg ' }; if ($modelType eq 'dimmer' ) { $list .= 'dimup:1,2,3,4,5,6,7,8,9,10 dimdown:1,2,3,4,5,6,7,8,9,10 ' }; return SetExtensions($hash, $list, $name, @a) if ( $a[0] eq q{?} ); return SetExtensions($hash, $list, $name, @a) if ( !grep { /^\Q$a[0]\E($|:)/xms } split q{ } , $list ); my $setstate = $a[0]; my $ebeneh = substr $hash->{BTN}, 0, 1; my $ebenel = substr $hash->{BTN}, 1, 1; my $housecode = $hash->{HC} - 1; my $kc; my $SignalRepeats = AttrVal($name,'repetition', '0') + 1; my $dimm = 0; my $newmsg = 'P61#'; if ($model eq 'FS10_MS') { $SignalRepeats = 1; } if ($SignalRepeats > 10) { $SignalRepeats = 10; } if ($na > 1 && $setstate =~ m/dim/xms) { # Anzahl dimup / dimdown $dimm += $a[1]; if ($dimm < 1 || $dimm > 10) { Log3 $name, 1, "$ioname: FS10 set $name $setstate $dimm - ERROR dimm value too low or high (1-10)"; return "FS10 set $name $setstate $dimm - ERROR: dimm value too low or high (1-10)"; } else { Log3 $name, 3, "$ioname: FS10 set $name $setstate $dimm $alias"; } } else { Log3 $name, 3, "$ioname: FS10 set $name $setstate $alias"; } Log3 $name, 5, "$ioname: FS10 set $name hc=$housecode ebeneHL=$ebeneh$ebenel setstate=$setstate"; for my $i (1..2) { my $sum = 0; $kc = $fs10_c2b{$setstate . '_' . $i}; $kc = $kc & 7; if (defined $kc) { Log3 $name, 5, "$ioname: FS10 set $name setstate$i=$setstate command=$kc"; $newmsg .= '0000000000001'; # 12 Bit Praeambel, 1 Pruefbit $newmsg .= dec2nibble($kc); # 1. setstate $sum += $kc; $newmsg .= dec2nibble($ebenel); # 2. Ebene low $sum += $ebenel; $newmsg .= dec2nibble($ebeneh); # 3. Ebene high $sum += $ebeneh; $newmsg .= '10001'; # 4. unused $newmsg .= dec2nibble($housecode); # 5. housecode $sum += $housecode; $sum = (10 - $sum) & 7; $newmsg .= dec2nibble($sum); # 6. Summe if ($dimm == 0) { # ein / aus if ($i == 1) { # 1. Teil Nachricht $newmsg .= 'PPP'; # 3*32400=97200 Pause } else { # 2. Teil Nachricht if ($SignalRepeats == 1) { $newmsg .= '#R1'; # 1 Repeat } else { $newmsg .= 'PPPPPP#R' . $SignalRepeats; # 6*32400=194400 Pause . Repeats } } } else { # dimmen if ($i == 1) { # 1. Nachricht $newmsg .= 'PPPPPPPPPPPPPPPP'; # 16*32400=518400 Pause . 1 Repeat (original remote control) if ($dimm >= 2) { $newmsg .= '#R1'; IOWrite($hash, 'sendMsg', $newmsg); Log3 $name, 5, "$ioname: FS10 set dimm $dimm, 1. sendMsg=$newmsg"; $newmsg = 'P61#'; # Reset newmsg fuer 2. Nachricht } } else { # 2. Nachricht if ($dimm == 1) { $newmsg .= '#R1'; # 1 Repeat } else { $newmsg .= 'PPPPPP#R' . $dimm; # 6*32400=194400 Pause . Repeats Log3 $name, 5, "$ioname: FS10 set dimm $dimm, 2. sendMsg=$newmsg"; } } } if ($i == 2) { # 2. Nachricht Log3 $name, 5, "$ioname: FS10 set sendMsg=$newmsg"; IOWrite($hash, 'sendMsg', $newmsg); } } } # Set the state of a device to off if on-for-timer is called if ($modules{FS10}{ldata}{$name}) { CommandDelete(undef, $name . '_timer'); delete $modules{FS10}{ldata}{$name}; } # following timers if ($setstate eq 'on' && AttrVal($name, 'follow-on-for-timer', 0)) { my $dur = AttrVal($name, 'follow-on-timer', 0); if ($dur > 0) { my $newState = 'off'; my $to = sprintf '%02d:%02d:%02d', $dur/3600, ($dur%3600)/60, $dur%60; Log3 $name, 3, "$ioname: FS10_set $name Set_Follow +$to setstate $newState"; CommandDefine(undef, $name."_timer at +$to "."setstate $name $newState; trigger $name $newState"); $modules{FS10}{ldata}{$name} = $to; } } readingsSingleUpdate($hash, 'state', $setstate, 1); return $ret; } sub Define { # define FS10 _