diff --git a/fhem/FHEM/98_Siro.pm b/fhem/FHEM/98_Siro.pm index b7b4c4f57..79c9c84f2 100644 --- a/fhem/FHEM/98_Siro.pm +++ b/fhem/FHEM/98_Siro.pm @@ -3,69 +3,10 @@ # Siro module for FHEM # Thanks for templates/coding from SIGNALduino team and Jarnsen_darkmission_ralf9 # -# Needs SIGNALduino >= V3.3.1-dev (10.03.2017). +# Needs SIGNALduino. # Published under GNU GPL License, v2 # History: - -# 0.01 2017-05-24 Smag Decoding/sniffing signals, Binary-keycode-decoding for on, off, stop, favourite and p2 (pairing). -# 0.02 2017-05-25 Smag Tests with CUL/COC and Signalduino. Successful signalrepeat to device via Signalduino. -# 0.03 2017-07-23 Smag initial template -# 0.04 2017-07-24 Smag Changed binary device-define to much more easier hex-code (28bit+channel). -# 0.10 2017-07-30 Smag Siro-Parse implemented. First alpha-version went out for Byte09 and det -# 0.11 2017-07-30 Smag, Byte09 updated module -# 0.12 2017-08-02 Byte Subroutine X_internaltset komplett entfernt, Zusammenlegung mit X_set -# Byte Variablen bereinigt -# Byte Code bereinigt -# Byte Einführung "readings", "lastmsg" und "aktMsg" inkl. Unixtime -# 0.13 2017-08-03 Byte Senden eines doppelten Stoppbefehls abgefangen, keine Hardwaremittelanfahrt durch zweimaliges Stopp mehr möglich -# 0.14 2017-08-04 Byte Attr SignalLongStopRepeats eingeführt. Anzahl der Repeats für Longstop (Favourite). undef = 15 -# 0.15 2017-08-05 Byte Attr "timer" eingeführt. Enthält die Zeit zwischen zwei ausgeführten Befehlen zur Positionsberechnung -# 0.16 2017-08-06 Byte Berechnung der aktuellen Position nach Stop-Kommando - Darstellung im state bzw. im Slider -# 0.17 2017-08-09 Byte Fehler bei der Positionsfahrt aus der Fav-Position behoben -# 0.18 2017-08-10 Byte Änderung des State bei Empfang von FB integriert -# 0.19 2017-08-12 Byte Attr 'position_adjust' abgeschafft -# 0.20 2017-08-12 Attr 'operation_mode' eingeführt -# 0 Normaler Modus : Keine 'position_adjust' - Fahrt über 0 -# 1 Normaler Modus : Positionsanfahrt immer -> 'position_adjust' - Fahrt über 0 -# 2 Repeater Modus : Modul empfängt die FB und leitet es an den Motor weiter. Motor empfängt die FB nicht direkt. -# Kanalanpassung notwendig. Zuverlässigster Betrieb! -# 0.21 2017-08-13 Smag: Code-Cleanup. Spellcheck. Documentation -# 0.22 2017-08-18 Byte: Kompletten Code überarbeitet. Laufzeitoptimierung. Reaktionszeit verbessert. Unnötige Readings in die Internals verlagert. Fehler bei direktem umschalten behoben. -# Operation_mode 1 komplett entfernt, om 2 ist nun om 1. Operationmode 1 bis Fertigstellung deaktiviert -# 0.23 Beta Byte V0.22 - > V1.0 Beta -# 0.24 2017-08-20 Byte Positionsanfahrt über Alexa möglich - "schalte DEVICE XX%" -# Operation_mode 1 eingeführt. ( Repeatermodus ) -# 0.25 2017-08-26 Byte diverse Korrekturen, Codebereinigung, Anfahrt der HW_Favorit Position über FB im Mode 1 möglich -# 0.26 2017-08-26 Byte Commandref Deutsch hinzugefügt -# 0.27 2017-08-29 Byte Define von Devices, die eine Kanal nutzen der bereits von einem Device genutzt wird (channel / send_channel_mode1) wird unterbunden -# Debug_Attr (0/1) eingefügt - es werden diverse redings angelegt und kein Befehl physisch anden Rollo gesendet - nur Fehlersuche -# 0.28 2017-09-02 ByteFehler bei Stateaktualisierung in Zusammenhang mit Stop bei Favoritenanfahrt behoben -# 0.29 2017-08-29 Byte Define von Devices, die einen Kanal nutzen, der bereits von einem Device genutzt wird (channel / send_channel_mode1) wird unterbunden -# Debug_Attr (0/1) eingefügt - es werden diverse redings angelegt und kein Befehl physisch anden Rollo gesendet - nur Fehlersuche -# Set favorite und Attr prog_fav_sequence eingeführt - programmierung derHardware_Favorite_Position -# Codebereinigung -# Allgemeine Fehler behoben -# 0.30 2017-09-09 Byte Betrieb in eingeschränkter Funktion ohne 'time'- Attribute möglich -# 0.31 2017-09-10 Byte Commandref ergänzt Deutsch/Englisch -# 0.32 2017-09-16 Byte Fehlerkorrekturen -# 0.34 2017-09-17 Invers Dokumentation, Byte Korrekturen Log -# 0.35 2017-09-24 Byte Fehlerkorrekturen , Einbau Device mit Kanal 0 als Gruppendevice ( noch gesperrt ) . Attribut "channel" enfernt , Kanalwahl nur noch über das Device möglich . -# 0.36 2017-09-24 Byte Device0 Favoritenanfahrt und Positionsanfahrt durch FHEM möglich -# 0.37 2017-09-25 SMag Prerelease-Vorbereitungen. Codeformatierung, Fehlerkorrekturen, Textkorrekturen. -# 0.38 2017-09-27 optimierung sub Siro_Setgroup($) -> laufzeitverbesserung -# -# 0.39 2017-10-14 Byte Log überarbeitet / Parse überarbeitet / Define überarbeitet / interne Datenstruktur geändert / Internals überarbeitet / Groupdevice ( Kanal 0 ) möglich . Fehlerkorrekturen / attribut down_for_timer und up_for_timer eingebaut -# 0.40 2017-10-15 Byte Code bereinigt -# 0.41 2017-10-17 Byte anpassung der %Sets je nach device ( groupdevice ) -# 0.42 2017-10-18 Byte attr "down_auto_stop" eingefügt - beendet runterfahrt durch on/close/fb bei ATTR weiterfahrt durch nochmalige cmd . Comandref ergänzt -# 0.43 2017-10-19 Byte attr "invers_position[0/1]" eingefügt. Invertiert positionsanzeige und anfahrt 0 -> 100% = rollo geschlossen - 1 -> 0% =rollo geschlossen -# 0.44 2017-10-19 Byte bugfix -> set favorite. Unterscheidung ob "time_down_to_favorite" gesetzt oder nicht. ( interpretation :favorite programmiert oder nicht ) - entsprechende anpassung des kommandos ( erst löschen -> dann speichern ) -# 0.45 2017-10-28 Byte fehler bei erneutem Kommando während Positionsanfahrten behoben -# 0.46 2017-05-11 Byte fehler bei fhem-neustart behoben -# 0.47 2017-11-11 Byte attr Disable zugefügt. -# 0.47 2017-02-12 Byte/Dr Smag Quickfix ERB15LE -# 0.48 2018-26-01 Byte New Readings 'operating_seconds' / 'last_reset_os' -# 0.49 2018-03-03 Byte Fix for Signalduino V 3.3.1-RC2 SIGNALduino cc1101 +# 30.05.19 Version 1.0 innitial comit ################################################################################################################ # Todo's: # - @@ -76,7 +17,117 @@ package main; use strict; use warnings; -my $version = "V 0.49"; +my $version = "1.0"; + + +sub Siro_Initialize($) { + my ($hash) = @_; + + $hash->{SetFn} = "FHEM::Siro::Set"; + $hash->{NotifyFn} = "FHEM::Siro::Notify"; + $hash->{ShutdownFn} = "FHEM::Siro::Shutdown"; + $hash->{FW_deviceOverview} = 1; + $hash->{FW_detailFn} = "FHEM::Siro::fhemwebFn"; + $hash->{DefFn} = "FHEM::Siro::Define"; + $hash->{UndefFn} = "FHEM::Siro::Undef"; + $hash->{DeleteFn} = "FHEM::Siro::Delete"; + $hash->{ParseFn} = "FHEM::Siro::Parse"; + $hash->{AttrFn} = "FHEM::Siro::Attr"; + $hash->{Match} = "^P72#[A-Fa-f0-9]+"; + $hash->{AsyncOutput} = "FHEM::Siro::AsyncOutput"; + $hash->{AttrList} = + " IODev" + . " disable:0,1" + . " SIRO_signalRepeats:1,2,3,4,5,6,7,8,9" + . " SIRO_inversPosition:0,1" + . " SIRO_Battery_low" + . " SIRO_signalLongStopRepeats:10,15,20,40,45,50" + . " $readingFnAttributes" + . " SIRO_send_channel:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15" + + + + . " SIRO_send_id" + . " SIRO_time_to_open" + . " SIRO_time_to_close" + . " SIRO_debug:0,1" + + #oldversion entfernen mit kommender version + # . " SIRO_channel:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15" + . " SignalRepeats:1,2,3,4,5,6,7,8,9" + . " SignalLongStopRepeats:10,15,20,40,45,50" + . " channel_send_mode_1:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15" + . " $readingFnAttributes" + . " setList" + . " ignore:0,1" + . " dummy:1,0" + . " time_to_open" + . " time_to_close" + . " time_down_to_favorite" . " hash" + . " operation_mode:0,1" + . " debug_mode:0,1" + . " down_limit_mode_1:slider,0,1,100" + . " down_auto_stop:slider,0,1,100" + . " invers_position:0,1" + . " prog_fav_sequence"; + + + + + + $hash->{AutoCreate} = { + "Siro.*" => { + ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", + FILTER => "%NAME", + autocreateThreshold => "2:10" + } + }; + + $hash->{NOTIFYDEV} = "global"; + FHEM::Siro::LoadHelper($hash) if ($init_done); +} + + +################################################################# + + +#### arbeiten mit packages +package FHEM::Siro; + +use strict; +use warnings; + +use GPUtils qw(GP_Import) + ; # wird fuer den Import der FHEM Funktionen aus der fhem.pl ben?tigt + + +## Import der FHEM Funktionen +BEGIN { + GP_Import( + qw(readingsSingleUpdate + readingsBeginUpdate + readingsEndUpdate + readingsBulkUpdate + defs + modules + Log3 + AttrVal + ReadingsVal + IsDisabled + gettimeofday + InternalTimer + RemoveInternalTimer + AssignIoPort + IOWrite + ReadingsNum + CommandAttr + attr + fhem + ) + + ); +} + my %codes = ( "55" => "stop", # Stop the current movement or move to custom position @@ -88,95 +139,60 @@ my %codes = ( my %sets = ( "open" => "noArg", "close" => "noArg", + "up" => "noArg", + "down" => "noArg", "off" => "noArg", "stop" => "noArg", "on" => "noArg", "fav" => "noArg", - "prog" => "noArg", - "prog_stop" => "noArg", - "position" => - "slider,0,1,100", # Wird nur bei vorhandenen time_to attributen gesetzt + "prog" => "noArg", + "sequenz" => "noArg", + "prog_mode_on" => "noArg", + "prog_mode_off" => "noArg", + "reset_motor_term" => "noArg", + "pct" => "slider,0,1,100", # Wird nur bei vorhandenen time_to attributen gesetzt "state" => "noArg", "set_favorite" => "noArg", + "del_favorite" => "only_modul,only_shutter,shutter_and_modul", "down_for_timer" => "textField", - "reset_operating_seconds" => "noArg", - "up_for_timer" => "textField", + "up_for_timer" => "textField" ); my %sendCommands = ( - "off" => "off", + "pct" => "level", + "level" => "level", "stop" => "stop", + "off" => "off", "on" => "on", "open" => "off", "close" => "on", + "up" => "off", + "down" => "on", "fav" => "fav", "prog" => "prog", - "set_favorite" => "setfav" + "reset_motor_term" => "reset_motor_term", + "up_for_timer" => "upfortimer", + "down_for_timer" => "downfortimer" + ); my %siro_c2b; - -my %models = ( - siroblinds => 'blinds', - siroshutter => 'shutter' -); - -################################################################# -sub Siro_Initialize($) { - my ($hash) = @_; - - # Map commands from web interface to codes used in Siro - foreach my $k ( keys %codes ) { - $siro_c2b{ $codes{$k} } = $k; - } - $hash->{SetFn} = "Siro_Set"; - $hash->{NotifyFn} = "Siro_Notify"; - $hash->{ShutdownFn} = "Siro_Shutdown"; - - #$hash->{StateFn} = "Siro_SetState"; #change - $hash->{DefFn} = "Siro_Define"; - $hash->{UndefFn} = "Siro_Undef"; - $hash->{DeleteFn} = "Siro_Delete"; - $hash->{ParseFn} = "Siro_Parse"; - $hash->{AttrFn} = "Siro_Attr"; - $hash->{Match} = "^P72#[A-Fa-f0-9]+"; - $hash->{AttrList} = - " IODev" - . " disable:0,1" - . " SignalRepeats:1,2,3,4,5,6,7,8,9" - . " SignalLongStopRepeats:10,15,20,40,45,50" - . " channel_send_mode_1:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15" - . " $readingFnAttributes" - . " setList" - . " ignore:0,1" - . " dummy:1,0" - - # . " model:siroblinds,siroshutter" - . " time_to_open" - . " time_to_close" - . " time_down_to_favorite" . " hash" - . " operation_mode:0,1" - . " debug_mode:0,1" - . " down_limit_mode_1:slider,0,1,100" - . " down_auto_stop:slider,0,1,100" - . " invers_position:0,1" - . " prog_fav_sequence"; - - $hash->{AutoCreate} = { - "Siro.*" => { - ATTR => "event-min-interval:.*:300 event-on-change-reading:.*", - FILTER => "%NAME", - autocreateThreshold => "2:10" - } - }; - - $hash->{NOTIFYDEV} = "global"; - Siro_LoadHelper($hash) if ($init_done); +# Map commands from web interface to codes used in Siro +foreach my $k ( keys %codes ) { + $siro_c2b{ $codes{$k} } = $k; } +###################### +sub Attr(@) { + my ( $cmd, $name, $aName, $aVal ) = @_; + my $hash = $defs{$name}; + return "\"Siro Attr: \" $name does not exist" if ( !defined($hash) ); + +return; +} ################################################################# -sub Siro_Define($$) { +sub Define($$) { my ( $hash, $def ) = @_; my @a = split( "[ \t][ \t]*", $def ); @@ -190,7 +206,7 @@ sub Siro_Define($$) { if ( $a[2] =~ m/^[A-Fa-f0-9]{8}$/i ) { $hash->{ID} = uc( substr( $a[2], 0, 7 ) ); - $hash->{CHANNEL} = sprintf( "%d", hex( substr( $a[2], 7, 1 ) ) ); + $hash->{CHANNEL_RECEIVE} = sprintf( "%d", hex( substr( $a[2], 7, 1 ) ) ); $askedchannel = sprintf( "%d", hex( substr( $a[2], 7, 1 ) ) ); } else { @@ -198,94 +214,30 @@ sub Siro_Define($$) { "Define $a[0]: wrong address format: specify a 8 char hex value (id=7 chars, channel=1 char) . Example A23B7C51. The last hexchar identifies the channel. -> ID=A23B7C5, Channel=1. "; } - my $test; - my $device; - my $chanm1; - my $chan; - my @channels = ( '', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ); - my @testchannels; # Enthält alle Kanäle die in Benutzung sind - my @keys; - my @values; - my $testname; - $hash->{Version} = $version; my $name = $a[0]; - - # Log3($name, 0, "Siro_define: $hash->{helper}{position} "); - # if ($hash->{helper}{position} eq '') - # { - # $hash->{helper}{position}="0"; - # $hash->{helper}{aktMsg} = "stop".' '.'0'.' '.gettimeofday(); - # $hash->{helper}{lastMsg} = "stop".' '.'0'.' '.gettimeofday(); - # $hash->{helper}{lastProg} ="0"; - # $hash->{helper}{lastparse_stop} ="stop".' '.gettimeofday(); - # $hash->{helper}{lastparse} =""; - # $hash->{helper}{parse_aborted} ="0"; - # } - - my $tn = TimeNow(); #Wird wohl nicht benötigt?!?! down_limit_mode_1 - - if ( $askedchannel ne "0" ) { - - #Setzen der vordefinierten Attribute - $attr{$name}{devStateIcon} = - "{return '.*:fts_shutter_1w_'.(int(\x{24}state/10)*10)}" - if ( !defined( $attr{$name}{devStateIcon} ) ); #TMP_Byte09 !defined - - $attr{$name}{webCmd} = "stop:on:off:fav:position" - if ( !defined( $attr{$name}{webCmd} ) ); - $attr{$name}{down_limit_mode_1} = "100" - if ( !defined( $attr{$name}{down_limit_mode_1} ) ); - $attr{$name}{prog_fav_sequence} = "prog,2,stop,2,stop" - if ( !defined( $attr{$name}{prog_fav_sequence} ) ); - - #$attr{$name}{room} ="Siro" if (!defined ($attr{$name}{genericDeviceType})); - $attr{$name}{SignalLongStopRepeats} = "15" - if ( !defined( $attr{$name}{SignalLongStopRepeats} ) ); - $attr{$name}{SignalRepeats} = "8" - if ( !defined( $attr{$name}{SignalRepeats} ) ); - $attr{$name}{operation_mode} = "0" - if ( !defined( $attr{$name}{operation_mode} ) ); - $attr{$name}{down_auto_stop} = "100" - if ( !defined( $attr{$name}{down_auto_stop} ) ); - $attr{$name}{invers_position} = "0" - if ( !defined( $attr{$name}{invers_position} ) ); - } - else { - $attr{$name}{devStateIcon} = - "{return '.*:fts_shutter_1w_'.(int(\x{24}state/10)*10)}" - if ( !defined( $attr{$name}{devStateIcon} ) ); #TMP_Byte09 !defined - $attr{$name}{webCmd} = "stop:on:off:fav:position" - if ( !defined( $attr{$name}{webCmd} ) ); - - #$attr{$name}{room} ="Siro" if (!defined ($attr{$name}{genericDeviceType})); - $attr{$name}{SignalLongStopRepeats} = "15" - if ( !defined( $attr{$name}{SignalLongStopRepeats} ) ); - $attr{$name}{SignalRepeats} = "8" - if ( !defined( $attr{$name}{SignalRepeats} ) ); - - #$attr{$name}{SignalRepeats} ="2"; - $attr{$name}{down_auto_stop} = "100" - if ( !defined( $attr{$name}{down_auto_stop} ) ); - $attr{$name}{invers_position} = "0" - if ( !defined( $attr{$name}{invers_position} ) ); - } my $code = uc( $a[2] ); my $ncode = 1; - my $devpointer = $hash->{ID} . $hash->{CHANNEL}; + my $devpointer = $hash->{ID} . $hash->{CHANNEL_RECEIVE}; $hash->{CODE}{ $ncode++ } = $code; + $hash->{MODEL} = "LE-serie"; $modules{Siro}{defptr}{$devpointer} = $hash; + AssignIoPort($hash); + + CommandAttr( undef,$name . ' devStateIcon {if (ReadingsVal( $name, \'state\', \'undef\' ) =~ m/[a-z]/ ) { return \'programming:edit_settings notAvaible:hue_room_garage runningUp.*:fts_shutter_up runningDown.*:fts_shutter_down\'}else{return \'[0-9]{1,3}:fts_shutter_1w_\'.(int($state/10)*10)}}' ) + if ( AttrVal($name,'devStateIcon','none') eq 'none' ); - Log3( $name, 5, -"Siro_define: angelegtes Device - code -> $code name -> $name hash -> $hash " + CommandAttr(undef,$name . ' webCmd stop:open:close:fav:pct') + if ( AttrVal($name,'webCmd','none') eq 'none' ); + + + Log3( $name, 5, "Siro_define: angelegtes Device - code -> $code name -> $name hash -> $hash " ); - - AssignIoPort($hash); } ################################################################# -sub Siro_Undef($$) { +sub Undef($$) { my ( $hash, $name ) = @_; delete( $modules{Siro}{defptr}{$hash} ); @@ -293,102 +245,34 @@ sub Siro_Undef($$) { } ################################################################# -sub Siro_Shutdown($) { +sub Shutdown($) { my ($hash) = @_; my $name = $hash->{NAME}; - - readingsSingleUpdate( $hash, ".aktMsg", $hash->{helper}{aktMsg}, 0 ); - readingsSingleUpdate( $hash, ".lastMsg", $hash->{helper}{lastMsg}, 0 ); - readingsSingleUpdate( $hash, ".lastProg", $hash->{helper}{lastProg}, 0 ); - readingsSingleUpdate( $hash, ".lastparse", $hash->{helper}{lastparse}, 0 ); - readingsSingleUpdate( $hash, ".lastparse_stop", - $hash->{helper}{lastparse_stop}, 0 ); - readingsSingleUpdate( $hash, ".parse_aborted", - $hash->{helper}{parse_aborted}, 0 ); - readingsSingleUpdate( $hash, ".positionsave", $hash->{helper}{position}, - 0 ); - readingsSingleUpdate( $hash, ".positiontimer", - $hash->{helper}{positiontimer}, 0 ); - return; } ################################################################# -sub Siro_LoadHelper($) { +sub LoadHelper($) { my ($hash) = @_; my $name = $hash->{NAME}; - - my $save = ReadingsVal( $name, '.aktMsg', 'undef' ); - if ( $save eq 'undef' ) { - Log3( $name, 5, "Siro: Helper lade new device" ); - $hash->{helper}{position} = "0"; - $hash->{helper}{aktMsg} = "stop" . ' ' . '0' . ' ' . gettimeofday(); - $hash->{helper}{lastMsg} = "stop" . ' ' . '0' . ' ' . gettimeofday(); - $hash->{helper}{lastProg} = "0"; - $hash->{helper}{lastparse_stop} = "stop" . ' ' . gettimeofday(); - $hash->{helper}{lastparse} = ""; - $hash->{helper}{parse_aborted} = "0"; - } - - else { - Log3( $name, 5, "Siro: Helper lade bestandsdaten" ); - $hash->{helper}{aktMsg} = ReadingsVal( $name, '.aktMsg', '' ); - $hash->{helper}{lastMsg} = ReadingsVal( $name, '.lastMsg', '' ); - $hash->{helper}{lastparse} = ReadingsVal( $name, '.lastparse', '' ); - $hash->{helper}{lastProg} = ReadingsVal( $name, '.lastProg', '' ); - $hash->{helper}{lastparse_stop} = - ReadingsVal( $name, '.lastparse_stop', '' ); - $hash->{helper}{parse_aborted} = - ReadingsVal( $name, '.parse_aborted', '' ); - $hash->{helper}{position} = ReadingsVal( $name, '.positionsave', '' ); - $hash->{helper}{positiontimer} = - ReadingsVal( $name, '.positiontimer', '' ); - readingsSingleUpdate( $hash, "position", - ReadingsVal( $name, '.positionsave', '0' ), 0 ); - readingsSingleUpdate( $hash, "state", - ReadingsVal( $name, '.positionsave', '0' ), 0 ); - } - Log3( $name, 5, - "Siro: Helper initialisiert: positionsave " - . ReadingsVal( $name, '.positionsave', '0' ) - . " " ); - Log3( $name, 5, - "Siro: Helper initialisiert: state " - . ReadingsVal( $name, 'state', '0' ) - . " " ); - Log3( $name, 5, - "Siro: Helper initialisiert: position " - . ReadingsVal( $name, 'position', '0' ) - . " " ); return; } ################################################################# -sub Siro_Notify($$) { - my ( $own_hash, $dev_hash ) = @_; - my $ownName = $own_hash->{NAME}; # own name / hash +sub Notify($$) { - my $devName = $dev_hash->{NAME}; # Device that created the events - my $events = deviceEvents( $dev_hash, 1 ); - - if ( $devName eq "global" - && grep( m/^INITIALIZED|REREADCFG$/, @{$events} ) ) - { - Siro_LoadHelper($own_hash); - } return; } ################################################################# -sub Siro_Delete($$) { +sub Delete($$) { my ( $hash, $name ) = @_; - return undef; } ################################################################# -sub Siro_SendCommand($@) { +sub SendCommand($@) { my ( $hash, @args ) = @_; my $ret = undef; my $cmd = $args[0]; # Command as text (on, off, stop, prog) @@ -404,67 +288,47 @@ sub Siro_SendCommand($@) { my $command = $siro_c2b{$cmd}; my $io = $hash->{IODev}; # IO-Device (SIGNALduino) - if ( $cmd eq 'on' || $cmd eq 'off' ) { + if ( $hash->{helper}{exexcmd} eq "off") # send kommand blockiert / keine ausf?hrung + { + Log3( $name, 5,"Siro_sendCommand: ausf?hrung durch helper blockiert "); + return; + + } - # setze startzeit - $hash->{helper}{motorstart} = gettimeofday(); + Log3( $name, 5,"Siro_sendCommand: args1 - $args[1]"); - #ReadingsVal( $name, '.positionsave', '' ); - } - - if ( $cmd eq 'stop' - && gettimeofday() - $hash->{helper}{motorstart} < - AttrVal( $name, 'time_to_open', 0 ) - && $hash->{CHANNEL} ne '0' ) - { - my $addtime = gettimeofday() - $hash->{helper}{motorstart}; - my $oldmotortime = ReadingsVal( $name, 'operating_seconds', 0 ); - my $newtime = $oldmotortime + $addtime; - my $rounded = int( 100 * $newtime + 0.5 ) / 100; - readingsSingleUpdate( $hash, "operating_seconds", $rounded, 1 ); - } - - my $debug = AttrVal( $name, 'debug_mode', '0' ); - - Log3( $name, 5, - "Siro_sendCommand: hash -> $hash - $name -> cmd :$cmd: - args -> @args" - ); - - if ( $args[2] eq "longstop" ) { - $SignalRepeats = AttrVal( $name, 'SignalLongStopRepeats', '15' ); - } - else { - $SignalRepeats = AttrVal( $name, 'SignalRepeats', '10' ); - } - - my $operationmode = AttrVal( $name, 'operation_mode', 'on' ); - - Log3( $name, 5, "Siro_sendCommand: operationmode -> $operationmode" ); - - if ( $operationmode eq '1' ) { - $chan = AttrVal( $name, 'channel_send_mode_1', $hash->{CHANNEL} ); - Log3( $name, 5, "Siro_sendCommand: channel für OM1 -> $chan" ); - } - else { - $chan = AttrVal( $name, 'channel', undef ); - if ( !defined($chan) ) { - $chan = $hash->{CHANNEL}; + if ( $args[1] eq "longstop" || $hash->{helper}{progmode} eq "on") + { + $SignalRepeats = AttrVal( $name, 'SIRO_signalLongStopRepeats', '15' ); + } + else + { + $SignalRepeats = AttrVal( $name, 'SIRO_signalRepeats', '10' ); + } + + $chan = AttrVal( $name, 'SIRO_send_channel', undef ); + if ( !defined($chan) ) + { + $chan = $hash->{CHANNEL_RECEIVE}; } - } - - if ( $chan eq "0" ) { - Log3( $name, 5, - "Siro_sendCommand: Aborted not sent on a channel 0 request " ); - return; - } $binChannel = sprintf( "%04b", $chan ); - #Log3($name, 5, "Siro set channel: $chan ($binChannel) for $io->{NAME}"); - my $value = $name . " " . join( " ", @args ); + + my $sendid = AttrVal( $name, 'SIRO_send_id', 'undef' ); + if ( $sendid eq 'undef') + { $binHash = sprintf( "%028b", hex( $hash->{ID} ) ); + } + else{ + $binHash = sprintf( "%028b", hex( $sendid ) ); + } + + + + Log3 $io, 5, "Siro_sendCommand: BinHash: = $binHash"; $binCommand = sprintf( "%08b", hex($command) ); @@ -475,83 +339,43 @@ sub Siro_SendCommand($@) { $message = 'P72#' . $bin . '#R' . $SignalRepeats; - if ( $debug eq "1" ) { - readingsSingleUpdate( $hash, "DEBUG_SEND", - "$name -> message :$message: ", 1 ); - } - else { - Log3 $io, 5, - "Siro_sendCommand: Siro_sendCommand: $name -> message :$message: "; - - if ( $args[2] eq "longstop" && $SignalRepeats > 35) - { - my $newsignalrepeats = int($SignalRepeats/3); - Log3( $name, 5,"Siro_sendCommand: found oversized Longstop -> newlongstop $newsignalrepeats * 15 " ); - my $testrepeats = $newsignalrepeats*3; - my $lastrepeats = $SignalRepeats-$testrepeats; - Log3( $name, 5,"Siro_sendCommand: found oversized Longstop -> Block 1-3 repeats 15 " ); - Log3( $name, 5,"Siro_sendCommand: found oversized Longstop -> Block 4 repeats $lastrepeats " ); - $message = 'P72#' . $bin . '#R' . $newsignalrepeats; - IOWrite( $hash, 'sendMsg', $message ); - Log3 $io, 5,"Siro_sendCommand: Siro_sendCommand: Block1 "; - Log3( $name, 5,"Siro_sendCommand: found oversized Longstop -> send Block 1 " ); - IOWrite( $hash, 'sendMsg', $message ); - Log3 $io, 5,"Siro_sendCommand: Siro_sendCommand: Block2 "; - Log3( $name, 5,"Siro_sendCommand: found oversized Longstop -> send Block 2 " ); - IOWrite( $hash, 'sendMsg', $message ); - Log3 $io, 5,"Siro_sendCommand: Siro_sendCommand: Block3 "; - Log3( $name, 5,"Siro_sendCommand: found oversized Longstop -> send Block 3 " ); - if ($lastrepeats > 0) - { - $message = 'P72#' . $bin . '#R' . $lastrepeats; - IOWrite( $hash, 'sendMsg', $message ); - Log3 $io, 5,"Siro_sendCommand: Siro_sendCommand: Block3 "; - Log3( $name, 5,"Siro_sendCommand: found oversized Longstop -> send Block 4 " ); - } - - } - else - { - IOWrite( $hash, 'sendMsg', $message ); - } - } - - my $devicename = $hash->{IODev}; - - Log3( $name, 2, -"Siro_sendCommand: name -> $name command -> $cmd channel -> $chan bincmd -> $binCommand " - ); - -#Log3($name, 3, "Siro_sendCommand: execute comand $cmd - sendMsg to $devicename channel $chan -> $message "); + IOWrite( $hash, 'sendMsg', $message ) if AttrVal( $name, 'SIRO_debug', "0" ) ne "1"; + Log3( $name, 5, +"Siro_sendCommand: name -> $name command -> $cmd channel -> $chan bincmd -> $binCommand bin -> $bin + message -> $message"); return $ret; } ################################################################# -sub Siro_Parse($$) { - my $debug = ''; +sub Parse($$) { + my @args; my ( $hash, $msg ) = @_; - my $doubelmsgtime = - 2; # zeit in sek in der doppelte nachrichten blockiert werden - my $favcheck = $doubelmsgtime + - 1; # zeit in der ein zweiter stop kommen muss/darf für fav + my $doubelmsgtime = 2; # zeit in sek in der doppelte nachrichten blockiert werden + my $favcheck = $doubelmsgtime +1;# zeit in der ein zweiter stop kommen muss/darf für fav my $testid = substr( $msg, 4, 8 ); my $testcmd = substr( $msg, 12, 2 ); my $timediff; my $name = $hash->{NAME}; return "" if ( IsDisabled($name) ); + + + if ($hash->{helper}{progmode} eq "on") + { + Log3( $name, 5, "Siro Parse deactivated cause off programmingmode"); + return; + } + if ( my $lh = $modules{Siro}{defptr}{$testid} ) { my $name = $lh->{NAME}; - Log3 $hash, 5, -"Siro_Parse: Incomming msg from IODevice $testid - $name device is defined"; - if ( defined($name) - && $testcmd ne "54" - ) # prüfe auf doppele msg falls gerät vorhanden und cmd nicht stop + Log3 $hash, 5,"Siro_Parse: Incomming msg from IODevice $testid - $name device is defined"; + + + if ( defined($name)&& $testcmd ne "54")# prüfe auf doppele msg falls gerät vorhanden und cmd nicht stop { - Log3 $lh, 5, -"Siro_Parse: Incomming msg $msg from IODevice name/DEF $testid - Hash -> $lh"; + Log3 $lh, 5,"Siro_Parse: Incomming msg $msg from IODevice name/DEF $testid - Hash -> $lh"; my $testparsetime = gettimeofday(); my $lastparse = $lh->{helper}{lastparse}; @@ -594,25 +418,19 @@ sub Siro_Parse($$) { my $id = substr( $rawData, 0, 7 ); # The first 7 hexcodes are the ID my $BitChannel = substr( $bitData, 28, 4 ); # Not needed atm - my $channel = sprintf( "%d", hex( substr( $rawData, 7, 1 ) ) ) - ; # The last hexcode-char defines the channel + my $channel = sprintf( "%d", hex( substr( $rawData, 7, 1 ) ) );# The last hexcode-char defines the channel my $channelhex = substr( $rawData, 7, 1 ); # tmp my $cmd = sprintf( "%d", hex( substr( $rawData, 8, 1 ) ) ); my $newstate = $codes{ $cmd . $cmd }; # Set new state - my $deviceCode = $id - . $channelhex - ; # Tmp change channel -> channelhex. The device-code is a combination of id and channel - - $debug = $debug . "id-" . $id . " "; + my $deviceCode = $id. $channelhex;#Tmp change channel -> channelhex. The device-code is a combination of id and channel + Log3 $hash, 5, "Siro_Parse: device ID: $id"; Log3 $hash, 5, "Siro_Parse: Channel: $channel"; Log3 $hash, 5, "Siro_Parse: Cmd: $cmd Newstate: $newstate"; Log3 $hash, 5, "Siro_Parse: deviceCode: $deviceCode"; - if ( defined($name) - && $testcmd eq - "54" ) # prüfe auf doppele msg falls gerät vorhanden und cmd stop + if ( defined($name)&& $testcmd eq "54" )#prüfe auf doppele msg falls gerät vorhanden und cmd stop { # Log3 $lh, 5, "Siro_Parse: prüfung auf douplestop "; my $testparsetime = gettimeofday(); @@ -662,73 +480,37 @@ sub Siro_Parse($$) { } } - if ( defined($name) ) { - $args[0] = $newstate; +Log3( $name, 5, "Siro Parse Befehl: $newstate"); + + if ( defined($name) ) {#device vorhanden my $parseaborted = 0; $lh->{helper}{parse_aborted} = $parseaborted; - - $debug = $debug . ' ' . $name; - my $operationmode = AttrVal( $name, 'operation_mode', '0' ); - my $debugmode = AttrVal( $name, 'debug_mode', '0' ); - my $chan; - if ( $operationmode eq '0' ) { - $chan = AttrVal( $name, 'channel', undef ); - if ( !defined($chan) ) { - $chan = $lh->{CHANNEL}; - } - } - - if ( $operationmode eq '1' ) { - $chan = AttrVal( $name, 'channel', undef ); - if ( !defined($chan) ) { - $chan = $lh->{CHANNEL}; - } - } - - my $aktMsg = $lh->{helper}{aktMsg}; - my @last_action_array = split( / /, $aktMsg ); - my $lastaction = $last_action_array[0]; - my $lastaction_position = $last_action_array[1]; - my $lastaction_time = $last_action_array[2]; - - readingsSingleUpdate( $lh, "parsestate", $newstate, 1 ); - Log3 $lh, 5, "Siro_Parse: $name $newstate"; - Log3 $lh, 5, "Siro_Parse: operationmode -> $operationmode"; - - if ( $operationmode ne '1' || $chan eq "0" ) { - Log3 $lh, 5, "Siro_Parse: set mode to physical"; - $lh->{helper}{MODE} = "physical"; - $debug = $debug . ' physical'; - } - else { - $lh->{helper}{MODE} = "repeater"; - $debug = $debug . ' repeater'; - } - - if ( $chan eq "0" ) { - - $args[1] = "physical"; - $debug = $debug . ' physical'; - } - - Log3 $lh, 2, "Siro_Parse -> Siro_Set: $lh, $name, @args"; - - Siro_Set( $lh, $name, @args ); - $debug = $debug . ' ' . $lh; - - if ( $debugmode eq "1" ) { - readingsSingleUpdate( $lh, "DEBUG_PARSE", $debug, 1 ); - } - ############################################## - # Return list of affected devices - #my ( $hash, $name, @args ) = @_; - ############################################## + + + my $defchannnel = $lh->{CHANNEL_RECEIVE}; + my $atrrchannel = AttrVal( $name, 'SIRO_send_channel', $defchannnel ); + + Log3 $lh, 5, "Siro_Parse: defchannnel - $defchannnel "; + Log3 $lh, 5, "Siro_Parse: atrrchannel - $atrrchannel "; + + if ($defchannnel eq $atrrchannel) + { + $lh->{helper}{remotecmd} = "on"; #verhindert das senden von signalen nur wenn nicht auf anderem kanal gesendet wird + } + + Log3 $lh, 5, "Siro_Parse: hash->{helper}{remotecmd} - ".$hash->{helper}{remotecmd}; + Log3( $name, 3, "Siro-Parse ($name) : Signal FB emfangen - $newstate"); + Set( $lh, $name, $newstate ); + return $name; } } - else { - + + + + else + { # device nicht vorhanden my ( undef, $rawData ) = split( "#", $msg ); my $hlen = length($rawData); my $blen = $hlen * 4; @@ -740,16 +522,11 @@ sub Siro_Parse($$) { my $id = substr( $rawData, 0, 7 ); # The first 7 hexcodes are the ID my $BitChannel = substr( $bitData, 28, 4 ); # Not needed atm - my $channel = sprintf( "%d", hex( substr( $rawData, 7, 1 ) ) ) - ; # The last hexcode-char defines the channel + my $channel = sprintf( "%d", hex( substr( $rawData, 7, 1 ) ) ); # The last hexcode-char defines the channel my $channelhex = substr( $rawData, 7, 1 ); # tmp my $cmd = sprintf( "%d", hex( substr( $rawData, 8, 1 ) ) ); my $newstate = $codes{ $cmd . $cmd }; # Set new state - my $deviceCode = $id - . $channelhex - ; # Tmp change channel -> channelhex. The device-code is a combination of id and channel - - $debug = $debug . "id-" . $id . " "; + my $deviceCode = $id. $channelhex; # Tmp change channel -> channelhex. The device-code is a combination of id and channel Log3 $hash, 5, "Siro_Parse: device ID: $id"; Log3 $hash, 5, "Siro_Parse: Channel: $channel"; @@ -763,421 +540,66 @@ sub Siro_Parse($$) { ############################################################# -sub Siro_Attr(@) { - my ( $cmd, $name, $aName, $aVal ) = @_; - my $hash = $defs{$name}; - return "\"Siro Attr: \" $name does not exist" if ( !defined($hash) ); - my $channel = ( $hash->{CHANNEL} ); - - if ( $channel eq "0" ) { - my @notallowed = ( - "prog_fav_sequence", "time_to_open", - "time_to_close", "operation_mode", - "channel_send_mode_1", "time_down_to_favorite" - ); - foreach my $test (@notallowed) { - if ( $test eq $aName ) { - return -"\"Siro Attr: \" $name is a group device, the attribute $aName $aVal is not allowed here."; - } - } - } - - return undef if ( !defined($name) ); - return undef if ( !defined($aName) ); - - #return undef if (!defined($aVal)); - - if ( $cmd eq "set" ) { - if ( $aName eq "debug_mode" && $aVal eq "0" ) { - Log3 $hash, 5, "debug_mode: reading deleted"; - delete( $hash->{READINGS}{DEBUG_SEND} ); - delete( $hash->{READINGS}{DEBUG_PARSE} ); - delete( $hash->{READINGS}{DEBUG_SET} ); - } - - if ( $aName eq "debug_mode" && $aVal eq "1" ) { - readingsSingleUpdate( $hash, "DEBUG_SEND", "aktiv", 1 ); - readingsSingleUpdate( $hash, "DEBUG_PARSE", "aktiv", 1 ); - readingsSingleUpdate( $hash, "DEBUG_SET", "aktiv", 1 ); - Log3 $hash, 5, "debug_mode: create reading"; - } - - if ( $aName eq "invers_position" ) { - - if ( $aVal eq "0" ) { - my $oldicon = - "{return '.*:fts_shutter_1w_'.(100-(int(\$state/10)*10))}"; - Log3 $hash, 3, -"Siro_Attr: change attr old -> $attr{$name}{devStateIcon} $oldicon"; - if ( $attr{$name}{devStateIcon} eq $oldicon ) { - Log3 $hash, 3, "Siro_Attr: ersetzt"; - $attr{$name}{devStateIcon} = - "{return '.*:fts_shutter_1w_'.(int(\$state/10)*10)}"; - } - if ( defined( $attr{$name}{down_auto_stop} ) ) { - my $autostop = AttrVal( $name, 'down_auto_stop', 'undef' ); - $autostop = 100 - $autostop; - $attr{$name}{down_auto_stop} = $autostop; - } - - my $oldstate = $hash->{helper}{position}; - - #Log3 $hash, 0, "Siro_Attr: "; - if ( !defined $oldstate ) { $oldstate = 0 } - - my $newState = $oldstate; - my $updateState; - Log3 $hash, 3, - "Siro_Attr: state old -> $oldstate new -> $newState"; - Siro_UpdateState( $hash, $newState, '', $updateState, 1 ); - - } - - if ( $aVal eq "1" ) { - my $oldicon = - "{return '.*:fts_shutter_1w_'.(int(\$state/10)*10)}"; - Log3 $hash, 3, -"Siro_Attr: change attr old -> $attr{$name}{devStateIcon} $oldicon"; - if ( $attr{$name}{devStateIcon} eq $oldicon ) { - Log3 $hash, 3, "Siro_Attr: ersetzt"; - $attr{$name}{devStateIcon} = -"{return '.*:fts_shutter_1w_'.(100-(int(\$state/10)*10))}"; - } - if ( defined( $attr{$name}{down_auto_stop} ) ) { - my $autostop = AttrVal( $name, 'down_auto_stop', 'undef' ); - $autostop = 100 - $autostop; - $attr{$name}{down_auto_stop} = $autostop; - } - my $oldstate = $hash->{helper}{position}; - my $newState = 100 - $oldstate; - my $updateState; - Log3 $hash, 3, - "Siro_Attr: state old -> $oldstate new -> $newState"; - Siro_UpdateState( $hash, $newState, '', $updateState, 1 ); - } - } - } - - if ( $cmd eq "del" ) { - if ( $aName eq "invers_position" ) { - my $oldicon = - "{return '.*:fts_shutter_1w_'.(100-(int(\$state/10)*10))}"; - - Log3 $hash, 3, -"Siro_Attr delete invers: change attr old -> $attr{$name}{devStateIcon} $oldicon"; - if ( $attr{$name}{devStateIcon} eq $oldicon ) { - Log3 $hash, 3, "Siro_Attr: ersetzt"; - $attr{$name}{devStateIcon} = - "{return '.*:fts_shutter_1w_'.(int(\$state/10)*10)}"; - } - my $oldstate = $hash->{helper}{position}; - my $newState = $oldstate; - my $updateState; - Log3 $hash, 3, "Siro_Attr: state old -> $oldstate new -> $newState"; - Siro_UpdateState( $hash, $newState, '', $updateState, 1 ); - } - } - return undef; -} - -################################################################# - # Call with hash, name, virtual/send, set-args -sub Siro_Set($@) { - +sub Set($@) { my $testtimestart = gettimeofday(); my $debug; my ( $hash, $name, @args ) = @_; + my $cmd = $args[0]; # eingehendes set + my $zielposition = $args[1]; # eingehendes set position + Log3( $name, 5, "Siro-Set: eingehendes Kommando $cmd") if $cmd ne "?"; + ### check for old version + if (ReadingsVal( $name, 'last_reset_os', 'undef' ) ne 'undef' && $cmd ne "?") + { + Log3( $name,0 , "Das Siromodul wurde geaendert und die einstellungen sind nicht mehr Kompatibel. Bitte das Sirodevice \"$name\" kontrollieren ."); + } + ################## + + my $actiontime = time; # zeit dieses Aufrufes + my $lastactiontime = ReadingsVal( $name, 'ActionTime', $actiontime ); # Zeit des letzten Aufrufes + my $betweentime = $actiontime-$lastactiontime; # Zeit zwischen aktuellem und letztem Aufruf + my $downtime = AttrVal( $name, 'SIRO_time_to_close','undef' ); # fahrdauer runter + my $uptime = AttrVal( $name, 'SIRO_time_to_open','undef' ); # fahrdauer hoch + my $down1time ="undef"; # fahrzeit 1 prozent + my $up1time ="undef"; # fahrzeit 1 prozent + my $drivingtime; # fahrzeit bei positionsanfahrt + my $aktendaction = ReadingsVal( $name, 'aktEndAction', '0' ); #endzeit laufende avtion + my $akttimeaction = ReadingsVal( $name, 'aktTimeAction', '0' ); #dauer einer laufenden aktion + my $aktrunningaction = ReadingsVal( $name, 'aktRunningAction', '' ); #typ einer laufenden aktion + my $position = ReadingsVal( $name, 'pct', '' ); #position pct bis zum ende einer aktion + my $state = ReadingsVal( $name, 'state', 'undef' ); #aktuelle aktion ( runningDown/runningUp ) + my $drivedpercents; # beinhaltet gefahrene prozent bei aktionswechsel + my $newposition ; # beinhaltet neue positin bei aktionswechsel + my $favposition = ReadingsVal( $name, 'Favorite-Position', 'nA' ); #gespeicherte Favoritenposition + my $invers = 1; #invertiert position + + + if ($downtime ne "undef" && $uptime ne "undef") + { + $down1time = $downtime/100; + $up1time = $uptime/100; + } + return "" if ( IsDisabled($name) ); - - # Set without argument #parseonly - my $numberOfArgs = int(@args); - my $nodrive = "false"; - $args[2] = "0"; - my $action = "no action"; - - return "Siro_set: No set value specified" if ( $numberOfArgs < 1 ); - - my $cmd = $args[0]; - my $invers = AttrVal( $name, 'invers_position', '0' ); - my $runningaction = ReadingsVal( $name, 'action', 'no action' ); - my $runningtime = 0; - - # teste auf hilfsvariablen - my $save = ReadingsVal( $name, '.aktMsg', 'undef' ); - if ( $save eq 'undef' ) { - $hash->{helper}{position} = "0"; - $hash->{helper}{aktMsg} = "stop" . ' ' . '0' . ' ' . gettimeofday(); - $hash->{helper}{lastMsg} = "stop" . ' ' . '0' . ' ' . gettimeofday(); - $hash->{helper}{lastProg} = "0"; - $hash->{helper}{lastparse_stop} = "stop" . ' ' . gettimeofday(); - $hash->{helper}{lastparse} = ""; - $hash->{helper}{parse_aborted} = "0"; - - readingsSingleUpdate( $hash, ".aktMsg", $hash->{helper}{aktMsg}, 0 ); - readingsSingleUpdate( $hash, ".lastMsg", $hash->{helper}{lastMsg}, 0 ); - readingsSingleUpdate( $hash, ".lastProg", $hash->{helper}{lastProg}, - 0 ); - readingsSingleUpdate( $hash, ".lastparse", $hash->{helper}{lastparse}, - 0 ); - readingsSingleUpdate( $hash, ".lastparse_stop", - $hash->{helper}{lastparse_stop}, 0 ); - readingsSingleUpdate( $hash, ".parse_aborted", - $hash->{helper}{parse_aborted}, 0 ); - readingsSingleUpdate( $hash, ".positionsave", - $hash->{helper}{position}, 0 ); - readingsSingleUpdate( $hash, ".positiontimer", - $hash->{helper}{positiontimer}, 0 ); - } - ######################################### für ECHO - if ( $cmd =~ /^\d+$/ ) { - if ( $cmd >= 0 && $cmd <= 100 ) { - $args[0] = "position"; - $args[1] = $cmd; - $cmd = "position"; - } - } - ######################################### - - #diverse befehle bei laufender aktion abfangen - if ( - ( - $cmd eq "position" - || $cmd eq 'up_for_timer' - || $cmd eq 'on_for_timer' - ) - && $runningaction ne 'no action' - ) - { - - my $restartmsg = $name . ' ' . $args[0] . ' ' . $args[1]; - Log3( $name, 3, - "Siro_Set: laufende action gefunden - restart msg -> $restartmsg " - ); - InternalTimer( gettimeofday() + 0, "Siro_Restartcmd", $restartmsg ); - $args[0] = "stop"; - $args[1] = ''; - $cmd = "stop"; - - } - - ######################################### - # invertiere position - if ( $cmd eq "position" && $invers eq "1" ) { - my $noinvers = $args[1]; - my $inversposition = 100 - $args[1]; - $args[1] = $inversposition; - Log3( $name, 3, -"Siro_Set: invertiere Position - input -> $noinvers - inverted -> $inversposition " - ); - } - #########################################gettimeofday(); - - if ( $cmd eq "reset_operating_seconds" ) { - readingsSingleUpdate( $hash, "operating_seconds", '0', 1 ); #tmp - readingsSingleUpdate( $hash, ".last_reset_operating_seconds", - gettimeofday(), 0 ); - - return; - } - - # test anzahl der Tage - if ( $hash->{CHANNEL} ne '0' ) { - my $oldtime = - ReadingsVal( $name, '.last_reset_operating_seconds', gettimeofday() ); - - my $sec = gettimeofday() - $oldtime; - my $min = int( $sec / 60 ); - $sec = $sec - ( $min * 60 ); - my $hour = int( $min / 60 ); - $min = $min - ( $hour * 60 ); - my $day = int( $hour / 24 ); - $hour = $hour - ( $day * 24 ); - - # my $running = sprintf("%d %02d:%02d:%02d",$day,$hour,$min,$sec); - - if ( ReadingsVal( $name, 'last_reset_os', '' ) ne $day ) { - readingsSingleUpdate( $hash, "last_reset_os", $day, 1 ); - } - } - else - - { - readingsDelete( $hash, 'last_reset_os' ); - readingsDelete( $hash, 'operating_seconds' ); - } - ######################################### - if ( !defined $args[2] ) { - $args[2] = ''; - } - - if ( !defined $args[1] ) { - $args[2] = '0'; - $args[1] = ''; - } - - if ( $args[1] eq "physical" ) { - $hash->{helper}{MODE} = "physical"; - } - - if ( !defined($hash) ) { return; } - if ( !defined($name) ) { return; } - - $debug = "$hash, $name, @args"; - - if ( $cmd ne "?" ) { - Log3( $name, 5, "Siro_Set: aufgerufen -> cmd -> $cmd args -> @args " ); - } - ######################################### - - # up/down for timer mappen auf on/off und timer für stop setzen - if ( $cmd eq 'up_for_timer' ) { - Log3( $name, 5, "Siro_Set: up_for_timer @args $args[1]" ); - $cmd = "off"; - - InternalTimer( $testtimestart + $args[1], "Siro_Stop", $hash, 0 ) - ; # State auf Stopp - $args[0] = $cmd; - $action = 'up for timer ' . $args[1]; - readingsSingleUpdate( $hash, "action", $action, 1 ); #tmp - } - - if ( $cmd eq 'down_for_timer' ) { - Log3( $name, 3, "Siro_Set: down_for_timer @args $args[1]" ); - $cmd = "on"; - readingsSingleUpdate( $hash, "action", 'down for timer ' . $args[1], - 1 ); #tmp - InternalTimer( $testtimestart + $args[1], "Siro_Stop", $hash, 0 ) - ; # State auf Stopp - $args[0] = $cmd; - $action = 'down for timer ' . $args[1]; - readingsSingleUpdate( $hash, "action", $action, 1 ); #tmp - } - ######################################### - - # diverse befehle auf bekannte befehle mappen - if ( $cmd eq 'open' ) { - $cmd = "off"; - $args[0] = $cmd; - } - - if ( $cmd eq 'close' ) { - $cmd = "on"; - $args[0] = $cmd; - } - ######################################### - - $hash->{Version} = $version; - - # diverse attr einlesen - my $debugmode = AttrVal( $name, 'debug_mode', '0' ); - my $testchannel = $hash->{CHANNEL}; - my $timetoopen = - AttrVal( $name, 'time_to_open', 'undef' ); # fahrzeit komplett runter - my $timetoclose = - AttrVal( $name, 'time_to_close', 'undef' ); # fahrzeit komplett hoch - my $operationmode = - AttrVal( $name, 'operation_mode', '0' ); # mode 0 normal / 1 repeater - my $limitedmode = "off"; - my $downlimit = AttrVal( $name, 'down_limit_mode_1', '100' ) - ; # maximale runterfahrt im mode 1 - my $autostop = AttrVal( $name, 'down_auto_stop', '100' ) - ; # automatischer stop bei runterfahrt - ######################################### - - # sets an device anpassen - if ( $testchannel ne "0" ) { - - %sets = ( - "open" => "noArg", - "close" => "noArg", - "off" => "noArg", - "stop" => "noArg", - "on" => "noArg", - "fav" => "noArg", - "prog" => "noArg", - "prog_stop" => "noArg", - "position" => "slider,0,1,100" - , # Wird nur bei vorhandenen time_to attributen gesetzt - "state" => "noArg", - "set_favorite" => "noArg", - "down_for_timer" => "textField", - "reset_operating_seconds" => "noArg", - "up_for_timer" => "textField" # Ggf. entfernen (Alexa) - ); - - if ( $timetoopen eq 'undef' || $timetoclose eq 'undef' ) { - if ( $attr{$name}{webCmd} eq "stop:on:off:fav:position" ) { - $attr{$name}{webCmd} = "stop:on:off:fav"; - } - - $limitedmode = "on"; - $hash->{INFO} = -"limited function without ATTR time_to_open / time_to_close / time_down_to_favorite"; - } - else { - if ( $attr{$name}{webCmd} eq "stop:on:off:fav" ) { - $attr{$name}{webCmd} = "stop:on:off:fav:position"; - } - delete( $hash->{INFO} ); - - } - } - else # this block is for groupdevicec ( channel 0 ) - { - Log3( $name, 5, "Siro_Set: Groupdevice erkannt " ); - - %sets = ( - "open" => "noArg", - "close" => "noArg", - "off" => "noArg", - "stop" => "noArg", - "on" => "noArg", - "fav" => "noArg", - - #"prog" => "noArg", - #"prog_stop" => "noArg", - "position" => "slider,0,1,100" - , # Wird nur bei vorhandenen time_to attributen gesetzt - "state" => "noArg", - - #"set_favorite" => "noArg", - "down_for_timer" => "textField", - "up_for_timer" => "textField" - ); - - if ( $cmd ne "?" ) #change - { - my $timetoopen = "15"; - my $timetoclose = "15"; - my $testhashtmp = ""; - my $testhashtmp1 = ""; - my $namex = ""; - my $testid = ""; - my $id = $hash->{ID}; - my @grouphash; - my @groupnames; - - @groupnames = Siro_Testgroup( $hash, $id ); - - $hash->{INFO} = -"This is a group Device with limited functions affected the following devices:\n @groupnames"; - my $groupcommand = - $cmd . "," . $args[0] . "," . $args[1] . "," . $hash; - - $hash->{helper}{groupcommand} = $groupcommand; - InternalTimer( gettimeofday() + 0, "Siro_Setgroup", $hash, 1 ); - } - $hash->{helper}{MODE} = "physical"; - } - ######################################### - - # Check for unknown arguments - if ( !exists( $sets{$cmd} ) ) { + + # versionschange + #changeconfig + + if ( $cmd eq 'changeconfig'){ + versionchange( $name ); + return; + } + + # pr?fe auf unbekannte sets + + if ( $cmd =~ m/^exec.*/ )# empfangene sequenz aus programmiermode + { + $args[1] = $cmd; + $cmd = "sequenz"; + } + + if ( !exists( $sets{$cmd} ) ) { my @cList; - - # Overwrite %sets with setList my $atts = AttrVal( $name, 'setList', "" ); my %setlist = split( "[: ][ ]*", $atts ); foreach my $k ( sort keys %sets ) { @@ -1193,933 +615,702 @@ sub Siro_Set($@) { } # end foreach return "Unknown argument $cmd, choose one of " . join( " ", @cList ); } - ######################################### - # undefinierte attr time to open/close abfangen - if ( ( $timetoopen eq 'undef' || $timetoclose eq 'undef' ) - && $testchannel ne "0" ) - { - Log3( $name, 1, -"Siro_Set:limited function without definition of time_to_close and time_to_open. Please define this attributes." - ); - $nodrive = "true"; - $timetoopen = 1; - $timetoclose = 1; - } - ######################################### +#################################### +# programmiermodus +#################################### + + if ( $hash->{helper}{progmode} eq "on" && $cmd eq "sequenz") # sequenz ausführen + { + Log3( $name, 5, "Siro-Programmiermodus: Sequenz gefunden :$args[1]"); + my @seq = split(/,/, $args[1]); + + shift @seq; + my $exectime = time; + foreach my $seqpart (@seq) + { + #$actiontime + $exectime = $exectime+2; + my $execcmd = $seqpart; + Log3( $name, 5, "Siro-Programmiermodus: Sequenz - $exectime - $execcmd"); + InternalTimer( $exectime, "FHEM::Siro::Prog", $name." ".$execcmd ); + } + return; + } + + if ($cmd eq "prog_mode_on" && $hash->{helper}{progmode} ne "on") + { + readingsSingleUpdate( $hash, "state", 'programming', 1 ); + $hash->{helper}{progmode} = "on"; + } + + if ($cmd eq "prog_mode_off" && $hash->{helper}{progmode} eq "on") + { + readingsSingleUpdate( $hash, "state", $position, 1 ); + delete( $hash->{helper}{progmode} ); + } + + if ($hash->{helper}{progmode} eq "on") + { + SendCommand( $hash, $sendCommands{$cmd} ); + delete( $hash->{Signalduino_RAWMSG} ); + delete( $hash->{Signalduino_MSGCNT} ); + delete( $hash->{Signalduino_RSSI} ); + delete( $hash->{Signalduino_TIME} ); + Log3( $name, 5, "Siro-Programmiermodus: Parse deaktiviert"); + return; + } + +#################################### - # progmodus setzen - if ( $cmd eq "prog" ) { - $hash->{helper}{lastProg} = - gettimeofday() + 180; # 3 min programmiermodus + if ($state eq "programming") # keine Befehlsausf?hrung w?hrend einer programmierung + { + Log3( $name, 1, "Siro-Programmiermodus: Befehl nicht moeglich , Device ist im Programmiermodus"); + return; + } + + # setze actiontime und lastactiontime + # umbauen zu bulk update + RemoveInternalTimer($name); #alle vorhandenen timer l?schen + delete( $hash->{helper}{exexcmd} ); # on/off off blockiert befehlsausf?hrung / l?schen vor jedem durchgang + + #setze helper neu wenn signal von fb kommt + + if ($hash->{helper}{remotecmd} eq "on") + { + $hash->{helper}{exexcmd} = "off" + } + delete( $hash->{helper}{remotecmd} ); + + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "ActionTime", $actiontime, 0 ); + readingsBulkUpdate( $hash, "LastActionTime", $lastactiontime, 0 ); + readingsBulkUpdate( $hash, "BetweentActionTime", $betweentime, 0 ); + readingsEndUpdate($hash, 1); + # befehl aus %sendCommands ermitteln + my $comand = $sendCommands{$cmd}; # auzuf?hrender befehl + Log3( $name, 5, "Siro-Set: ermittelter Befehl: $comand " ); + + + # set reset_motor_term reset_motor_term + if ($comand eq "reset_motor_term") + { + readingsSingleUpdate( $hash, "motor-term", "0", 1 ) ; + readingsSingleUpdate( $hash, "batteryState", "unknown", 1 ) ; + return; + } + + # pr?fe auf laufende aktion nur bei definierten laufzeiten + # wenn vorhanden neuberechnung aller readings + if ($aktendaction > time && ($downtime ne "undef" || $uptime ne "undef")) + { + Log3( $name, 5, "Siro-Set: laufende aktion gefunden - abbruch"); + Log3( $name, 5, "Siro-Set: laufende aktion -"); + + #aktTimeAction - dauer der laufenden aktion - in variable $akttimeaction + #aktEndAction geplantes aktionsende - in variabel $aktendaction + #$actiontime aktuelle zeit + #$aktrunningaction - typ der laufenden aktion + #$position -position bei actionsbeginn + my $pastaction = $akttimeaction - ($aktendaction - $actiontime); + Log3( $name, 5, "Siro-Set: unterbrochene Aktion $state lief $pastaction "); + Log3( $name, 5, "Siro-Set: Aktionsbeginn bei $position "); + + if ($state eq "runningDown" || $state eq "runningDownfortimer") + { + $drivedpercents = $pastaction/$down1time; + $drivedpercents = ( int( $drivedpercents * 10 ) / 10 ); + Log3( $name, 5, "Siro-Set: Positionsveraenderung um $drivedpercents Prozent nach unten "); + $newposition = int ($position+$drivedpercents); + } + + if ($state eq "runningUp" || $state eq "runningUpfortimer") + { + $drivedpercents = $pastaction/$up1time; + $drivedpercents = ( int( $drivedpercents * 10 ) / 10 ); + Log3( $name, 5, "Siro-Set: Positionsveraenderung um $drivedpercents Prozent nach oben "); + $newposition = int ($position-$drivedpercents); + } + + Log3( $name, 5, "Siro-Set: neue Position - $newposition "); + + my $operationtime = ReadingsNum( $name, 'motor-term', 0 ); + my $newoperationtime = $operationtime + $pastaction; + + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "state", $newposition ) ; + readingsBulkUpdate( $hash, "pct", $newposition ) ; + readingsBulkUpdate( $hash, "aktRunningAction", "noAction" ) ; + readingsBulkUpdate( $hash, "aktEndAction", 0 ) ; + readingsBulkUpdate( $hash, "aktTimeAction", 0 ) ; + readingsBulkUpdate( $hash, "aktActionFinish", 0 ) ; + readingsBulkUpdate( $hash, "motor-term", $newoperationtime, 1 ) ; + readingsEndUpdate($hash, 1); + + if ($comand ne "stop") #wenn anders kommando als stop befehl zwischenspeichern und per internal timer neu aufrufen , vorher fahrt stoppen per befehl. Stopbefehl l?uft durch wegen notbetrieb ohne timer attribute, gespeicherter befehl wir abgelegt in reading ($cmd) helper/cmd1 und ($zielposition) helper/cmd2. bei aufruf set wird auf vorhandensein gepr?ft. + { + SendCommand( $hash, 'stop' ); + Log3( $name, 5, "Siro-Set: Twischenspeichern von Cmd ($cmd) und Position ($zielposition)"); + $hash->{helper}{savedcmds}{cmd1} = $cmd; + $hash->{helper}{savedcmds}{cmd2} = $zielposition if defined $zielposition; + InternalTimer( time, "FHEM::Siro::Restartset", "$name" ); + return; + } + } + +############## on off for timer +# up/down for timer mappen auf on/off und timer für stop setzen + if ( $comand eq 'upfortimer' ) + { + Log3( $name, 5, "Siro-Set: up_for_timer $args[1]" ); + $hash->{helper}{savedcmds}{cmd1} = 'stop'; + InternalTimer( time + $args[1], "FHEM::Siro::Restartset", "$name" ); } - if ( $cmd eq "prog_stop" ) { - $hash->{helper}{lastProg} = gettimeofday(); - return; - } - ######################################### +############## on off for timer - # favoritenposition speichern +# up/down for timer mappen auf on/off und timer für stop setzen + if ( $comand eq 'downfortimer' ) + { + Log3( $name, 5, "Siro_Set: down_for_timer $args[1]" ); + $hash->{helper}{savedcmds}{cmd1} = 'stop'; + InternalTimer( time + $args[1], "FHEM::Siro::Restartset", "$name" ); + } +################# + if ($comand eq "fav") # favoritenanfahrt + { + if ($favposition eq "nA") + { + Log3( $name, 1, "Siro-Set: Favoritenanfahrt nicht m?glich , Reading nicht gesetzt"); + return; + } + Log3( $name, 3, "Siro-Set ($name) : set Favorit"); + SendCommand( $hash, 'stop' , 'longstop' ); + # befehl ?ndern auf position favorite + # weiterer programmdurchlauf + # per defintition keine weiteren send kommandos helper exexcmd on/off (off) + $hash->{helper}{exexcmd} = 'off'; # schaltet das senden folgender befehls ab / nur anpassung der readings + $comand = "level"; + $zielposition = $favposition; + } +#################################### +# favoritenposition speichern if ( $cmd eq "set_favorite" ) { - if ( $debugmode eq "1" ) { - readingsSingleUpdate( $hash, "DEBUG_SET", 'setze Favorite', 1 ); - } - my $sequence; - my $sequenceraw = AttrVal( $name, 'prog_fav_sequence', '' ); - if ( defined( $attr{$name}{time_down_to_favorite} ) ) { + + # lockdevive einrichten ! + readingsSingleUpdate( $hash, "state", 'programming', 1 ); - $sequence = $sequenceraw . ',2,' . $sequenceraw; - Log3( $name, 0, "Siro_Set: delete and set favorit -> $sequence" ); - } - else { - $sequence = $sequenceraw; - Log3( $name, 0, "Siro_Set: set favorit -> $sequence" ); - } - - $hash->{sequence} = $sequence; # 3 Min Programmiermodus - InternalTimer( gettimeofday() + 1, "Siro_Sequence", $hash, 0 ) - ; # State auf stop setzen nach Erreichen der Fahrdauer - Log3( $name, 1, "Siro_Set:setting new favorite" ); + my $sequence ; + my $blocking; + if ($favposition eq "nA") + { + $sequence = '1:prog,3:stop,3:stop' ; + $blocking = 8; + } + else + { + $sequence = '1:prog,3:stop,3:stop,3:prog,3:stop,3:stop' ; + $blocking =17; + } + + my @sequenzraw =split (/,/,$sequence); + my $exectime = $actiontime; + foreach my $seqpart (@sequenzraw) + { + Log3( $name, 5, "Siro-Set: Favorit seqpart - $seqpart"); + my @seqpartraw =split (/\:/,$seqpart); + #$actiontime + $exectime = $exectime+$seqpartraw[0]; + my $execcmd = $seqpartraw[1]; + Log3( $name, 5, "Siro-Set: Favorit $exectime - $execcmd"); + InternalTimer( $exectime, "FHEM::Siro::Prog", $name." ".$execcmd ); + InternalTimer( ($actiontime+$blocking), "FHEM::Siro::Delock", $name ); + } + readingsSingleUpdate( $hash, "Favorite-Position", $position, 1 ); + return; + } + +################################################### +# favoritenposition speichern + if ( $cmd eq "del_favorite" ) + { + if ($args[1] eq "only_shutter" || $args[1] eq "shutter_and_modul") + { + readingsSingleUpdate( $hash, "state", 'programming', 1 ); + my $sequence ; + $sequence = '0:prog,2:stop,2:stop' ; + my @sequenzraw =split (/,/,$sequence); + my $exectime = $actiontime; + foreach my $seqpart (@sequenzraw) + { + Log3( $name, 5, "Siro-Set: Delfavorit seqpart - $seqpart"); + my @seqpartraw =split (/\:/,$seqpart); + #$actiontime + $exectime = $exectime+$seqpartraw[0]; + my $execcmd = $seqpartraw[1]; + Log3( $name, 5, "Siro-Set: Delfavorit $exectime - $execcmd"); + InternalTimer( $exectime, "FHEM::Siro::Prog", $name." ".$execcmd ); + InternalTimer( $exectime+10, "FHEM::Siro::Delock", $name ); + } + } + if ($args[1] eq "only_modul" || $args[1] eq "shutter_and_modul") + { + readingsSingleUpdate( $hash, "Favorite-Position", 'nA', 1 ); + } return; } - ######################################### + + + ################################################## + ################################## + + # set on ( device faeht runter ) + if ($comand eq "on" || $comand eq "downfortimer" ) + { + Log3( $name, 3, "Siro-Set ($name) : set Down"); + if ($downtime eq "undef" || $uptime eq "undef") # bei ungesetzten fahrzeiten + { + readingsSingleUpdate( $hash, "state", "100", 1 ) ; + readingsSingleUpdate( $hash, "motor-term", "Function is not available without set runtime attribute, please define", 1 ) ; + SendCommand( $hash, 'on' ); + return; + } + if ($state eq "undef" || $state eq "notAvaible") { $state = 0; } + my $waytodrive = 100 - $state; + my $timetodrive = $waytodrive * $down1time; + my $endaction = time + $timetodrive; + Log3( $name, 5, "Siro-Set: on downtime - waytodrive $waytodrive"); + Log3( $name, 5, "Siro-Set: on downtime - state $state"); + Log3( $name, 5, "Siro-Set: on downtime - down1time $down1time"); + SendCommand( $hash, 'on' ); + #SendCommand( $hash, 'stop' ); + + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "aktRunningAction", $comand ) ; + readingsBulkUpdate( $hash, "aktEndAction", $endaction ) ; + readingsBulkUpdate( $hash, "aktTimeAction", $timetodrive ) ; + readingsBulkUpdate( $hash, "aktActionFinish", "100" ) ; + readingsEndUpdate( $hash, 1); + + if ($comand eq "on") + { + readingsSingleUpdate( $hash, "state", "runningDown" , 1 ) ; + + # internen timer setzen runningtime - dann states setzen + Log3( $name, 5, "Siro-Set: setze Timer -$comand"); + InternalTimer( $endaction, "FHEM::Siro::Finish", "$name" ); + + } + else{ + readingsSingleUpdate( $hash, "state", "runningDownfortimer" , 1 ) ; + } + #befehl ausfuhren + } + +########################################## + # set off ( device faeht hoch ) + if ($comand eq "off" || $comand eq "upfortimer" ) + { + Log3( $name, 3, "Siro-Set ($name) : set Up"); + if ($downtime eq "undef" || $uptime eq "undef") # bei ungesetzten fahrzeiten + { + + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "state", "0" ) ; + readingsBulkUpdate( $hash, "motor-term", "Function is not available without set runtime attribute, please define") ; + readingsBulkUpdate( $hash, "LastAction", $comand ); + readingsEndUpdate( $hash, 1); + SendCommand( $hash, 'off' ); + } + + if ($state eq "undef" || $state eq "notAvaible") { $state = 100; } + my $waytodrive = 0 + $state; + my $timetodrive = $waytodrive * $up1time; + my $endaction = time + $timetodrive; + Log3( $name, 5, "Siro-Set: off downtime - waytodrive $waytodrive"); + Log3( $name, 5, "Siro-Set: off downtime - state $state"); + Log3( $name, 5, "Siro-Set: off downtime - down1time $down1time"); + SendCommand( $hash, 'off' ); + + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "aktRunningAction", $comand ) ; + readingsBulkUpdate( $hash, "aktEndAction", $endaction ) ; + readingsBulkUpdate( $hash, "aktTimeAction", $timetodrive ) ; + readingsBulkUpdate( $hash, "aktActionFinish", "0" ) ; + readingsEndUpdate( $hash, 1); + + + if ($comand eq "off") + { + readingsSingleUpdate( $hash, "state", "runningUp" , 1 ) ; + + # internen timer setzen runningtime - dann states setzen + Log3( $name, 5, "Siro-Set: setze timer -$comand"); + InternalTimer( $endaction, "FHEM::Siro::Finish", "$name" ); + } + else + { + readingsSingleUpdate( $hash, "state", "runningUpfortimer" , 1 ) ; + } - # variablenberechnung für folgende funktionen - my $check = 'check'; - my $bmode = $hash->{helper}{aktMsg}; - if ( $bmode eq "repeater" ) { - $check = 'nocheck'; - } - my $ondirekttime = $timetoclose / 100; # Zeit für 1 Prozent Runterfahrt - my $offdirekttime = $timetoopen / 100; # Zeit für 1 Prozent Hochfahrt - #my $runningtime; - my $timetorun; - my $newposstate; - if ( defined( $args[1] ) ) { - if ( $args[1] =~ /^\d+$/ ) { - $newposstate = $args[1]; # Anzufahrende Position in Prozent - Log3( $name, 5, "Siro_Set:newposstate -> $newposstate" ); - $timetorun = - $timetoclose / 100 * - $newposstate - ; # Laufzeit von 0 prozent }bis zur anzufahrenden Position - } - } - my $virtual; # Kontrollvariable der Positionsanfahrt - my $newState; - my $updateState; - my $positiondrive; - my $state = $hash->{STATE}; - my $aktMsg = $hash->{helper}{aktMsg}; - my @last_action_array = split( / /, $aktMsg ); - my $lastaction = $last_action_array[0]; - my $lastaction_position = $last_action_array[1]; - my $lastaction_time = $last_action_array[2]; - my $befMsg = $hash->{helper}{lastMsg}; - my @before_action_array = split( / /, $befMsg ); - my $beforeaction_position = $before_action_array[1]; - my $timebetweenmsg = - $testtimestart - - $last_action_array[2]; # Zeit zwischen dem aktuellen und letzten Befehl - $timebetweenmsg = ( int( $timebetweenmsg * 10 ) / 10 ); - my $oldposition; # Alter Stand in Prozent - my $newposition - ; # Errechnende Positionsänderung in Prozent - > bei on plus alten Stand - my $finalposition; # Erreichter Rollostand in Prozent für state; - my $time_to_favorite = AttrVal( $name, 'time_down_to_favorite', 'undef' ); - my $favorit_position; - my $mode = $hash->{helper}{MODE}; # Betriebsmodus virtual, physicalFP - my $lastprogmode = $hash->{helper}{lastProg}; - my $testprogmode = $testtimestart; - my $testprog = int($testprogmode) - int($lastprogmode); - my $oldstate = ReadingsVal( $name, 'state', 100 ); + #befehl ausfuhren + } + +################################################# + # set level ( positionsanfahrt ) + if ($comand eq "level") + { + + if ( AttrVal($name,'SIRO_inversPosition','0') eq '1' ) + { + $zielposition = 100 - $zielposition; + $state = 100 - $state; + } - Log3( $name, 5, "Siro_set: test auf double stop" ); - Log3( $name, 5, "Siro_set: testprogmode -> $testprogmode" ); - Log3( $name, 5, "Siro_set: lastprogmode -> $lastprogmode" ); - Log3( $name, 5, "Siro_set: lastaction -> $lastaction" ); - Log3( $name, 5, "Siro_set: cmd -> $cmd" ); + Log3( $name, 3, "Siro-Set ($name) : set Position $zielposition "); + + if ($downtime eq "undef" || $uptime eq "undef") # bei ungesetzten fahrzeiten + { + Log3( $name, 1, "ERROR Siro - Set: Function is not available without set runtime attribute, please define"); + readingsSingleUpdate( $hash, "LastAction", $comand, 1 ); + readingsSingleUpdate( $hash, "motor-term", "Function is not available without set runtime attribute, please define", 1 ) ; + return "Function PCT is not available without set runtime attribute, please define "; + } + my $timetodrive; #enth?tlt fahrzeit + my $cmdpos ="undef"; # enth?lt fahrbefehl f?r gew?nschte richtung + my $cmdactiontime ; # enth?lt fahrtdauer f?r gew?nschte position + my $directionmsg; #enth?lt actionstesxt + # geforderte farhtrichtung ermitteln + if ($state < $zielposition) # fahrt runter ben?tigt + { + $cmdpos = "on"; + # fahrdauer ermitteln + $timetodrive = ($zielposition - $state) * $down1time; + $directionmsg ="runningDown"; + } + + if ($state > $zielposition) # fahrt hoch ben?tigt + { + $cmdpos = "off"; + # fahrdauer ermitteln + $timetodrive = ($state - $zielposition) * $up1time; + $directionmsg ="runningUp"; + } - # verhindern eines doppelten stoppbefehls ausser progmodus 1 - if ( $testprogmode > $lastprogmode - ) # Doppelten Stoppbefehl verhindern, ausser progmodus aktiv - { - if ( $lastaction eq 'stop' && $cmd eq 'stop' && $check ne 'nocheck' ) { - Log3( $name, 5, "Siro_set: double stop, action aborted" ); - readingsSingleUpdate( $hash, "prog_mode", "inaktiv ", 1 ); - if ( $debugmode eq "1" ) { - $debug = "Siro_set: double stop, action aborted"; - readingsSingleUpdate( $hash, "DEBUG_SET", $debug, 1 ); - } - return; - } - } - else { - $testprog = $testprog * -1; - $virtual = "virtual"; - readingsSingleUpdate( $hash, "prog_mode", "$testprog", 1 ); + my $endaction = time + $timetodrive; + SendCommand( $hash, $cmdpos ); - } - ######################################### - - # invertierung position - if ( $invers eq "1" ) { - $oldstate = 100 - $oldstate; - $autostop = 100 - $autostop; - } - ######################################### - - Log3( $name, 5, -"Siro_Set: teste autostop: $autostop < 100 $oldstate < $autostop - $cmd" - ); - - # erkennung autostopfunktiuon - if ( $cmd eq "on" && $autostop < 100 && $oldstate < $autostop ) { - $cmd = "position"; - $args[1] = $autostop; - $newposstate = $args[1]; # position autostop - $timetorun = $timetoclose / 100 * $newposstate; - Log3( $name, 1, -"Siro_Set: autostop gefunden mapping auf position erfolgt: $newposstate " - ); - } - ######################################### - - # erkennung downlimit funktion - if ( $downlimit < 100 && $operationmode eq "1" ) { - if ( $cmd eq 'position' && $downlimit < $newposstate ) { - $args[1] = $downlimit; - $newposstate = $args[1]; # Anzufahrende Position in Prozent - $timetorun = $timetoclose / 100 * $newposstate; - Log3( $name, 1, - "Siro_Set: drive down limit reached: $newposstate " ); - } - if ( $cmd eq 'on' ) { - $cmd = "position"; - $args[1] = $downlimit; - $newposstate = $args[1]; # Anzufahrende Position in Prozent - $timetorun = $timetoclose / 100 * $newposstate; - Log3( $name, 1, - "Siro_Set: drive down limit reached: $newposstate " ); - } - } - ######################################### - - # on/off Umschaltung ohne zwischenzeitliches Anhalten - if ( $cmd eq 'on' - && $timebetweenmsg < $timetoopen - && $lastaction eq 'off' ) # Prüfe auf direkte Umschaltung on - off - { - $oldposition = $beforeaction_position; - $newposition = $timebetweenmsg / $offdirekttime; - $finalposition = $oldposition - $newposition; - if ( $limitedmode eq "on" ) { - $finalposition = "50"; - } - $hash->{helper}{lastMsg} = $aktMsg; - $hash->{helper}{aktMsg} = - "stop" . ' ' . int($finalposition) . ' ' . gettimeofday(); - $hash->{helper}{positiontimer} = $timebetweenmsg; - $hash->{helper}{position} = int($finalposition); - - if ( $mode ne "physical" ) { - Siro_SendCommand( $hash, 'stop' ); - } - $aktMsg = $hash->{helper}{aktMsg}; - @last_action_array = split( / /, $aktMsg ); - $lastaction = $last_action_array[0]; - $lastaction_position = $last_action_array[1]; - $lastaction_time = $last_action_array[2]; - $befMsg = $hash->{helper}{lastMsg}; - @before_action_array = split( / /, $befMsg ); - $beforeaction_position = $before_action_array[1]; - $timebetweenmsg = - $testtimestart - - $last_action_array[2] - ; # Zeit zwischen dem aktuellen und letzten Befehl - $timebetweenmsg = ( int( $timebetweenmsg * 10 ) / 10 ); - } - ######################################### - - # off/on Umschaltung ohne zwischenzeitliches Anhalten - if ( $cmd eq 'off' - && $timebetweenmsg < $timetoclose - && $lastaction eq 'on' ) - { - $oldposition = $beforeaction_position; - $newposition = $timebetweenmsg / $ondirekttime; - $finalposition = $oldposition + $newposition; - if ( $limitedmode eq "on" ) { - $finalposition = "50"; - } - $hash->{helper}{lastMsg} = $aktMsg; - $hash->{helper}{aktMsg} = - "stop" . ' ' . int($finalposition) . ' ' . gettimeofday(); - $hash->{helper}{positiontimer} = $timebetweenmsg; - - if ( $mode ne "physical" ) { - Siro_SendCommand( $hash, 'stop' ); - } - $aktMsg = $hash->{helper}{aktMsg}; - @last_action_array = split( / /, $aktMsg ); - $lastaction = $last_action_array[0]; - $lastaction_position = $last_action_array[1]; - $lastaction_time = $last_action_array[2]; - $befMsg = $hash->{helper}{lastMsg}; - @before_action_array = split( / /, $befMsg ); - $beforeaction_position = $before_action_array[1]; - $timebetweenmsg = - gettimeofday() - - $last_action_array[2] - ; # Zeit zwischen dem aktuellen und letzten Befehl - $timebetweenmsg = ( int( $timebetweenmsg * 10 ) / 10 ); - } - ######################################### - - # Positionsberechnung bei einem Stopp-Befehl - if ( $cmd eq 'stop' ) { - - # lösche interne timer - setze reading action auf no action - - readingsSingleUpdate( $hash, "action", 'no action', 1 ); - RemoveInternalTimer($hash); - - Log3( $name, 5, -"Siro_Set: cmd stop timebetweenmsg -> $timebetweenmsg ondirekttime -> $ondirekttime offdirekttime -> $offdirekttime " - ); - - $oldposition = $beforeaction_position; - if ( $ondirekttime eq "0" - || $offdirekttime eq - "0" ) # Fehler division durch 0 abfanken bei ungesetzten attributen - { - Log3( $name, 5, -"Siro_Set: cmd stop -> Positionserrechnung ohne gesetzte Attribute , Finalposition wird auf 50 gesetzt " - ); - $finalposition = "50"; - $args[1] = $finalposition; - } - else { - Log3( $name, 5, -"Siro_Set: stop - Lastaction -> $lastaction $lastaction_position $oldposition" - ); - if ( $lastaction eq 'position' ) { - if ( $lastaction_position > $oldposition ) { - $lastaction = "on"; - } - else { - $lastaction = "off"; - } - - } - if ( $lastaction eq 'on' ) # Letzte Fahrt runter (on) - { - $newposition = $timebetweenmsg / $ondirekttime; - $finalposition = $oldposition + $newposition; - } - elsif ( $lastaction eq 'off' ) # Letzte Fahrt hoch (off) - { - $newposition = $timebetweenmsg / $offdirekttime; - $finalposition = $oldposition - $newposition; - } - elsif ( $lastaction eq 'fav' ) # Letzte Fahrt unbekannt - { -#Fahrtrichtung ermitteln - dafür Position von lastmsg nehmen $beforeaction_position - $favorit_position = $time_to_favorite / $ondirekttime; - Log3( $name, 5, -"Siro_Set: drive to position aborted (target position:$favorit_position %) : (begin possition $beforeaction_position %) " - ); - - if ( $favorit_position < $beforeaction_position ) # Fahrt hoch - { - $newposition = $timebetweenmsg / $offdirekttime; - $finalposition = $oldposition - $newposition; - } - - if ( $favorit_position > $beforeaction_position ) # Fahrt runter - { - $newposition = $timebetweenmsg / $ondirekttime; - $finalposition = $oldposition + $newposition; - } - - Log3( $name, 5, "Siro_Set position: $finalposition " ); - } - - if ( $finalposition < 0 ) { $finalposition = 0; } - if ( $finalposition > 100 ) { $finalposition = 100; } - if ( $limitedmode eq "on" ) { $finalposition = "50"; } - $finalposition = int($finalposition); # abrunden - $args[1] = $finalposition; - } - } - ######################################### - - # Hardware-Favorit anfahren - if ( $cmd eq 'fav' ) { - Log3( $name, 5, "Siro_Set fav: $cmd " ); - if ( !defined $time_to_favorite ) { - $time_to_favorite = 5; - } # Tmp ggf. ändern - - # if ( $time_to_favorite eq "undef") - # { - # $time_to_favorite=5; - # #return; - # } - - if ( $ondirekttime eq "0" - || $offdirekttime eq - "0" ) # Fehler division durch 0 abfanken bei ungesetzten attributen - { - Log3( $name, 1, -"Siro_Set: set cmd fav -> Favoritberechnung ohne gesetzte Attribute , aktion nicht möglich" - ); - return; - } - - $favorit_position = - $time_to_favorite / - $ondirekttime - ; # Errechnet nur die Position, die von oben angefahren wurde. pos - $args[0] = $cmd; - $args[1] = int($favorit_position); - - if ( $time_to_favorite eq 'undef' ) { - Log3( $name, 1, -"Siro_Set: function position limited without attr time_down_to_favorite" - ); - $time_to_favorite = "1"; - $args[1] = "50"; - - # new - if ( $mode ne "physical" ) { - $args[2] = 'longstop'; - $args[0] = 'stop'; - Siro_SendCommand( $hash, @args ); - readingsSingleUpdate( $hash, "position", '50', 1 ); - readingsSingleUpdate( $hash, "state", '50', 1 ); - } - return; - } - - $args[2] = 'longstop'; - $hash->{helper}{lastMsg} = $aktMsg; - $hash->{helper}{aktMsg} = - $args[0] . ' ' . $args[1] . ' ' . gettimeofday(); - $hash->{helper}{positiontimer} = $timebetweenmsg; - $cmd = 'stop'; - $args[0] = $cmd; - - if ( $mode ne "physical" ) { - Siro_SendCommand( $hash, @args ); - } - - my $position = - $hash->{helper}{position}; # Position für die Zeitberechnung speichern - $hash->{helper}{position} = int($favorit_position); - Siro_UpdateState( $hash, int($favorit_position), '', '', 1 ); - -#Fahrtrichtung ermitteln - dafür Position von lastmsg nehmen $beforeaction_position - $runningtime = 0; - - if ( $favorit_position < $position ) # Fahrt hoch - { - readingsSingleUpdate( $hash, "action", 'up to favorite', 1 ); #tmp - my $change = $position - $favorit_position; # änderung in % - $runningtime = $change * $offdirekttime; - } - - if ( $favorit_position > $position ) # Fahrt runter - { - readingsSingleUpdate( $hash, "action", 'down to favorite', 1 ); #tmp - my $change = $favorit_position - $position; # Änderung in % - $runningtime = $change * $ondirekttime; - } - - InternalTimer( $testtimestart + $runningtime, - "Siro_Position_fav", $hash, 0 ) - ; # state auf Stopp setzen nach Erreichen der Fahrtdauer - return; - } - ######################################### - - # Teste auf Position '0' oder '100' -> Mappen auf 'on' oder 'off' - if ( $cmd eq 'on' ) { $args[1] = "100"; } - if ( $cmd eq 'off' ) { $args[1] = "0"; } - ######################################### - - #Aktualisierung des Timers (Zeit zwischen den Befehlen, lastmsg und aktmsg) - $hash->{helper}{lastMsg} = $hash->{helper}{aktMsg}; - $hash->{helper}{aktMsg} = $args[0] . ' ' . $args[1] . ' ' . gettimeofday(); - $hash->{helper}{positiontimer} = $timebetweenmsg; - ######################################### - - if ( defined($newposstate) ) { - if ( $newposstate eq "0" ) { - $cmd = "off"; - Log3( $name, 5, "recognized position 0 " ); - } - elsif ( $newposstate eq "100" ) { - $cmd = "on"; - Log3( $name, 5, "recognized position 100 " ); - } - } - - # Direkte Positionsanfahrt - if ( $cmd eq 'position' ) { - Log3( $name, 5, "Siro_Set: nodrive -> $nodrive" ); - if ( - ( - $ondirekttime eq "0" - || $offdirekttime eq "0" - || $nodrive eq "true" - ) - && $testchannel ne "0" - ) # Fehler division durch 0 abfanken bei ungesetzten attributen - { - Log3( $name, 1, -"Siro_Set: Positionsanfahrt ohne gesetzte Attribute , aktion nicht möglich -> abbruch" - ); - return -"Positionsanfahrt ohne gesetzte Attribute time_to_open und time_to_close nicht moeglich"; - } - my $aktposition = $hash->{helper}{position}; - - # Fahrt nach oben - if ( $newposstate < $aktposition ) { - if ( $action eq "no action" ) { - $action = 'up to position ' . $newposstate; - readingsSingleUpdate( $hash, "action", $action, 1 ); #tmp - } - $cmd = 'off'; - my $percenttorun = $aktposition - $newposstate; - $runningtime = $percenttorun * $offdirekttime; - $timetorun = $runningtime; - Log3( $name, 5, -"Siro_Set: direkt positiondrive: -> timing:($runningtime = $percenttorun*$offdirekttime) -> open runningtime:$runningtime - modification in % :$percenttorun" - ); - } - - #Fahrt nach unten - if ( $newposstate > $aktposition ) { - if ( $action eq "no action" ) { - $action = 'down to position ' . $newposstate; - readingsSingleUpdate( $hash, "action", $action, 1 ); #tmp - } - $cmd = 'on'; - my $percenttorun = $newposstate - $aktposition; - $runningtime = $percenttorun * $ondirekttime; - $timetorun = $runningtime; - Log3( $name, 5, -"Siro_Set: direkt positiondrive: -> timing: ($runningtime = $percenttorun*$ondirekttime) -> close runningtime:$runningtime - modification in % :$percenttorun" - ); - } - $virtual = "virtual"; # keine Stateänderung - Log3( $name, 5, - "Siro_Set: direkt positiondrive: -> setting timer to $runningtime" - ); - InternalTimer( $testtimestart + $runningtime, - "Siro_Position_down_stop", $hash, 0 ); - } - ######################################### - - # abarbeitung weiterer befehle - if ( $cmd eq 'on' ) { - if ( $action eq "no action" ) { - $action = 'down '; - readingsSingleUpdate( $hash, "action", $action, 1 ); #tmp - # voraussichtliche fahrzeit berechnen bis 100% - my $aktposition = $hash->{helper}{position}; - my $percenttorun = 100 - $aktposition; - $runningtime = $percenttorun * $ondirekttime; - $timetorun = $runningtime; - Log3( $name, 4, -"Siro_Set: aktposition -> $aktposition - percenttorun -> $percenttorun - ondirekttime -> $ondirekttime" - ); - Log3( $name, 4, - "Siro_Set: voraussichtliche fahrdauer bis 100%: -> $runningtime" - ); - InternalTimer( gettimeofday() + $timetorun + 1, - "Siro_Stopaction", $hash, 0 ); # action auf Stopp - } - $newState = '100'; - $positiondrive = 100; - } - elsif ( $cmd eq 'off' ) { - if ( $action eq "no action" ) { - $action = 'up '; - readingsSingleUpdate( $hash, "action", $action, 1 ); #tmp - # voraussichtliche fahrzeit berechnen bis 0% - my $aktposition = $hash->{helper}{position}; - my $percenttorun = $aktposition; - $runningtime = $percenttorun * $offdirekttime; - $timetorun = $runningtime; - Log3( $name, 4, -"Siro_Set: aktposition -> $aktposition - percenttorun -> $percenttorun - offdirekttime -> $offdirekttime" - ); - Log3( $name, 4, - "Siro_Set: voraussichtliche fahrdauer bis 0%: -> $runningtime" - ); - InternalTimer( gettimeofday() + $timetorun + 1, - "Siro_Stopaction", $hash, 0 ); # action auf Stopp - } - $newState = '0'; - $positiondrive = 0; - } - elsif ( $cmd eq 'stop' ) { - $newState = $finalposition; - $positiondrive = $finalposition; - } - elsif ( $cmd eq 'fav' ) { - $newState = $favorit_position; - $positiondrive = $favorit_position; - } - else { - $newState = $state; #todo: Was mache ich mit der Positiondrive? - } -######################################### - - if ( !defined($virtual) ) { $virtual = ""; } - if ( !defined($newposstate) ) { $newposstate = 0; } - if ( !defined($newposstate) ) { $newposstate = 0; } - - if ( $virtual ne "virtual" ) # Kein Stateupdate beim Anfahren einer Position - { - - if ( $newposstate < 0 ) { $newposstate = 0; } - if ( $newposstate > 100 ) { $newposstate = 100; } - $hash->{helper}{position} = $positiondrive; - Log3( $name, 5, "Siro_Set: stateupdate erfolgt -> $positiondrive" ); - - ######################################### - # invertiere position - if ( $invers eq "1" ) { - my $noinvers = $newState; - my $inversposition = 100 - $newState; - $newState = $inversposition; - - Log3( $name, 3, -"Siro_Set: invertiere Position vor setstate - berechnet -> $noinvers - inverted -> $newState " - ); - } - ######################################### - - Siro_UpdateState( $hash, $newState, '', $updateState, 1 ); - } - else { - Log3( $name, 5, "Siro_Set: kein stateupdate erfolgt" ); - - #Setze readings positiondrive und positiontime - if ( $newposstate < 0 ) { $newposstate = 0; } - if ( $newposstate > 100 ) { $newposstate = 100; } - $hash->{helper}{position} = $newposstate; - } - - $args[0] = $cmd; - - if ( !defined($mode) ) { $mode = "virtual" } - - if ( $debugmode eq "1" ) { - readingsSingleUpdate( $hash, "DEBUG_SET", $debug, 1 ); - } - - if ( $mode ne "physical" ) { - Log3( $name, 5, -"Siro_set: handing over to Siro_Send_Command with following arguments: @args" - ); - Siro_SendCommand( $hash, @args ); - } - - $hash->{helper}{MODE} = "virtual"; - $hash->{helper}{LastMODE} = $mode; - my $testtimeend = gettimeofday(); - $runningtime = $testtimeend - $testtimestart; - Log3( $name, 5, "Siro_set: runningtime -> $runningtime" ); - - return; + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "aktRunningAction", 'position' ) ; + readingsBulkUpdate( $hash, "aktEndAction", $endaction ) ; + readingsBulkUpdate( $hash, "aktTimeAction", $timetodrive ) ; + readingsBulkUpdate( $hash, "aktActionFinish", $zielposition ) ; + readingsBulkUpdate( $hash, "state", $directionmsg ) ; + readingsEndUpdate( $hash, 1); + + # internen timer setzen runningtime - dann states setzen + Log3( $name, 5, "Siro-Set: setze timer -$comand"); + InternalTimer( $endaction, "FHEM::Siro::Finish", "$name" ); + + Log3( $name, 5, "Siro-Set: found direction - $cmdpos"); + Log3( $name, 5, "Siro-Set: found finish - $zielposition"); + Log3( $name, 5, "Siro-Set: found position now - $state"); + + } + +###################################################### + # set stop + if ($comand eq "stop" && ReadingsVal( $name, 'LastAction', 'undef' ) ne $comand ) + { + Log3( $name, 3, "Siro-Set ($name) : set Stop "); + if ($downtime eq "undef" || $uptime eq "undef") # bei ungesetzten fahrzeiten + { + SendCommand( $hash, 'stop' ); + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "state", "notAvaible" ) ; + readingsBulkUpdate( $hash, "LastAction", $comand ); + readingsBulkUpdate( $hash, "motor-term", "Function is not available without set runtime attribute, please define", 1 ) ; + readingsEndUpdate( $hash, 1); + return; + } + else # bei gesetzten fahrzeiten + { + SendCommand( $hash, 'stop' ); + } + + } +############################################ + # batteriecheck + if ( AttrVal( $name, 'SIRO_Battery_low','undef' ) ne "undef") + { + readingsSingleUpdate( $hash, "batteryState", "ok" , 1 ) if (AttrVal( $name, 'SIRO_Battery_low','' ) > ReadingsNum( $name, 'motor-term', 0 )); + readingsSingleUpdate( $hash, "batteryState", "low" , 1 ) if (AttrVal( $name, 'SIRO_Battery_low','' ) < ReadingsNum( $name, 'motor-term', 0 )); + } + else + { + readingsSingleUpdate( $hash, "batteryState", "unknown" , 1 ); + } + return; } -########################################################################### +####################### +sub Delock($) { +# entsperrt device nach programmierung des shutters + my ($input) = @_; + my ( $name, $arg ) = split(/ /, $input ); + my $hash = $defs{$name}; + my $position = ReadingsVal( $name, 'pct', '' ); #position pct bis zum ende einer aktion + readingsSingleUpdate( $hash, "state", $position , 1 ); + } -sub Siro_UpdateState($$$$$) { - my ( $hash, $newState, $move, $updateState, $doTrigger ) = @_; - readingsBeginUpdate($hash); - if ( $newState < 0 ) { $newState = 0; } - if ( $newState > 100 ) { $newState = 100; } - readingsBulkUpdate( $hash, "state", $newState ); - readingsBulkUpdate( $hash, "position", $newState ); - $hash->{state} = $newState; +####################### +sub Prog($) { +#wird im programmiermode von internaltimer aufgerufen + my ($input) = @_; + my ( $name, $arg ) = split(/ /, $input ); + my $hash = $defs{$name}; + Log3( $name, 5, "Siro-Prog: $arg "); + SendCommand( $hash, $arg ); + return; + } + +####################### +sub Finish($) { +# wird bei errechnetem aktionsende aufgerufen + my ($input) = @_; + my ( $name, $arg ) = split( / /, $input ); + my $hash = $defs{$name}; + return "" if ( IsDisabled($name) ); + + my $invers = 1; + my $action = ReadingsVal( $name, 'aktRunningAction', '' ); + my $state = ReadingsVal( $name, 'aktActionFinish', 'notAvaible' ); + my $operationtime = ReadingsNum( $name, 'motor-term', 0 ); + my $newoperationtime = $operationtime + ReadingsNum ($name, 'aktTimeAction', 0 ); + + Log3( $name, 5, "Siro-Finish: action - $action"); + + SendCommand( $hash, 'stop' ) if ( $action ne "on" && $action ne "off" ) ; + + if ( AttrVal($name,'SIRO_inversPosition','0') eq '1' ) + { + $state = 100 - $state; + } + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "state", $state ) ; + readingsBulkUpdate( $hash, "pct", $state ) ; + readingsBulkUpdate( $hash, "aktRunningAction", "noAction" ) ; + readingsBulkUpdate( $hash, "aktEndAction", 0 ) ; + readingsBulkUpdate( $hash, "aktTimeAction", 0 ) ; + readingsBulkUpdate( $hash, "aktActionFinish", 0 ) ; + readingsBulkUpdate( $hash, "motor-term", $newoperationtime, 1 ) ; + readingsEndUpdate( $hash, 1); + return; + } - #$hash->{helper}{position} = $newState; - readingsEndUpdate( $hash, $doTrigger ); +##################### +sub Restartset($) { + my ($input) = @_; + my ( $name, $arg ) = split( / /, $input ); + my $hash = $defs{$name}; + return "" if ( IsDisabled($name) ); + Log3( $name, 5, "Siro-Restartset : aufgerufen"); + my $cmd = $hash->{helper}{savedcmds}{cmd1}; + my $pos = $hash->{helper}{savedcmds}{cmd2}; + delete( $hash->{helper}{savedcmds} ); + Set($hash, $name, $cmd , $pos); + return; } +##################### +sub versionchange($) { + my ($input) = @_; + my ( $name, $arg ) = split( / /, $input ); + my $hash = $defs{$name}; + return "" if ( IsDisabled($name) ); + Log3( $name, 0, "Siro - versionchange : aufruf"); + my $attr; -################################################################# + $attr = AttrVal($name,'time_to_close','undef'); + CommandAttr(undef,$name . ' SIRO_time_to_close ' . $attr) if ( AttrVal($name,'time_to_close','undef') ne 'undef' ); + fhem("deleteattr $name time_to_close"); + + $attr = AttrVal($name,'time_to_open','undef'); + CommandAttr(undef,$name . ' SIRO_time_to_open ' . $attr) if ( AttrVal($name,'time_to_open','undef') ne 'undef' ); + fhem("deleteattr $name time_to_open"); + + $attr = AttrVal($name,'SignalLongStopRepeats','undef'); + CommandAttr(undef,$name . ' SIRO_signalLongStopRepeats ' . $attr) if ( AttrVal($name,'SignalLongStopRepeats','undef') ne 'undef' ); + fhem("deleteattr $name SignalLongStopRepeats"); + + $attr = AttrVal($name,'SignalRepeats','undef'); + CommandAttr(undef,$name . ' SIRO_signalRepeats ' . $attr) if ( AttrVal($name,'SignalRepeats','undef') ne 'undef' ); + fhem("deleteattr $name SignalRepeats"); + + $attr = AttrVal($name,'invers_position','undef'); + CommandAttr(undef,$name . ' SIRO_inversPosition ' . $attr) if ( AttrVal($name,'invers_position','undef') ne 'undef' ); + fhem("deleteattr $name invers_position"); -sub Siro_Position_down_start($) { - my ($hash) = @_; - my $name = $hash->{NAME}; + CommandAttr( undef,$name . ' devStateIcon {if (ReadingsVal( $name, \'state\', \'undef\' ) =~ m/[a-z]/ ) { return \'programming:edit_settings notAvaible:hue_room_garage runningUp.*:fts_shutter_up runningDown.*:fts_shutter_down\'}else{return \'[0-9]{1,3}:fts_shutter_1w_\'.(int($state/10)*10)}}' ); + CommandAttr(undef,$name . ' webCmd stop:open:close:fav:pct'); - #my $timetoopen = AttrVal($name,'time_to_open', 'undef'); #tmp - #my $timetoclose = AttrVal($name,'time_to_close', 'undef');#tmp - my @args; - $args[0] = 'on'; - my $virtual = 'virtual'; - Siro_SendCommand( $hash, @args,, $virtual ); - Log3 $name, 5, "Siro_Position_down_start: completed"; - return; + $attr = AttrVal($name,'operation_mode','undef'); + if ($attr eq "1"){ + my $modch = AttrVal($name,'channel_send_mode_1','undef'); + CommandAttr(undef,$name . ' SIRO_send_channel ' . $modch) + } + + fhem("deleteattr $name operation_mode"); + fhem("deleteattr $name channel_send_mode_1"); + + + fhem("deleteattr $name down_limit_mode_1"); + fhem("deleteattr $name operation_mode"); + fhem("deleteattr $name invers_position"); + fhem("deleteattr $name down_auto_stop"); + fhem("deleteattr $name prog_fav_sequence"); + fhem("deleteattr $name time_down_to_favorite"); + fhem("deleteattr $name time_down_to_favorite"); + + + my $seconds = ReadingsVal( $name, 'operating_seconds', '0' ); + fhem("deletereading $name .*"); + + readingsBeginUpdate($hash); + readingsBulkUpdate( $hash, "state", "0" ); + readingsBulkUpdate( $hash, "pct", "0" ) ; + readingsBulkUpdate( $hash, "motor-term", $seconds ) ; + readingsEndUpdate( $hash, 1 ); + + SendCommand( $hash, 'off' ); + return; } -################################################################# -sub Siro_Position_down_stop($) { - my ($hash) = @_; - my $name = $hash->{NAME}; - my @args; - $args[0] = 'stop'; - if ( !defined( $args[1] ) ) { $args[1] = ""; } - my $virtual = 'virtual'; - Siro_SendCommand( $hash, @args, $virtual ); - my $positiondrive = $hash->{helper}{position}; - my $aktMsg = $hash->{helper}{aktMsg}; - $hash->{helper}{lastMsg} = $aktMsg; +################## +sub fhemwebFn($$$$) { +my ( $FW_wname, $d, $room, $pageHash ) =@_; # pageHash is set for summaryFn. + my $hash = $defs{$d}; + my $name = $hash->{NAME}; + return "" if ( IsDisabled($name) ); + my $progmode =$hash->{helper}{progmode}; + if (!defined $progmode){$progmode='off';} + my $msg; + +############## versionsänderung +# kann irgendwann entfernt werden + + if (ReadingsVal( $name, 'last_reset_os', 'undef' ) ne 'undef') + { + $msg.= " + +
 
ACHTUNG !
 
Das Siromudul wurde komplett erneuert.
Die vorhandenen Attribute und Readings sind inkompatibel und das Device derzeit nur bedingt funktionsfaehig:
 
Durch druecken des untenstehenden Buttons ist eine automatisch Neukonfiguration moeglich, dabei werden vorhandene Daten beruecksichtigt. Nach betaetigen des Buttons macht das Rollo eine Initialisierungsfahrt nach oben.
 
Danach ist eine Funktion mit der alten Siroversion nicht mehr moeglich.
Fuer den Fall, das doch die alte Version wieder eingesetzt werden sollte ist die jetzt vorhandene Rawdefinition vor einer Umstellung zu sichern.
Wichtig: Bei einer automatischen Umstellung werden entgegen den Massgaben vorhandene Userattribute geaendert ! "; + $msg.= "
 
"; + $msg.= ""; + $msg.= " "; + $msg.= "
  +
+ "; + } +###################### - #$hash->{helper}{aktMsg} = $args[0].' '.$args[1].' '.gettimeofday(); - $hash->{helper}{aktMsg} = - $args[0] . ' ' . $positiondrive . ' ' . gettimeofday(); + if ( $progmode eq "on") + { + $msg.= " + +
 
Programmiermodus aktiv, es werden nur folgende Befehle unterstuetzt:
 
"; - # invertiere position - my $invers = AttrVal( $name, 'invers_position', '0' ); - - if ( $invers eq "1" ) { - my $noinvers = $positiondrive; - my $inversposition = 100 - $positiondrive; - $positiondrive = $inversposition; - - Log3( $name, 3, -"Siro_Set: invertiere Position vor setstate - berechnet -> $noinvers - inverted -> $positiondrive " - ); - } - readingsSingleUpdate( $hash, "action", 'no action', 1 ); #tmp - Siro_UpdateState( $hash, $positiondrive, '', '', 1 ); - Log3 $name, 5, - "Siro_Position_down_stop: completed -> state:$positiondrive "; - return; + + + $msg.= "Das Anlernen ene Rollos erfolgt unter der ID: "; + + + + my $sendid = AttrVal( $name, 'SIRO_send_id', 'undef' ); + if ( $sendid eq 'undef') + { + $msg.= $hash->{ID} ; + } + else + { + $msg.= $sendid ; + } + $msg.= " und dem Kanal: "; + my $sendchan = AttrVal( $name, 'SIRO_send_channel', 'undef' ); + if ( $sendchan eq 'undef') + { + $msg.= $hash->{CHANNEL_RECEIVE} ; + } + else + { + $msg.= $sendchan ; + } + + $msg.= "
 
"; + + $msg.= ""; + $msg.= " "; + + $msg.= ""; + $msg.= " "; + + $msg.= ""; + $msg.= " "; + + $msg.= ""; + $msg.= " "; + + $msg.= " "; + $msg.= " "; + $msg.= " "; + $msg.= " "; + $msg.= " "; + $msg.= " "; + $msg.= " "; + $msg.= " "; + $msg.= " "; + $msg.= ""; + $msg.= " 
 "; + + $msg.= "
- Motor anlernen: P2,P2,DOWN je nach Wicklung des Rollos"; + $msg.= " "; + + $msg.= "
- Motor anlernen: P2,P2,UP je nach Wicklung des Rollos"; + $msg.= " "; + + $msg.= "
- Einstellmodus aktivieren: P2, UP, P2"; + $msg.= " "; + + $msg.= "
- Endlagen loeschen: P2, DOWN, P2"; + $msg.= " "; + + $msg.= "
- Pairing loeschen: P2, STOP, P2"; + $msg.= " "; + + $msg.= "
 
"; + } + + $msg.= ""; + return $msg; } -################################################################# -sub Siro_Position_fav($) { - my ($hash) = @_; - my $name = $hash->{NAME}; - my @args; - my $aktMsg = $hash->{helper}{aktMsg}; - $hash->{helper}{lastMsg} = $aktMsg; - my @last_action_array = split( / /, $aktMsg ); - $hash->{helper}{aktMsg} = - 'stop' . ' ' . $last_action_array[1] . ' ' . gettimeofday(); - readingsSingleUpdate( $hash, "action", 'no action', 1 ); #tmp +################ - #my $addtime = gettimeofday() - $hash->{helper}{motorstart}; - #my $oldmotortime = ReadingsVal( $name, 'operating_seconds', 0 ); - #my $newtime = $oldmotortime + $addtime; - #my $rounded = int(100 * $newtime + 0.5) / 100; - #readingsSingleUpdate( $hash, "operating_seconds",$rounded , 1 ); - Log3 $name, 5, "Siro_Position_fav: completed"; - return; -} - -################################################################# - -sub Siro_Sequence($) { - - my $debug; - my ($hash) = @_; - my $name = $hash->{NAME}; - Log3( $name, 1, "Siro_Sequence:START" ); - my @args; - my @sequence = split( /,/, $hash->{sequence} ); - my $debugmode = AttrVal( $name, 'debug_mode', '0' ); - my $cmd = shift @sequence; - my $timer = shift @sequence; - $debug = $debug . ' ' . $cmd . ' ' . $timer . ' ' . @sequence; - $hash->{sequence} = join( ",", @sequence ); # 3 min Programmiermodus - $args[0] = $cmd; - Siro_SendCommand( $hash, @args, 'virtual' ); - - if ( defined($timer) ) { - InternalTimer( gettimeofday() + $timer, "Siro_Sequence", $hash, 0 ); - $debug = $debug . '- Erneute Aufrufsequenz'; - } - else { - $debug = $debug - . '- Sequenz beendet, ATTR time_to _fav neu berechnet und gesetzt, progmode beendet'; - readingsSingleUpdate( $hash, "prog_mode", "inaktiv ", 1 ); - delete( $hash->{sequence} ); - my $timetoclose = AttrVal( $name, 'time_to_close', '10' ); - my $ondirekttime = $timetoclose / 100; # Zeit für 1 Prozent Runterfahrt - my $position = $hash->{helper}{position}; - my $newfav = $ondirekttime * $position; - $attr{$name}{time_down_to_favorite} = $newfav; - } - if ( $debugmode eq "1" ) { - readingsSingleUpdate( $hash, "DEBUG_SEQUENCE", $debug, 1 ); - } - - Log3 $name, 5, "Siro_Sequence: completed"; - return; -} -############################################################### - -sub Siro_Setgroup($) { - my ($hash) = @_; - my $name = $hash->{NAME}; - my $grouphashraw = $hash->{helper}{affected_devices_h}; - my @grouphash = split( /,/, $grouphashraw ); - my $groupnamesraw = $hash->{helper}{affected_devices_n}; - my @groupnames = split( /,/, $groupnamesraw ); - my $groupcommandraw = $hash->{helper}{groupcommand}; - my @groupcommand = split( /,/, $groupcommandraw ); - Log3( $name, 5, "Siro_Setgroup : @groupnames -> $groupcommandraw " ); - - my $count = 0; - - foreach my $senddevice (@groupnames) { - my @args; - - #Log3($name,5,"----------------------------"); - Log3( $name, 5, "Siro_Setgroup: count -> $count " ); - Log3( $name, 5, "Siro_Setgroup: senddevice -> $senddevice " ); - Log3( $name, 5, "Siro_Setgroup: testhash -> $grouphash[$count] " ); - Log3( $name, 5, - "Siro_Setgroup: command -> $groupcommand[1] $groupcommand[2] " ); - - #Log3($name,5,"----------------------------"); - $args[0] = $groupcommand[1]; - $args[1] = $groupcommand[2]; - Log3( $name, 5, - "Siro_Setgroup: aufruf -> $grouphash[$count],$senddevice, @args " - ); - Log3( $name, 5, - "Siro_Setgroup: set $senddevice $groupcommand[1] $groupcommand[2]" - ); - - #my $cs = "set Siro_5B417081 on"; - my $cs = "set $senddevice $groupcommand[0] $groupcommand[2]"; - my $client_hash = $grouphash[$count]; - Log3( $name, 5, "Siro_Setgroup: command -> " . $cs ); - my $errors = AnalyzeCommandChain( undef, $cs ); - - $count++; - } - return; -} -############################################################### - -sub Siro_Stop($) { - my ($hash) = @_; - my $name = $hash->{NAME}; - my @args; - $args[0] = "stop"; - - #my ( $hash, $name, @args ) = @_; - readingsSingleUpdate( $hash, "action", 'no action', 1 ); #tmp - Log3( $name, 0, "Siro_Stop: x-for-timer stop -> @args " ); - Siro_Set( $hash, $name, @args ); - - return; -} -############################################################### - -sub Siro_Restartcmd($) { - my $incomming = $_[0]; - my @msgarray = split( / /, $incomming ); - my $name = $msgarray[1]; - - #my $hash = $msgarray[1]; - #my $name = $hash->{NAME}; - my $cs = "set $incomming"; - Log3( $name, 3, "Siro_Restartcmd: incomming -> $incomming " ); - Log3( $name, 3, "Siro_Restartcmd: command -> " . $cs ); - - my $errors = AnalyzeCommandChain( undef, $cs ); - - return; -} -############################################################### - -sub Siro_Stopaction($) { - my ($hash) = @_; - my $name = $hash->{NAME}; - Log3( $name, 5, "Siro_Stopaction: setze no action " ); - readingsSingleUpdate( $hash, "action", 'no action', 1 ); #tmp - - if ( $hash->{CHANNEL} ne '0' ) { - - my $addtime = gettimeofday() - $hash->{helper}{motorstart}; - my $oldmotortime = ReadingsVal( $name, 'operating_seconds', 0 ); - my $newtime = $oldmotortime + $addtime; - my $rounded = int( 100 * $newtime + 0.5 ) / 100; - readingsSingleUpdate( $hash, "operating_seconds", $rounded, 1 ); - } - return; -} -###############################################################readingsSingleUpdate($hash, "action",$action, 1); #tmp -sub Siro_Testgroup($$) { - my ( $hash, $id ) = @_; - my $name = $hash->{NAME}; - my $testid; - my $testidchan; - my @groupnames; - my @grouphash; - - foreach my $testdevices ( keys %{ $modules{Siro}{defptr} } ) # - { - - $testid = substr( $testdevices, 0, 7 ); - $testidchan = substr( $testdevices, 7, 1 ); - Log3( $name, 5, -"Siro_Testgroup: groupdevice search device $testid -> test device -> $testdevices-$testidchan " - ); - if ( $id eq $testid ) { - my $lh = $modules{Siro}{defptr}{$testdevices}; #def - my $namex = $lh->{NAME}; - my $channelx = $lh->{CHANNEL}; - Log3( $name, 5, - "Siro_Testgroup: device for group found -> $namex lh -$lh" ); - if ( $channelx ne "0" ) { - Log3( $name, 5, -"Siro_Testgroup: device for group found -> $namex hash -> $lh" - ); - push( @groupnames, $namex ); - push( @grouphash, $lh ); # betreffendes hash zur gruppe zufügen - } - } - } - - my $hashstring; - foreach my $target (@grouphash) { - $hashstring = $hashstring . $target . ","; - } - chop($hashstring); - $hash->{helper}{affected_devices_h} = "$hashstring"; - - my $devicestring; - foreach my $target (@groupnames) { - $devicestring = $devicestring . $target . ","; - } - - chop($devicestring); - $hash->{helper}{affected_devices_n} = $devicestring; - - return @groupnames; -} - -############################################# -sub Siro_icon($) { - - #return 'fts_shutter_1w_'.(int($state/10)*10); - my ($id) = @_; - my $lh = $modules{Siro}{defptr}{$id}; - my $position = $lh->{helper}{position}; - - my $xsvg = " - - - - - -Created by potrace 1.8, written by Peter Selinger 2001-2007 - - - image/svg+xml - - - - - - - -"; - - return $xsvg; - -} 1; =pod @@ -2192,11 +1383,13 @@ An autocreate (if enabled) automatically creates the device with the ID of the r set Siro1 on moves the roller blind up completely (0%)
set Siro1 off moves the roller blind down completely (100%)
set Siro1 stop stops the current movement of the roller blind
-set Siro1 position 45 moves the roller blind to the specified position (45%)
+set Siro1 pct 45 moves the roller blind to the specified position (45%)
set Siro1 45 moves the roller blind to the specified position (45%)
set Siro1 fav moves the blind to the hardware-programmed favourite middle position
-set Siro1 prog corresponds to the "P2" button on the remote control, the module is set to programming mode (3 min).
set Siro1 set_favorite programs the current roll position as hardware middle position. The attribute time_down_to_favorite is recalculated and set.
+set Siro1 progmode_on enable the programming mode
+ +
Notes:

@@ -2219,50 +1412,33 @@ set Siro1 set_favorite programs the current roll position as hardw Without the specification of the "Transmit and receive module" "IODev", a function is not possible.
- +
  • channel (since V1.09 no longer available)
    - contains the channel used by the module for sending and receiving. + contains the channel used by the module for sending. This is already set when the device is created.

  • - -
  • channel_send_mode_1
    - contains the channel that is used by the module in "operation_mode 1" to send. - This attribute is not used in "operation_mode 0" + + +
  • contains the ID used by the module for sending. + This is already set when the device is created. +

  • - + - -
  • operation_mode
    - Mode 0

    - This is the default mode. In this mode, the module uses only the channel specified by the remote control or the "channel" attribute. In the worst case, signals, timing problems etc. missed by FHEM can lead to wrong states and position readings. These are synchronized again when a final position is approached. -

    Mode 1

    - Extended mode. In this mode, the module uses two channels. The standard channel "channel" for receiving the remote control. This should no longer be received by the blind itself. And the "channel_send_mode_1", for sending to the roller blind motor. For this purpose, a reconfiguration of the motor is necessary. This mode is "much safer" in terms of the representation of the states, since missing a signal by FHEM does not cause the wrong positions to be displayed. The roller blind only moves when FHEM has received the signal and passes it on to the motor.
    - Instructions for configuring the motor will follow. -

  • - - -
  • time_down_to_favorite
    - contains the movement time in seconds, which the roller blind needs from 0% position to the hardware favorite center position. This time must be measured and entered manually. - Without this attribute, the module is not fully functional.

  • - - +
  • time_to_close
    contains the movement time in seconds required by the blind from 0% position to 100% position. This time must be measured and entered manually. Without this attribute, the module is not fully functional.

  • - +
  • time_to_open
    contains the movement time in seconds required by the blind from 100% position to 0% position. This time must be measured and entered manually. Without this attribute, the module is not fully functional.

  • - -
  • prog_fav_sequence
    - contains the command sequence for programming the hardware favorite position

  • -
  • debug_mode [0:1]
    - In mode 1, additional readings are created for troubleshooting purposes, in which the output of all module elements is output. Commands are NOT physically sent.

  • + In mode 1 Commands are NOT physically sent.
  • Info
    @@ -2273,13 +1449,8 @@ set Siro1 set_favorite programs the current roll position as hardw =end html - - - =begin html_DE - -

    Siro protocol