From 83bc36e2b4cea3aa236f68ece1517b75207bb1c0 Mon Sep 17 00:00:00 2001 From: sidey79 Date: Thu, 16 Jul 2020 20:16:24 +0000 Subject: [PATCH] 10_FS10.pm: perlcritic updates / moved out of main package git-svn-id: https://svn.fhem.de/fhem/trunk@22413 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/10_FS10.pm | 914 +++++++++++++++++++++++-------------------- 1 file changed, 484 insertions(+), 430 deletions(-) diff --git a/fhem/FHEM/10_FS10.pm b/fhem/FHEM/10_FS10.pm index 6fc549d1f..790240f60 100644 --- a/fhem/FHEM/10_FS10.pm +++ b/fhem/FHEM/10_FS10.pm @@ -1,372 +1,424 @@ ############################################## # $Id$ # -# FS10 basierend auf dem FS20 Modul (FHEM 5.3), elektron-bbs +# 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 main; +package FS10; use strict; use warnings; +use GPUtils qw(GP_Import GP_Export); -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", +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 + )) +}; -use vars qw(%fs10_c2b); # Peter would like to access it from outside +# 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', + FS10_ST => 'simple', + FS10_DI => 'dimmer', + FS10_HD => 'dimmer', + FS10_SA => 'timer', + FS10_MS => 'simple', + FS10_S4 => 'remote', + FS10_S8 => 'remote', ); - -sub -FS10_Initialize($) -{ - my ($hash) = @_; - - foreach my $k (keys %codes) { - $fs10_c2b{$codes{$k}} = $k; - } - - $hash->{Match} = '^P61#[a-fA-F0-9]{8,12}'; - $hash->{SetFn} = "FS10_Set"; - $hash->{DefFn} = "FS10_Define"; - $hash->{UndefFn} = "FS10_Undef"; - $hash->{ParseFn} = "FS10_Parse"; - $hash->{AttrList} = "IODev follow-on-for-timer:1,0 follow-on-timer ". - "do_not_notify:1,0 repetition ". - "ignore:1,0 dummy:1,0 showtime:1,0 ". - "$readingFnAttributes " . - "model:".join(",", sort keys %models); +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 -FS10_Set($@) -{ - my ($hash, $name, @a) = @_; - - my $ret = undef; - my $na = int(@a); # Anzahl in Array - #Log3 $name, 3, "FS10: na $na"; +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 - 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 $list .= "off:noArg on:noArg " if ($modelType ne "remote" ); - - $list .= "dimup dimdown " if ($modelType eq "dimmer" ); - - return SetExtensions($hash, $list, $name, @a) if( $a[0] eq "?" ); - return SetExtensions($hash, $list, $name, @a) if( !grep( $_ =~ /^\Q$a[0]\E($|:)/, split( ' ', $list ) ) ); - - my $setstate = $a[0]; - my $sum = 0; - my $temp = ""; - 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', '1'); - my $io = $hash->{IODev}; - my $iNum = 2; - - if ($na > 1 && $setstate =~ m/dim/) { # Anzahl dimup / dimdown - $iNum += $a[1]; - Log3 $name, 3, "$io->{NAME} FS10_set: $name $setstate $a[1]"; - } - else { - Log3 $name, 3, "$io->{NAME} FS10_set: $name $setstate"; - } - Log3 $name, 4, "$io->{NAME} FS10_set: $name: hc=$housecode ebeneHL=$ebeneh $ebenel setstate=$setstate"; - - for my $i (1..$iNum) { - if ($i == 1) { - $kc = $fs10_c2b{$setstate."_1"}; - } - else { - $kc = $fs10_c2b{$setstate."_2"}; - } - $kc = $kc & 7; - if (defined($kc)) { - Log3 $name, 4, "$io->{NAME} FS10_set: $name $i. setstate=$setstate kc=$kc"; - - my $newmsg = "P61#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; - - if ($sum >= 11) { # 6. Summe - $temp = 18 - $sum; - } else { - $temp = 10 - $sum; - } - $newmsg .= dec2nibble($temp); - - $newmsg .= "#R" . $SignalRepeats; - - IOWrite($hash, 'sendMsg', $newmsg); - - Log3 $name, 4, "$io->{NAME} FS10_set: $i.sendMsg=$newmsg"; - - #if ($i < $iNum) { - # IOWrite($hash, 'raw', 'SR;R=1;P0=-32000;D=0000;') - #} - } - } - - ########################################### - # 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, "$io->{NAME} 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; - } - } - - readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "state", $setstate); - readingsEndUpdate($hash, 1); # Notify is done by Dispatch - - return $ret; + 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 -FS10_Define($$) -{ - my ($hash, $def) = @_; - my @a = split("[ \t][ \t]*", $def); +sub Set { + my ($hash, $name, @a) = @_; + my $ioname = $hash->{IODev}{NAME}; + my $ret = undef; + my $na = int @a; # Anzahl in Array - my $u = "wrong syntax: define FS10 housecode_button"; + 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})); - return $u if(int(@a) < 3); - - my ($housecode, $btncode) = split("_", $a[2], 2); - - return "Define $a[0]: wrong syntax: housecode_button" - if (!defined($housecode) || !defined($btncode)); - - return "Define $a[0]: wrong housecode format: specify a 1 digit value [1-8]" - if ($housecode !~ m/^[1-8]$/i ); - - return "Define $a[0]: wrong button format: specify a 2 digit value [0-7]" - if ($btncode !~ m/^[0-7]{2}$/i ); # Ebene Low, Ebene High + 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 ' }; - $hash->{HC} = $housecode; - $hash->{BTN} = $btncode; + 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 $name = $a[0]; - $hash->{CODE} = $a[2]; - #$hash->{lastMSG} = ""; - $modules{FS10}{defptr}{$a[2]} = $hash; + 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#'; - AssignIoPort($hash); + 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 -FS10_Undef($$) -{ - my ($hash, $name) = @_; - delete($modules{FS10}{defptr}{$hash->{CODE}}) - if(defined($hash->{CODE}) && - defined($modules{FS10}{defptr}{$hash->{CODE}})); - return undef; +sub Define { + # define FS10 _