98_Siro.pm 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256
  1. # $Id: 98_Siro.pm 15424 2017-11-12 10:25:19Z Byte09 $
  2. #
  3. # Siro module for FHEM
  4. # Thanks for templates/coding from SIGNALduino team and Jarnsen_darkmission_ralf9
  5. #
  6. # Needs SIGNALduino >= V3.3.1-dev (10.03.2017).
  7. # Published under GNU GPL License, v2
  8. # History:
  9. # 0.01 2017-05-24 Smag Decoding/sniffing signals, Binary-keycode-decoding for on, off, stop, favourite and p2 (pairing).
  10. # 0.02 2017-05-25 Smag Tests with CUL/COC and Signalduino. Successful signalrepeat to device via Signalduino.
  11. # 0.03 2017-07-23 Smag initial template
  12. # 0.04 2017-07-24 Smag Changed binary device-define to much more easier hex-code (28bit+channel).
  13. # 0.10 2017-07-30 Smag Siro-Parse implemented. First alpha-version went out for Byte09 and det
  14. # 0.11 2017-07-30 Smag, Byte09 updated module
  15. # 0.12 2017-08-02 Byte Subroutine X_internaltset komplett entfernt, Zusammenlegung mit X_set
  16. # Byte Variablen bereinigt
  17. # Byte Code bereinigt
  18. # Byte Einführung "readings", "lastmsg" und "aktMsg" inkl. Unixtime
  19. # 0.13 2017-08-03 Byte Senden eines doppelten Stoppbefehls abgefangen, keine Hardwaremittelanfahrt durch zweimaliges Stopp mehr möglich
  20. # 0.14 2017-08-04 Byte Attr SignalLongStopRepeats eingeführt. Anzahl der Repeats für Longstop (Favourite). undef = 15
  21. # 0.15 2017-08-05 Byte Attr "timer" eingeführt. Enthält die Zeit zwischen zwei ausgeführten Befehlen zur Positionsberechnung
  22. # 0.16 2017-08-06 Byte Berechnung der aktuellen Position nach Stop-Kommando - Darstellung im state bzw. im Slider
  23. # 0.17 2017-08-09 Byte Fehler bei der Positionsfahrt aus der Fav-Position behoben
  24. # 0.18 2017-08-10 Byte Änderung des State bei Empfang von FB integriert
  25. # 0.19 2017-08-12 Byte Attr 'position_adjust' abgeschafft
  26. # 0.20 2017-08-12 Attr 'operation_mode' eingeführt
  27. # 0 Normaler Modus : Keine 'position_adjust' - Fahrt über 0
  28. # 1 Normaler Modus : Positionsanfahrt immer -> 'position_adjust' - Fahrt über 0
  29. # 2 Repeater Modus : Modul empfängt die FB und leitet es an den Motor weiter. Motor empfängt die FB nicht direkt.
  30. # Kanalanpassung notwendig. Zuverlässigster Betrieb!
  31. # 0.21 2017-08-13 Smag: Code-Cleanup. Spellcheck. Documentation
  32. # 0.22 2017-08-18 Byte: Kompletten Code überarbeitet. Laufzeitoptimierung. Reaktionszeit verbessert. Unnötige Readings in die Internals verlagert. Fehler bei direktem umschalten behoben.
  33. # Operation_mode 1 komplett entfernt, om 2 ist nun om 1. Operationmode 1 bis Fertigstellung deaktiviert
  34. # 0.23 Beta Byte V0.22 - > V1.0 Beta
  35. # 0.24 2017-08-20 Byte Positionsanfahrt über Alexa möglich - "schalte DEVICE XX%"
  36. # Operation_mode 1 eingeführt. ( Repeatermodus )
  37. # 0.25 2017-08-26 Byte diverse Korrekturen, Codebereinigung, Anfahrt der HW_Favorit Position über FB im Mode 1 möglich
  38. # 0.26 2017-08-26 Byte Commandref Deutsch hinzugefügt
  39. # 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
  40. # Debug_Attr (0/1) eingefügt - es werden diverse redings angelegt und kein Befehl physisch anden Rollo gesendet - nur Fehlersuche
  41. # 0.28 2017-09-02 ByteFehler bei Stateaktualisierung in Zusammenhang mit Stop bei Favoritenanfahrt behoben
  42. # 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
  43. # Debug_Attr (0/1) eingefügt - es werden diverse redings angelegt und kein Befehl physisch anden Rollo gesendet - nur Fehlersuche
  44. # Set favorite und Attr prog_fav_sequence eingeführt - programmierung derHardware_Favorite_Position
  45. # Codebereinigung
  46. # Allgemeine Fehler behoben
  47. # 0.30 2017-09-09 Byte Betrieb in eingeschränkter Funktion ohne 'time'- Attribute möglich
  48. # 0.31 2017-09-10 Byte Commandref ergänzt Deutsch/Englisch
  49. # 0.32 2017-09-16 Byte Fehlerkorrekturen
  50. # 0.34 2017-09-17 Invers Dokumentation, Byte Korrekturen Log
  51. # 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 .
  52. # 0.36 2017-09-24 Byte Device0 Favoritenanfahrt und Positionsanfahrt durch FHEM möglich
  53. # 0.37 2017-09-25 SMag Prerelease-Vorbereitungen. Codeformatierung, Fehlerkorrekturen, Textkorrekturen.
  54. # 0.38 2017-09-27 optimierung sub Siro_Setgroup($) -> laufzeitverbesserung
  55. #
  56. # 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
  57. # 0.40 2017-10-15 Byte Code bereinigt
  58. # 0.41 2017-10-17 Byte anpassung der %Sets je nach device ( groupdevice )
  59. # 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
  60. # 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
  61. # 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 )
  62. # 0.45 2017-10-28 Byte fehler bei erneutem Kommando während Positionsanfahrten behoben
  63. # 0.46 2017-05-11 Byte fehler bei fhem-neustart behoben
  64. # 0.47 2017-11-11 Byte attr Disable zugefügt.
  65. ################################################################################################################
  66. # Todo's:
  67. # -
  68. # -
  69. ###############################################################################################################
  70. package main;
  71. use strict;
  72. use warnings;
  73. my $version = "V 0.47";
  74. my %codes = (
  75. "55" => "stop", # Stop the current movement or move to custom position
  76. "11" => "off", # Move "up"
  77. "33" => "on", # Move "down"
  78. "CC" => "prog", # Programming-Mode (Remote-control-key: P2)
  79. );
  80. my %sets = (
  81. "open" => "noArg",
  82. "close" => "noArg",
  83. "off" => "noArg",
  84. "stop" => "noArg",
  85. "on" => "noArg",
  86. "fav" => "noArg",
  87. "prog" => "noArg",
  88. "prog_stop" => "noArg",
  89. "position" => "slider,0,1,100", # Wird nur bei vorhandenen time_to attributen gesetzt
  90. "state" => "noArg" ,
  91. "set_favorite" => "noArg",
  92. "down_for_timer" => "textField",
  93. "up_for_timer" => "textField"
  94. );
  95. my %sendCommands = (
  96. "off" => "off",
  97. "stop" => "stop",
  98. "on" => "on",
  99. "open" => "off",
  100. "close" => "on",
  101. "fav" => "fav",
  102. "prog" => "prog",
  103. "set_favorite" => "setfav"
  104. );
  105. my %siro_c2b;
  106. my %models = (
  107. siroblinds => 'blinds',
  108. siroshutter => 'shutter'
  109. );
  110. #################################################################
  111. sub Siro_Initialize($) {
  112. my ($hash) = @_;
  113. # Map commands from web interface to codes used in Siro
  114. foreach my $k ( keys %codes ) {
  115. $siro_c2b{ $codes{$k} } = $k;
  116. }
  117. $hash->{SetFn} = "Siro_Set";
  118. $hash->{NotifyFn} = "Siro_Notify";
  119. $hash->{ShutdownFn} = "Siro_Shutdown";
  120. #$hash->{StateFn} = "Siro_SetState"; #change
  121. $hash->{DefFn} = "Siro_Define";
  122. $hash->{UndefFn} = "Siro_Undef";
  123. $hash->{DeleteFn} = "Siro_Delete";
  124. $hash->{ParseFn} = "Siro_Parse";
  125. $hash->{AttrFn} = "Siro_Attr";
  126. $hash->{Match} = "^P72#[A-Fa-f0-9]+";
  127. $hash->{AttrList} = " IODev"
  128. . " disable:0,1"
  129. . " SignalRepeats:1,2,3,4,5,6,7,8,9"
  130. . " SignalLongStopRepeats:10,15,20"
  131. . " channel_send_mode_1:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15"
  132. . " $readingFnAttributes"
  133. . " setList"
  134. . " ignore:0,1"
  135. . " dummy:1,0"
  136. # . " model:siroblinds,siroshutter"
  137. . " time_to_open"
  138. . " time_to_close"
  139. . " time_down_to_favorite"
  140. . " hash"
  141. . " operation_mode:0,1"
  142. . " debug_mode:0,1"
  143. . " down_limit_mode_1:slider,0,1,100"
  144. . " down_auto_stop:slider,0,1,100"
  145. . " invers_position:0,1"
  146. . " prog_fav_sequence";
  147. $hash->{AutoCreate} =
  148. {
  149. "Siro.*" =>
  150. {
  151. ATTR => "event-min-interval:.*:300 event-on-change-reading:.*",
  152. FILTER => "%NAME",
  153. autocreateThreshold => "2:10"
  154. }
  155. };
  156. $hash->{NOTIFYDEV} = "global";
  157. Siro_LoadHelper($hash) if($init_done);
  158. }
  159. #################################################################
  160. sub Siro_Define($$) {
  161. my ( $hash, $def ) = @_;
  162. my @a = split( "[ \t][ \t]*", $def );
  163. my $u = "Wrong syntax: define <name> Siro id ";
  164. my $askedchannel; # Angefragter kanal
  165. # Fail early and display syntax help
  166. if ( int(@a) < 3 ) {
  167. return $u;
  168. }
  169. if ( $a[2] =~ m/^[A-Fa-f0-9]{8}$/i ){
  170. $hash->{ID} = uc(substr($a[2], 0, 7));
  171. $hash->{CHANNEL} = sprintf( "%d", hex(substr($a[2], 7, 1)) );
  172. $askedchannel=sprintf( "%d", hex(substr($a[2], 7, 1)) );;
  173. }
  174. else
  175. {
  176. return "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. "
  177. }
  178. my $test;
  179. my $device;
  180. my $chanm1;
  181. my $chan;
  182. my @channels = ('','0','1','2','3','4','5','6','7','8','9');
  183. my @testchannels; # Enthält alle Kanäle die in Benutzung sind
  184. my @keys;
  185. my @values;
  186. my $testname;
  187. $hash->{Version} = $version;
  188. my $name = $a[0];
  189. # Log3($name, 0, "Siro_define: $hash->{helper}{position} ");
  190. # if ($hash->{helper}{position} eq '')
  191. # {
  192. # $hash->{helper}{position}="0";
  193. # $hash->{helper}{aktMsg} = "stop".' '.'0'.' '.gettimeofday();
  194. # $hash->{helper}{lastMsg} = "stop".' '.'0'.' '.gettimeofday();
  195. # $hash->{helper}{lastProg} ="0";
  196. # $hash->{helper}{lastparse_stop} ="stop".' '.gettimeofday();
  197. # $hash->{helper}{lastparse} ="";
  198. # $hash->{helper}{parse_aborted} ="0";
  199. # }
  200. my $tn = TimeNow(); #Wird wohl nicht benötigt?!?! down_limit_mode_1
  201. if ($askedchannel ne "0")
  202. {
  203. #Setzen der vordefinierten Attribute
  204. $attr{$name}{devStateIcon} ="{return '.*:fts_shutter_1w_'.(int(\x{24}state/10)*10)}" if(!defined ($attr{$name}{devStateIcon})); #TMP_Byte09 !defined
  205. $attr{$name}{webCmd} ="stop:on:off:fav:position" if (!defined ($attr{$name}{webCmd}));
  206. $attr{$name}{down_limit_mode_1} ="100" if (!defined ($attr{$name}{down_limit_mode_1}));
  207. $attr{$name}{prog_fav_sequence} ="prog,2,stop,2,stop" if (!defined ($attr{$name}{prog_fav_sequence}));
  208. #$attr{$name}{room} ="Siro" if (!defined ($attr{$name}{genericDeviceType}));
  209. $attr{$name}{SignalLongStopRepeats} ="15" if (!defined ($attr{$name}{SignalLongStopRepeats}));
  210. $attr{$name}{SignalRepeats} ="8" if (!defined ($attr{$name}{SignalRepeats}));
  211. $attr{$name}{operation_mode} ="0" if (!defined ($attr{$name}{operation_mode}));
  212. $attr{$name}{down_auto_stop} ="100" if (!defined ($attr{$name}{down_auto_stop}));
  213. $attr{$name}{invers_position} ="0" if (!defined ($attr{$name}{invers_position}));
  214. }
  215. else
  216. {
  217. $attr{$name}{devStateIcon} ="{return '.*:fts_shutter_1w_'.(int(\x{24}state/10)*10)}" if(!defined ($attr{$name}{devStateIcon})); #TMP_Byte09 !defined
  218. $attr{$name}{webCmd} ="stop:on:off:fav:position" if (!defined ($attr{$name}{webCmd}));
  219. #$attr{$name}{room} ="Siro" if (!defined ($attr{$name}{genericDeviceType}));
  220. $attr{$name}{SignalLongStopRepeats} ="15" if (!defined ($attr{$name}{SignalLongStopRepeats}));
  221. $attr{$name}{SignalRepeats} ="8" if (!defined ($attr{$name}{SignalRepeats}));
  222. #$attr{$name}{SignalRepeats} ="2";
  223. $attr{$name}{down_auto_stop} ="100" if (!defined ($attr{$name}{down_auto_stop}));
  224. $attr{$name}{invers_position} ="0" if (!defined ($attr{$name}{invers_position}));
  225. }
  226. my $code = uc($a[2]);
  227. my $ncode = 1;
  228. my $devpointer = $hash->{ID}.$hash->{CHANNEL};
  229. $hash->{CODE}{ $ncode++ } = $code;
  230. $modules{Siro}{defptr}{$devpointer} = $hash;
  231. Log3($name, 5, "Siro_define: angelegtes Device - code -> $code name -> $name hash -> $hash ");
  232. AssignIoPort($hash);
  233. }
  234. #################################################################
  235. sub Siro_Undef($$)
  236. {
  237. my ( $hash, $name) = @_;
  238. delete( $modules{Siro}{defptr}{$hash} );
  239. return undef;
  240. }
  241. #################################################################
  242. sub Siro_Shutdown($)
  243. {
  244. my ( $hash ) = @_;
  245. my $name = $hash->{NAME};
  246. readingsSingleUpdate($hash, ".aktMsg",$hash->{helper}{aktMsg}, 0);
  247. readingsSingleUpdate($hash, ".lastMsg",$hash->{helper}{lastMsg}, 0);
  248. readingsSingleUpdate($hash, ".lastProg",$hash->{helper}{lastProg}, 0);
  249. readingsSingleUpdate($hash, ".lastparse",$hash->{helper}{lastparse}, 0);
  250. readingsSingleUpdate($hash, ".lastparse_stop",$hash->{helper}{lastparse_stop}, 0);
  251. readingsSingleUpdate($hash, ".parse_aborted",$hash->{helper}{parse_aborted}, 0);
  252. readingsSingleUpdate($hash, ".positionsave",$hash->{helper}{position}, 0);
  253. readingsSingleUpdate($hash, ".positiontimer",$hash->{helper}{positiontimer}, 0);
  254. return;
  255. }
  256. #################################################################
  257. sub Siro_LoadHelper($)
  258. {
  259. my ( $hash ) = @_;
  260. my $name = $hash->{NAME};
  261. my $save = ReadingsVal($name, '.aktMsg', 'undef');
  262. if ($save eq 'undef')
  263. {
  264. $hash->{helper}{position}="0";
  265. $hash->{helper}{aktMsg} = "stop".' '.'0'.' '.gettimeofday();
  266. $hash->{helper}{lastMsg} = "stop".' '.'0'.' '.gettimeofday();
  267. $hash->{helper}{lastProg} ="0";
  268. $hash->{helper}{lastparse_stop} ="stop".' '.gettimeofday();
  269. $hash->{helper}{lastparse} ="";
  270. $hash->{helper}{parse_aborted} ="0";
  271. }
  272. else
  273. {
  274. $hash->{helper}{aktMsg} = ReadingsVal($name, '.aktMsg', '');
  275. $hash->{helper}{lastMsg} = ReadingsVal($name, '.lastMsg', '');
  276. $hash->{helper}{lastparse} = ReadingsVal($name, '.lastparse', '');
  277. $hash->{helper}{lastProg} = ReadingsVal($name, '.lastProg', '');
  278. $hash->{helper}{lastparse_stop} = ReadingsVal($name, '.lastparse_stop', '');
  279. $hash->{helper}{parse_aborted} = ReadingsVal($name, '.parse_aborted', '');
  280. $hash->{helper}{position} = ReadingsVal($name, '.positionsave', '');
  281. $hash->{helper}{positiontimer} = ReadingsVal($name, '.positiontimer', '');
  282. }
  283. Log3($name, 5, "Siro: Helper initialisiert");
  284. return;
  285. }
  286. #################################################################
  287. sub Siro_Notify($$)
  288. {
  289. my ($own_hash, $dev_hash) = @_;
  290. my $ownName = $own_hash->{NAME}; # own name / hash
  291. my $devName = $dev_hash->{NAME}; # Device that created the events
  292. my $events = deviceEvents($dev_hash, 1);
  293. if($devName eq "global" && grep(m/^INITIALIZED|REREADCFG$/, @{$events}))
  294. {
  295. Siro_LoadHelper($own_hash);
  296. }
  297. return;
  298. }
  299. #################################################################
  300. sub Siro_Delete($$)
  301. {
  302. my ( $hash, $name ) = @_;
  303. return undef;
  304. }
  305. #################################################################
  306. sub Siro_SendCommand($@)
  307. {
  308. my ($hash, @args) = @_;
  309. my $ret = undef;
  310. my $cmd = $args[0]; # Command as text (on, off, stop, prog)
  311. my $message; # IO-Message (full)
  312. my $chan; # Channel
  313. my $binChannel; # Binary channel
  314. my $SignalRepeats; #
  315. my $name = $hash->{NAME};
  316. my $binHash;
  317. my $bin; # Full binary IO-Message
  318. my $binCommand;
  319. my $numberOfArgs = int(@args);
  320. my $command = $siro_c2b{ $cmd };
  321. my $io = $hash->{IODev}; # IO-Device (SIGNALduino)
  322. my $debug = AttrVal($name,'debug_mode', '0');
  323. Log3($name, 5, "Siro_sendCommand: hash -> $hash - $name -> cmd :$cmd: - args -> @args");
  324. if ($args[2] eq "longstop")
  325. {
  326. $SignalRepeats =AttrVal($name,'SignalLongStopRepeats', '15')
  327. }
  328. else
  329. {
  330. $SignalRepeats = AttrVal($name,'SignalRepeats', '10');
  331. }
  332. my $operationmode = AttrVal($name,'operation_mode', 'on');
  333. Log3($name, 5, "Siro_sendCommand: operationmode -> $operationmode");
  334. if ($operationmode eq '1')
  335. {
  336. $chan = AttrVal($name,'channel_send_mode_1', $hash->{CHANNEL});
  337. Log3($name, 5, "Siro_sendCommand: channel für OM1 -> $chan");
  338. }
  339. else
  340. {
  341. $chan = AttrVal($name,'channel', undef);
  342. if (!defined($chan))
  343. {
  344. $chan = $hash->{CHANNEL};
  345. }
  346. }
  347. if ($chan eq "0")
  348. {
  349. Log3($name, 5, "Siro_sendCommand: Aborted not sent on a channel 0 request ");
  350. return;
  351. }
  352. $binChannel = sprintf("%04b",$chan);
  353. Log3($name, 5, "Siro set channel: $chan ($binChannel) for $io->{NAME}");
  354. my $value = $name ." ". join(" ", @args);
  355. $binHash = sprintf( "%028b", hex( $hash->{ID} ) );
  356. Log3 $io, 5, "Siro_sendCommand: BinHash: = $binHash";
  357. $binCommand = sprintf( "%08b", hex( $command ) );
  358. Log3 $io, 5, "Siro_sendCommand: BinCommand: = $binCommand";
  359. $bin = $binHash . $binChannel . $binCommand; # Binary code to send
  360. Log3 $io, 5, "Siro_sendCommand: Siro set value = $value";
  361. $message = 'P72#' . $bin . '#R' . $SignalRepeats;
  362. if ($debug eq "1")
  363. {
  364. readingsSingleUpdate($hash, "DEBUG_SEND","$name -> message :$message: ", 1);
  365. }
  366. else
  367. {
  368. Log3 $io, 5, "Siro_sendCommand: Siro_sendCommand: $name -> message :$message: ";
  369. IOWrite($hash, 'sendMsg', $message);
  370. }
  371. my $devicename =$hash->{IODev};
  372. Log3($name, 5, "Siro_sendCommand: name -> $name command -> $cmd ");
  373. Log3($name, 3, "Siro_sendCommand: execute comand $cmd - sendMsg to $devicename channel $chan -> $message ");
  374. return $ret;
  375. }
  376. #################################################################
  377. sub Siro_Parse($$)
  378. {
  379. my $debug='';
  380. my @args;
  381. my ($hash, $msg) = @_;
  382. my $doubelmsgtime = 2; # zeit in sek in der doppelte nachrichten blockiert werden
  383. my $favcheck =$doubelmsgtime+1; # zeit in der ein zweiter stop kommen muss/darf für fav
  384. my $testid = substr($msg, 4, 8);
  385. my $testcmd = substr($msg, 12, 2);
  386. my $timediff;
  387. my $name = $hash->{NAME};
  388. return "" if(IsDisabled($name));
  389. if(my $lh = $modules{Siro}{defptr}{$testid})
  390. {
  391. my $name = $lh->{NAME};
  392. Log3 $hash, 3, "Siro_Parse: Incomming msg from IODevice $testid - $name device is defined";
  393. if (defined ($name) && $testcmd ne "54" ) # prüfe auf doppele msg falls gerät vorhanden und cmd nicht stop
  394. {
  395. Log3 $lh, 5, "Siro_Parse: Incomming msg $msg from IODevice name/DEF $testid - Hash -> $lh";
  396. my $testparsetime = gettimeofday();
  397. my $lastparse = $lh->{helper}{lastparse};
  398. my @lastparsearray =split(/ /,$lastparse);
  399. if (!defined($lastparsearray[1])){$lastparsearray[1] = 0};
  400. if (!defined($lastparsearray[0])){$lastparsearray[0] = ""};
  401. $timediff = $testparsetime-$lastparsearray[1];
  402. my $abort ="false";
  403. Log3 $lh, 5, "Siro_Parse: test doublemsg ";
  404. Log3 $lh, 5, "Siro_Parse: lastparsearray[0] -> $lastparsearray[0] ";
  405. Log3 $lh, 5, "Siro_Parse: lastparsearray[1] -> $lastparsearray[1] ";
  406. Log3 $lh, 5, "Siro_Parse: testparsetime -> $testparsetime ";
  407. Log3 $lh, 5, "Siro_Parse: timediff -> $timediff ";
  408. if ($msg eq $lastparsearray[0])
  409. {
  410. if ($timediff < $doubelmsgtime )
  411. {
  412. $abort ="true";
  413. }
  414. }
  415. $lh->{helper}{lastparse} = "$msg $testparsetime";
  416. if ($abort eq "true")
  417. {
  418. Log3 $lh, 4, "Siro_Parse: aborted , doublemsg ";
  419. return $name;
  420. }
  421. Log3 $lh, 4, "Siro_Parse: not aborted , no doublemsg ";
  422. }
  423. my (undef ,$rawData) = split("#",$msg);
  424. my $hlen = length($rawData);
  425. my $blen = $hlen * 4;
  426. my $bitData = unpack("B$blen", pack("H$hlen", $rawData));
  427. Log3 $hash, 5, "Siro_Parse: msg = $rawData length: $msg";
  428. Log3 $hash, 5, "Siro_Parse: rawData = $rawData length: $hlen";
  429. Log3 $hash, 5, "Siro_Parse: converted to bits: $bitData";
  430. my $id = substr($rawData, 0, 7); # The first 7 hexcodes are the ID
  431. my $BitChannel = substr($bitData, 28, 4); # Not needed atm
  432. my $channel = sprintf( "%d", hex(substr($rawData, 7, 1)) ); # The last hexcode-char defines the channel
  433. my $channelhex = substr($rawData, 7, 1) ; # tmp
  434. my $cmd = sprintf( "%d", hex(substr($rawData, 8, 1)) );
  435. my $newstate = $codes{ $cmd . $cmd}; # Set new state
  436. my $deviceCode = $id . $channelhex; # Tmp change channel -> channelhex. The device-code is a combination of id and channel
  437. $debug=$debug."id-".$id." ";
  438. Log3 $hash, 5, "Siro_Parse: device ID: $id";
  439. Log3 $hash, 5, "Siro_Parse: Channel: $channel";
  440. Log3 $hash, 5, "Siro_Parse: Cmd: $cmd Newstate: $newstate";
  441. Log3 $hash, 5, "Siro_Parse: deviceCode: $deviceCode";
  442. if (defined ($name) && $testcmd eq "54" ) # prüfe auf doppele msg falls gerät vorhanden und cmd stop
  443. {
  444. # Log3 $lh, 5, "Siro_Parse: prüfung auf douplestop ";
  445. my $testparsetime = gettimeofday();
  446. my $lastparsestop = $lh->{helper}{lastparse_stop};
  447. my $parseaborted = $lh->{helper}{parse_aborted};
  448. my @lastparsestoparray =split(/ /,$lastparsestop);
  449. my $timediff = $testparsetime-$lastparsestoparray[1];
  450. my $abort ="false";
  451. $parseaborted=0 if (!defined ($parseaborted));
  452. Log3 $lh, 5, "Siro_Parse: test doublestop ";
  453. Log3 $lh, 5, "Siro_Parse: lastparsearray[0] -> $lastparsestoparray[0] ";
  454. Log3 $lh, 5, "Siro_Parse: lastparsearray[1] -> $lastparsestoparray[1] ";
  455. Log3 $lh, 5, "Siro_Parse: testparsetime -> $testparsetime ";
  456. Log3 $lh, 5, "Siro_Parse: timediff -> $timediff ";
  457. Log3 $lh, 5, "Siro_Parse: parseaborted -> $parseaborted ";
  458. if ($newstate eq $lastparsestoparray[0])
  459. {
  460. if ($timediff < 3 )
  461. {
  462. $abort ="true";
  463. $parseaborted++;
  464. }
  465. }
  466. if ($abort eq "true" && $parseaborted < 8 )
  467. {
  468. $lh->{helper}{parse_aborted}=$parseaborted;
  469. Log3 $lh, 5, "Siro_Parse: aborted , doublestop ";
  470. return $name;
  471. }
  472. $lh->{helper}{lastparse_stop} = "$newstate $testparsetime";
  473. if ( $parseaborted >= 7 )
  474. {
  475. $parseaborted = 0;
  476. $lh->{helper}{parse_aborted}=$parseaborted;
  477. $testparsetime = gettimeofday();
  478. $lh->{helper}{lastparse_stop} = "$newstate $testparsetime";
  479. if ($newstate eq "stop")
  480. {
  481. Log3 $lh, 3, "Siro_Parse: double_msg signal_favoritenanfahrt erkannt ";
  482. $newstate="fav";
  483. $args[0]="fav";
  484. }
  485. }
  486. }
  487. if (defined ($name))
  488. {
  489. $args[0]=$newstate;
  490. my $parseaborted = 0;
  491. $lh->{helper}{parse_aborted}=$parseaborted;
  492. $debug=$debug.' '.$name;
  493. my $operationmode = AttrVal($name,'operation_mode', '0');
  494. my $debugmode = AttrVal($name,'debug_mode', '0');
  495. my $chan;
  496. if ($operationmode eq '0')
  497. {
  498. $chan = AttrVal($name,'channel', undef);
  499. if (!defined($chan))
  500. {
  501. $chan = $lh->{CHANNEL};
  502. }
  503. }
  504. if ($operationmode eq '1')
  505. {
  506. $chan = AttrVal($name,'channel', undef);
  507. if (!defined($chan))
  508. {
  509. $chan = $lh->{CHANNEL};
  510. }
  511. }
  512. my $aktMsg = $lh->{helper}{aktMsg} ;
  513. my @last_action_array=split(/ /,$aktMsg);
  514. my $lastaction = $last_action_array[0];
  515. my $lastaction_position = $last_action_array[1];
  516. my $lastaction_time = $last_action_array[2];
  517. readingsSingleUpdate($lh, "parsestate", $newstate, 1);
  518. Log3 $lh, 5, "Siro_Parse: $name $newstate";
  519. Log3 $lh, 5, "Siro_Parse: operationmode -> $operationmode";
  520. if ($operationmode ne '1' || $chan eq "0")
  521. {
  522. Log3 $lh, 5, "Siro_Parse: set mode to physical";
  523. $lh->{helper}{MODE} = "physical";
  524. $debug=$debug.' physical';
  525. }
  526. else
  527. {
  528. $lh->{helper}{MODE} = "repeater";
  529. $debug=$debug.' repeater';
  530. }
  531. if ($chan eq "0")
  532. {
  533. $args[1]="physical";
  534. $debug=$debug.' physical';
  535. }
  536. Log3 $lh, 2, "Siro_Parse -> Siro_Set: $lh, $name, @args";
  537. Siro_Set($lh, $name, @args) ;
  538. $debug=$debug.' '.$lh;
  539. if($debugmode eq "1")
  540. {
  541. readingsSingleUpdate($lh, "DEBUG_PARSE",$debug, 1);
  542. }
  543. ##############################################
  544. # Return list of affected devices
  545. #my ( $hash, $name, @args ) = @_;
  546. ##############################################
  547. return $name;
  548. }
  549. }
  550. else
  551. {
  552. my (undef ,$rawData) = split("#",$msg);
  553. my $hlen = length($rawData);
  554. my $blen = $hlen * 4;
  555. my $bitData = unpack("B$blen", pack("H$hlen", $rawData));
  556. Log3 $hash, 5, "Siro_Parse: msg = $rawData length: $msg";
  557. Log3 $hash, 5, "Siro_Parse: rawData = $rawData length: $hlen";
  558. Log3 $hash, 5, "Siro_Parse: converted to bits: $bitData";
  559. my $id = substr($rawData, 0, 7); # The first 7 hexcodes are the ID
  560. my $BitChannel = substr($bitData, 28, 4); # Not needed atm
  561. my $channel = sprintf( "%d", hex(substr($rawData, 7, 1)) ); # The last hexcode-char defines the channel
  562. my $channelhex = substr($rawData, 7, 1) ; # tmp
  563. my $cmd = sprintf( "%d", hex(substr($rawData, 8, 1)) );
  564. my $newstate = $codes{ $cmd . $cmd}; # Set new state
  565. my $deviceCode = $id . $channelhex; # Tmp change channel -> channelhex. The device-code is a combination of id and channel
  566. $debug=$debug."id-".$id." ";
  567. Log3 $hash, 5, "Siro_Parse: device ID: $id";
  568. Log3 $hash, 5, "Siro_Parse: Channel: $channel";
  569. Log3 $hash, 5, "Siro_Parse: Cmd: $cmd Newstate: $newstate";
  570. Log3 $hash, 5, "Siro_Parse: deviceCode: $deviceCode";
  571. Log3 $hash, 2, "Siro unknown device $deviceCode, please define it";
  572. return "UNDEFINED Siro_$deviceCode Siro $deviceCode";
  573. }
  574. }
  575. #############################################################
  576. sub Siro_Attr(@)
  577. {
  578. my ($cmd,$name,$aName,$aVal) = @_;
  579. my $hash = $defs{$name};
  580. return "\"Siro Attr: \" $name does not exist" if (!defined($hash));
  581. my $channel = ($hash->{CHANNEL});
  582. if ($channel eq "0")
  583. {
  584. my @notallowed = ("prog_fav_sequence", "time_to_open", "time_to_close", "operation_mode", "channel_send_mode_1", "time_down_to_favorite");
  585. foreach my $test (@notallowed)
  586. {
  587. if ($test eq $aName ){return "\"Siro Attr: \" $name is a group device, the attribute $aName $aVal is not allowed here.";}
  588. }
  589. }
  590. return undef if (!defined($name));
  591. return undef if (!defined($aName));
  592. #return undef if (!defined($aVal));
  593. if ($cmd eq "set")
  594. {
  595. if ($aName eq "debug_mode" && $aVal eq "0")
  596. {
  597. Log3 $hash, 5, "debug_mode: reading deleted";
  598. delete ($hash->{READINGS}{DEBUG_SEND});
  599. delete ($hash->{READINGS}{DEBUG_PARSE});
  600. delete ($hash->{READINGS}{DEBUG_SET});
  601. }
  602. if ($aName eq "debug_mode" && $aVal eq "1")
  603. {
  604. readingsSingleUpdate($hash, "DEBUG_SEND","aktiv", 1);
  605. readingsSingleUpdate($hash, "DEBUG_PARSE","aktiv", 1);
  606. readingsSingleUpdate($hash, "DEBUG_SET","aktiv", 1);
  607. Log3 $hash, 5, "debug_mode: create reading";
  608. }
  609. if ($aName eq "invers_position")
  610. {
  611. if ( $aVal eq "0" )
  612. {
  613. my $oldicon = "{return '.*:fts_shutter_1w_'.(100-(int(\$state/10)*10))}";
  614. Log3 $hash, 3, "Siro_Attr: change attr old -> $attr{$name}{devStateIcon} $oldicon";
  615. if ($attr{$name}{devStateIcon} eq $oldicon)
  616. {
  617. Log3 $hash, 3, "Siro_Attr: ersetzt";
  618. $attr{$name}{devStateIcon} ="{return '.*:fts_shutter_1w_'.(int(\$state/10)*10)}" ;
  619. }
  620. if (defined ($attr{$name}{down_auto_stop}))
  621. {
  622. my $autostop = AttrVal($name,'down_auto_stop', 'undef');
  623. $autostop = 100 - $autostop;
  624. $attr{$name}{down_auto_stop} =$autostop;
  625. }
  626. my $oldstate =$hash->{helper}{position};
  627. my $newState = $oldstate;
  628. my $updateState;
  629. Log3 $hash, 3, "Siro_Attr: state old -> $oldstate new -> $newState";
  630. Siro_UpdateState( $hash, $newState, '', $updateState, 1 );
  631. }
  632. if ( $aVal eq "1" )
  633. {
  634. my $oldicon = "{return '.*:fts_shutter_1w_'.(int(\$state/10)*10)}";
  635. Log3 $hash, 3, "Siro_Attr: change attr old -> $attr{$name}{devStateIcon} $oldicon";
  636. if ($attr{$name}{devStateIcon} eq $oldicon)
  637. {
  638. Log3 $hash, 3, "Siro_Attr: ersetzt";
  639. $attr{$name}{devStateIcon} ="{return '.*:fts_shutter_1w_'.(100-(int(\$state/10)*10))}" ;
  640. }
  641. if (defined ($attr{$name}{down_auto_stop}))
  642. {
  643. my $autostop = AttrVal($name,'down_auto_stop', 'undef');
  644. $autostop = 100 - $autostop;
  645. $attr{$name}{down_auto_stop} =$autostop;
  646. }
  647. my $oldstate =$hash->{helper}{position};
  648. my $newState = 100 - $oldstate;
  649. my $updateState;
  650. Log3 $hash, 3, "Siro_Attr: state old -> $oldstate new -> $newState";
  651. Siro_UpdateState( $hash, $newState, '', $updateState, 1 );
  652. }
  653. }
  654. }
  655. if ($cmd eq "del")
  656. {
  657. if ($aName eq "invers_position")
  658. {
  659. my $oldicon = "{return '.*:fts_shutter_1w_'.(100-(int(\$state/10)*10))}";
  660. Log3 $hash, 3, "Siro_Attr delete invers: change attr old -> $attr{$name}{devStateIcon} $oldicon";
  661. if ($attr{$name}{devStateIcon} eq $oldicon)
  662. {
  663. Log3 $hash, 3, "Siro_Attr: ersetzt";
  664. $attr{$name}{devStateIcon} ="{return '.*:fts_shutter_1w_'.(int(\$state/10)*10)}" ;
  665. }
  666. my $oldstate =$hash->{helper}{position};
  667. my $newState = $oldstate;
  668. my $updateState;
  669. Log3 $hash, 3, "Siro_Attr: state old -> $oldstate new -> $newState";
  670. Siro_UpdateState( $hash, $newState, '', $updateState, 1 );
  671. }
  672. }
  673. return undef;
  674. }
  675. #################################################################
  676. # Call with hash, name, virtual/send, set-args
  677. sub Siro_Set($@)
  678. {
  679. my $testtimestart = gettimeofday();
  680. my $debug;
  681. my ( $hash, $name, @args ) = @_;
  682. return "" if(IsDisabled($name));
  683. # Set without argument #parseonly
  684. my $numberOfArgs = int(@args);
  685. my $nodrive = "false";
  686. $args[2]="0";
  687. my $action ="no action";
  688. return "Siro_set: No set value specified" if ( $numberOfArgs < 1 );
  689. my $cmd = $args[0];
  690. my $invers = AttrVal($name,'invers_position', '0');
  691. my $runningaction = ReadingsVal($name, 'action', 'no action');
  692. my $runningtime = 0;
  693. # teste auf hilfsvariablen
  694. my $save = ReadingsVal($name, '.aktMsg', 'undef');
  695. if ($save eq 'undef')
  696. {
  697. $hash->{helper}{position}="0";
  698. $hash->{helper}{aktMsg} = "stop".' '.'0'.' '.gettimeofday();
  699. $hash->{helper}{lastMsg} = "stop".' '.'0'.' '.gettimeofday();
  700. $hash->{helper}{lastProg} ="0";
  701. $hash->{helper}{lastparse_stop} ="stop".' '.gettimeofday();
  702. $hash->{helper}{lastparse} ="";
  703. $hash->{helper}{parse_aborted} ="0";
  704. readingsSingleUpdate($hash, ".aktMsg",$hash->{helper}{aktMsg}, 0);
  705. readingsSingleUpdate($hash, ".lastMsg",$hash->{helper}{lastMsg}, 0);
  706. readingsSingleUpdate($hash, ".lastProg",$hash->{helper}{lastProg}, 0);
  707. readingsSingleUpdate($hash, ".lastparse",$hash->{helper}{lastparse}, 0);
  708. readingsSingleUpdate($hash, ".lastparse_stop",$hash->{helper}{lastparse_stop}, 0);
  709. readingsSingleUpdate($hash, ".parse_aborted",$hash->{helper}{parse_aborted}, 0);
  710. readingsSingleUpdate($hash, ".positionsave",$hash->{helper}{position}, 0);
  711. readingsSingleUpdate($hash, ".positiontimer",$hash->{helper}{positiontimer}, 0);
  712. }
  713. ######################################### für ECHO
  714. if ( $cmd =~ /^\d+$/)
  715. {
  716. if ($cmd >= 0 && $cmd <= 100)
  717. {
  718. $args[0] ="position";
  719. $args[1] =$cmd;
  720. $cmd = "position";
  721. }
  722. }
  723. #########################################
  724. #diverse befehle bei laufender aktion abfangen
  725. if (($cmd eq "position" || $cmd eq 'up_for_timer' || $cmd eq 'on_for_timer') && $runningaction ne 'no action')
  726. {
  727. my $restartmsg = $name.' '.$args[0].' '.$args[1];
  728. Log3($name,3,"Siro_Set: laufende action gefunden - restart msg -> $restartmsg ");
  729. InternalTimer(gettimeofday()+0,"Siro_Restartcmd",$restartmsg);
  730. $args[0] ="stop";
  731. $args[1] ='';
  732. $cmd = "stop";
  733. }
  734. #########################################
  735. # invertiere position
  736. if ($cmd eq "position" && $invers eq "1")
  737. {
  738. my $noinvers = $args[1];
  739. my $inversposition = 100 - $args[1];
  740. $args[1] = $inversposition;
  741. Log3($name,3,"Siro_Set: invertiere Position - input -> $noinvers - inverted -> $inversposition ");
  742. }
  743. #########################################
  744. #########################################
  745. if (!defined $args[2])
  746. {
  747. $args[2]='';
  748. }
  749. if (!defined $args[1])
  750. {
  751. $args[2]='0';
  752. $args[1]='';
  753. }
  754. if ($args[1] eq "physical")
  755. {
  756. $hash->{helper}{MODE} = "physical";
  757. }
  758. if (!defined($hash)){return;}
  759. if (!defined($name)){return;}
  760. $debug = "$hash, $name, @args";
  761. if ($cmd ne "?")
  762. {
  763. Log3($name,5,"Siro_Set: aufgerufen -> cmd -> $cmd args -> @args ");
  764. }
  765. #########################################
  766. # up/down for timer mappen auf on/off und timer für stop setzen
  767. if ($cmd eq 'up_for_timer')
  768. {
  769. Log3($name,5,"Siro_Set: up_for_timer @args $args[1]");
  770. $cmd ="off";
  771. InternalTimer($testtimestart+$args[1], "Siro_Stop", $hash, 0); # State auf Stopp
  772. $args[0] =$cmd;
  773. $action = 'up for timer '.$args[1];
  774. readingsSingleUpdate($hash, "action",$action, 1); #tmp
  775. }
  776. if ($cmd eq 'down_for_timer')
  777. {
  778. Log3($name,3,"Siro_Set: down_for_timer @args $args[1]");
  779. $cmd ="on";
  780. readingsSingleUpdate($hash, "action",'down for timer '.$args[1], 1); #tmp
  781. InternalTimer($testtimestart+$args[1], "Siro_Stop", $hash, 0); # State auf Stopp
  782. $args[0] =$cmd;
  783. $action = 'down for timer '.$args[1];
  784. readingsSingleUpdate($hash, "action",$action, 1); #tmp
  785. }
  786. #########################################
  787. # diverse befehle auf bekannte befehle mappen
  788. if ($cmd eq 'open')
  789. {
  790. $cmd ="off";
  791. $args[0] =$cmd;
  792. }
  793. if ($cmd eq 'close')
  794. {
  795. $cmd ="on";
  796. $args[0] =$cmd;
  797. }
  798. #########################################
  799. $hash->{Version} = $version;
  800. # diverse attr einlesen
  801. my $debugmode = AttrVal($name,'debug_mode', '0');
  802. my $testchannel = $hash->{CHANNEL};
  803. my $timetoopen = AttrVal($name,'time_to_open', 'undef'); # fahrzeit komplett runter
  804. my $timetoclose = AttrVal($name,'time_to_close', 'undef'); # fahrzeit komplett hoch
  805. my $operationmode = AttrVal($name,'operation_mode', '0'); # mode 0 normal / 1 repeater
  806. my $limitedmode="off";
  807. my $downlimit = AttrVal($name,'down_limit_mode_1', '100'); # maximale runterfahrt im mode 1
  808. my $autostop = AttrVal($name,'down_auto_stop', '100'); # automatischer stop bei runterfahrt
  809. #########################################
  810. # sets an device anpassen
  811. if ($testchannel ne "0")
  812. {
  813. %sets = (
  814. "open" => "noArg",
  815. "close" => "noArg",
  816. "off" => "noArg",
  817. "stop" => "noArg",
  818. "on" => "noArg",
  819. "fav" => "noArg",
  820. "prog" => "noArg",
  821. "prog_stop" => "noArg",
  822. "position" => "slider,0,1,100", # Wird nur bei vorhandenen time_to attributen gesetzt
  823. "state" => "noArg" ,
  824. "set_favorite" => "noArg",
  825. "down_for_timer" => "textField",
  826. "up_for_timer" => "textField" # Ggf. entfernen (Alexa)
  827. );
  828. if($timetoopen eq 'undef' || $timetoclose eq 'undef')
  829. {
  830. if ($attr{$name}{webCmd} eq "stop:on:off:fav:position")
  831. {
  832. $attr{$name}{webCmd} ="stop:on:off:fav";
  833. }
  834. $limitedmode="on";
  835. $hash->{INFO} = "limited function without ATTR time_to_open / time_to_close / time_down_to_favorite";
  836. }
  837. else
  838. {
  839. if ($attr{$name}{webCmd} eq "stop:on:off:fav")
  840. {
  841. $attr{$name}{webCmd} ="stop:on:off:fav:position";
  842. }
  843. delete($hash->{INFO});
  844. }
  845. }
  846. else # this block is for groupdevicec ( channel 0 )
  847. {
  848. Log3($name,5,"Siro_Set: Groupdevice erkannt ");
  849. %sets = (
  850. "open" => "noArg",
  851. "close" => "noArg",
  852. "off" => "noArg",
  853. "stop" => "noArg",
  854. "on" => "noArg",
  855. "fav" => "noArg",
  856. #"prog" => "noArg",
  857. #"prog_stop" => "noArg",
  858. "position" => "slider,0,1,100", # Wird nur bei vorhandenen time_to attributen gesetzt
  859. "state" => "noArg" ,
  860. #"set_favorite" => "noArg",
  861. "down_for_timer" => "textField",
  862. "up_for_timer" => "textField"
  863. );
  864. if ($cmd ne "?") #change
  865. {
  866. my $timetoopen = "15";
  867. my $timetoclose = "15";
  868. my $testhashtmp ="";
  869. my $testhashtmp1 ="";
  870. my $namex ="";
  871. my $testid ="";
  872. my $id = $hash->{ID};
  873. my @grouphash;
  874. my @groupnames;
  875. @groupnames = Siro_Testgroup($hash,$id);
  876. $hash->{INFO} = "This is a group Device with limited functions affected the following devices:\n @groupnames";
  877. my $groupcommand = $cmd.",".$args[0].",".$args[1].",".$hash;
  878. $hash->{helper}{groupcommand} = $groupcommand;
  879. InternalTimer(gettimeofday()+0,"Siro_Setgroup",$hash,1);
  880. }
  881. $hash->{helper}{MODE}="physical";
  882. }
  883. #########################################
  884. # Check for unknown arguments
  885. if(!exists($sets{$cmd}))
  886. {
  887. my @cList;
  888. # Overwrite %sets with setList
  889. my $atts = AttrVal($name,'setList',"");
  890. my %setlist = split("[: ][ ]*", $atts);
  891. foreach my $k (sort keys %sets)
  892. {
  893. my $opts = undef;
  894. $opts = $sets{$k};
  895. $opts = $setlist{$k} if(exists($setlist{$k}));
  896. if (defined($opts))
  897. {
  898. push(@cList,$k . ':' . $opts);
  899. }
  900. else
  901. {
  902. push (@cList,$k);
  903. }
  904. } # end foreach
  905. return "Siro_set: Unknown argument $cmd, choose one of " . join(" ", @cList);
  906. }
  907. #########################################
  908. # undefinierte attr time to open/close abfangen
  909. if(($timetoopen eq 'undef' || $timetoclose eq 'undef') && $testchannel ne "0")
  910. {
  911. Log3($name,1,"Siro_Set:limited function without definition of time_to_close and time_to_open. Please define this attributes.");
  912. $nodrive ="true";
  913. $timetoopen=1;
  914. $timetoclose=1;
  915. }
  916. #########################################
  917. # progmodus setzen
  918. if ($cmd eq "prog")
  919. {
  920. $hash->{helper}{lastProg} = gettimeofday()+180; # 3 min programmiermodus
  921. }
  922. if ($cmd eq "prog_stop")
  923. {
  924. $hash->{helper}{lastProg} = gettimeofday();
  925. return;
  926. }
  927. #########################################
  928. # favoritenposition speichern
  929. if ($cmd eq "set_favorite")
  930. {
  931. if($debugmode eq "1")
  932. {
  933. readingsSingleUpdate($hash, "DEBUG_SET",'setze Favorite', 1);
  934. }
  935. my $sequence;
  936. my $sequenceraw = AttrVal($name,'prog_fav_sequence', '');
  937. if (defined ($attr{$name}{time_down_to_favorite}))
  938. {
  939. $sequence = $sequenceraw.',2,'.$sequenceraw;
  940. Log3($name,0,"Siro_Set: delete and set favorit -> $sequence");
  941. }
  942. else
  943. {
  944. $sequence = $sequenceraw ;
  945. Log3($name,0,"Siro_Set: set favorit -> $sequence");
  946. }
  947. $hash->{sequence} = $sequence; # 3 Min Programmiermodus
  948. InternalTimer(gettimeofday()+1,"Siro_Sequence",$hash,0); # State auf stop setzen nach Erreichen der Fahrdauer
  949. Log3($name,1,"Siro_Set:setting new favorite");
  950. return;
  951. }
  952. #########################################
  953. # variablenberechnung für folgende funktionen
  954. my $check='check';
  955. my $bmode = $hash->{helper}{aktMsg};
  956. if ($bmode eq "repeater")
  957. {
  958. $check ='nocheck';
  959. }
  960. my $ondirekttime = $timetoclose/100; # Zeit für 1 Prozent Runterfahrt
  961. my $offdirekttime = $timetoopen/100; # Zeit für 1 Prozent Hochfahrt
  962. #my $runningtime;
  963. my $timetorun;
  964. my $newposstate;
  965. if (defined ($args[1]))
  966. {
  967. if ( $args[1]=~ /^\d+$/)
  968. {
  969. $newposstate = $args[1];# Anzufahrende Position in Prozent
  970. Log3($name,5,"Siro_Set:newposstate -> $newposstate");
  971. $timetorun = $timetoclose/100*$newposstate; # Laufzeit von 0 prozent }bis zur anzufahrenden Position
  972. }
  973. }
  974. my $virtual; # Kontrollvariable der Positionsanfahrt
  975. my $newState;
  976. my $updateState;
  977. my $positiondrive;
  978. my $state = $hash->{STATE};
  979. my $aktMsg = $hash->{helper}{aktMsg} ;
  980. my @last_action_array=split(/ /,$aktMsg);
  981. my $lastaction = $last_action_array[0];
  982. my $lastaction_position = $last_action_array[1];
  983. my $lastaction_time = $last_action_array[2];
  984. my $befMsg = $hash->{helper}{lastMsg};
  985. my @before_action_array=split(/ /,$befMsg);
  986. my $beforeaction_position = $before_action_array[1];
  987. my $timebetweenmsg = $testtimestart-$last_action_array[2];# Zeit zwischen dem aktuellen und letzten Befehl
  988. $timebetweenmsg = (int($timebetweenmsg*10)/10);
  989. my $oldposition; # Alter Stand in Prozent
  990. my $newposition ; # Errechnende Positionsänderung in Prozent - > bei on plus alten Stand
  991. my $finalposition;# Erreichter Rollostand in Prozent für state;
  992. my $time_to_favorite = AttrVal($name,'time_down_to_favorite', 'undef');
  993. my $favorit_position;
  994. my $mode = $hash->{helper}{MODE};# Betriebsmodus virtual, physicalFP
  995. my $lastprogmode = $hash->{helper}{lastProg};
  996. my $testprogmode = $testtimestart;
  997. my $testprog = int($testprogmode) - int($lastprogmode);
  998. my $oldstate = ReadingsVal($name, 'state', 100);
  999. Log3($name,5,"Siro_set: test auf double stop");
  1000. Log3($name,5,"Siro_set: testprogmode -> $testprogmode");
  1001. Log3($name,5,"Siro_set: lastprogmode -> $lastprogmode");
  1002. Log3($name,5,"Siro_set: lastaction -> $lastaction");
  1003. Log3($name,5,"Siro_set: cmd -> $cmd");
  1004. # verhindern eines doppelten stoppbefehls ausser progmodus 1
  1005. if ($testprogmode > $lastprogmode) # Doppelten Stoppbefehl verhindern, ausser progmodus aktiv
  1006. {
  1007. if ($lastaction eq 'stop' && $cmd eq 'stop' && $check ne 'nocheck')
  1008. {
  1009. Log3($name,5,"Siro_set: double stop, action aborted");
  1010. readingsSingleUpdate($hash, "prog_mode", "inaktiv " , 1);
  1011. if($debugmode eq "1")
  1012. {
  1013. $debug = "Siro_set: double stop, action aborted";
  1014. readingsSingleUpdate($hash, "DEBUG_SET",$debug, 1);
  1015. }
  1016. return;
  1017. }
  1018. }
  1019. else
  1020. {
  1021. $testprog = $testprog*-1;
  1022. $virtual = "virtual";
  1023. readingsSingleUpdate($hash, "prog_mode", "$testprog" , 1);
  1024. }
  1025. #########################################
  1026. # invertierung position
  1027. if ( $invers eq "1")
  1028. {
  1029. $oldstate = 100 - $oldstate;
  1030. $autostop = 100 - $autostop;
  1031. }
  1032. #########################################
  1033. Log3($name,5,"Siro_Set: teste autostop: $autostop < 100 $oldstate < $autostop - $cmd");
  1034. # erkennung autostopfunktiuon
  1035. if ($cmd eq "on" && $autostop < 100 && $oldstate < $autostop )
  1036. {
  1037. $cmd="position";
  1038. $args[1]=$autostop;
  1039. $newposstate = $args[1]; # position autostop
  1040. $timetorun = $timetoclose/100*$newposstate;
  1041. Log3($name,1,"Siro_Set: autostop gefunden mapping auf position erfolgt: $newposstate ");
  1042. }
  1043. #########################################
  1044. # erkennung downlimit funktion
  1045. if ($downlimit < 100 && $operationmode eq "1")
  1046. {
  1047. if ($cmd eq 'position' && $downlimit < $newposstate)
  1048. {
  1049. $args[1]=$downlimit;
  1050. $newposstate = $args[1]; # Anzufahrende Position in Prozent
  1051. $timetorun = $timetoclose/100*$newposstate;
  1052. Log3($name,1,"Siro_Set: drive down limit reached: $newposstate ");
  1053. }
  1054. if ($cmd eq 'on')
  1055. {
  1056. $cmd="position";
  1057. $args[1]=$downlimit;
  1058. $newposstate = $args[1]; # Anzufahrende Position in Prozent
  1059. $timetorun = $timetoclose/100*$newposstate;
  1060. Log3($name,1,"Siro_Set: drive down limit reached: $newposstate ");
  1061. }
  1062. }
  1063. #########################################
  1064. # on/off Umschaltung ohne zwischenzeitliches Anhalten
  1065. if ($cmd eq 'on' && $timebetweenmsg < $timetoopen && $lastaction eq 'off') # Prüfe auf direkte Umschaltung on - off
  1066. {
  1067. $oldposition = $beforeaction_position;
  1068. $newposition = $timebetweenmsg/$offdirekttime;
  1069. $finalposition = $oldposition-$newposition;
  1070. if ($limitedmode eq "on")
  1071. {
  1072. $finalposition ="50";
  1073. }
  1074. $hash->{helper}{lastMsg} = $aktMsg;
  1075. $hash->{helper}{aktMsg} = "stop".' '.int($finalposition).' '.gettimeofday();
  1076. $hash->{helper}{positiontimer} = $timebetweenmsg;
  1077. $hash->{helper}{position} = int($finalposition);
  1078. if ($mode ne "physical")
  1079. {
  1080. Siro_SendCommand($hash, 'stop');
  1081. }
  1082. $aktMsg = $hash->{helper}{aktMsg} ;
  1083. @last_action_array=split(/ /,$aktMsg);
  1084. $lastaction = $last_action_array[0];
  1085. $lastaction_position = $last_action_array[1];
  1086. $lastaction_time = $last_action_array[2];
  1087. $befMsg = $hash->{helper}{lastMsg};
  1088. @before_action_array=split(/ /,$befMsg);
  1089. $beforeaction_position = $before_action_array[1];
  1090. $timebetweenmsg = $testtimestart-$last_action_array[2]; # Zeit zwischen dem aktuellen und letzten Befehl
  1091. $timebetweenmsg = (int($timebetweenmsg*10)/10);
  1092. }
  1093. #########################################
  1094. # off/on Umschaltung ohne zwischenzeitliches Anhalten
  1095. if ($cmd eq 'off' && $timebetweenmsg < $timetoclose && $lastaction eq 'on')
  1096. {
  1097. $oldposition = $beforeaction_position;
  1098. $newposition = $timebetweenmsg/$ondirekttime;
  1099. $finalposition = $oldposition+$newposition;
  1100. if ($limitedmode eq "on")
  1101. {
  1102. $finalposition ="50";
  1103. }
  1104. $hash->{helper}{lastMsg} = $aktMsg;
  1105. $hash->{helper}{aktMsg} = "stop".' '.int($finalposition).' '.gettimeofday();
  1106. $hash->{helper}{positiontimer} = $timebetweenmsg;
  1107. if ($mode ne "physical")
  1108. {
  1109. Siro_SendCommand($hash, 'stop');
  1110. }
  1111. $aktMsg = $hash->{helper}{aktMsg} ;
  1112. @last_action_array=split(/ /,$aktMsg);
  1113. $lastaction = $last_action_array[0];
  1114. $lastaction_position = $last_action_array[1];
  1115. $lastaction_time = $last_action_array[2];
  1116. $befMsg = $hash->{helper}{lastMsg};
  1117. @before_action_array=split(/ /,$befMsg);
  1118. $beforeaction_position = $before_action_array[1];
  1119. $timebetweenmsg = gettimeofday()-$last_action_array[2]; # Zeit zwischen dem aktuellen und letzten Befehl
  1120. $timebetweenmsg = (int($timebetweenmsg*10)/10);
  1121. }
  1122. #########################################
  1123. # Positionsberechnung bei einem Stopp-Befehl
  1124. if ($cmd eq 'stop')
  1125. {
  1126. # lösche interne timer - setze reading action auf no action
  1127. readingsSingleUpdate($hash, "action",'no action', 1);
  1128. RemoveInternalTimer($hash);
  1129. Log3($name,5,"Siro_Set: cmd stop timebetweenmsg -> $timebetweenmsg ondirekttime -> $ondirekttime offdirekttime -> $offdirekttime ");
  1130. $oldposition = $beforeaction_position;
  1131. if ($ondirekttime eq "0" || $offdirekttime eq "0") # Fehler division durch 0 abfanken bei ungesetzten attributen
  1132. {
  1133. Log3($name,5,"Siro_Set: cmd stop -> Positionserrechnung ohne gesetzte Attribute , Finalposition wird auf 50 gesetzt ");
  1134. $finalposition ="50";
  1135. $args[1] = $finalposition;
  1136. }
  1137. else
  1138. {
  1139. Log3($name,5,"Siro_Set: stop - Lastaction -> $lastaction $lastaction_position $oldposition");
  1140. if ($lastaction eq 'position')
  1141. {
  1142. if ( $lastaction_position > $oldposition)
  1143. {
  1144. $lastaction="on";
  1145. }
  1146. else
  1147. {
  1148. $lastaction="off";
  1149. }
  1150. }
  1151. if ($lastaction eq 'on')# Letzte Fahrt runter (on)
  1152. {
  1153. $newposition = $timebetweenmsg/$ondirekttime;
  1154. $finalposition = $oldposition+$newposition;
  1155. }
  1156. elsif ($lastaction eq 'off')# Letzte Fahrt hoch (off)
  1157. {
  1158. $newposition = $timebetweenmsg/$offdirekttime;
  1159. $finalposition = $oldposition-$newposition;
  1160. }
  1161. elsif ($lastaction eq 'fav')# Letzte Fahrt unbekannt
  1162. {
  1163. #Fahrtrichtung ermitteln - dafür Position von lastmsg nehmen $beforeaction_position
  1164. $favorit_position =$time_to_favorite/$ondirekttime;
  1165. Log3($name,5,"Siro_Set: drive to position aborted (target position:$favorit_position %) : (begin possition $beforeaction_position %) ");
  1166. if ($favorit_position < $beforeaction_position)# Fahrt hoch
  1167. {
  1168. $newposition = $timebetweenmsg/$offdirekttime;
  1169. $finalposition = $oldposition-$newposition;
  1170. }
  1171. if ($favorit_position > $beforeaction_position)# Fahrt runter
  1172. {
  1173. $newposition = $timebetweenmsg/$ondirekttime;
  1174. $finalposition = $oldposition+$newposition;
  1175. }
  1176. Log3($name,5,"Siro_Set position: $finalposition ");
  1177. }
  1178. if ($finalposition < 0){$finalposition = 0;}
  1179. if ($finalposition > 100){$finalposition = 100;}
  1180. if ($limitedmode eq "on"){$finalposition ="50";}
  1181. $finalposition = int($finalposition); # abrunden
  1182. $args[1] = $finalposition;
  1183. }
  1184. }
  1185. #########################################
  1186. # Hardware-Favorit anfahren
  1187. if ($cmd eq 'fav')
  1188. {
  1189. Log3($name,5,"Siro_Set fav: $cmd ");
  1190. if (!defined $time_to_favorite)
  1191. {
  1192. $time_to_favorite=5;
  1193. } # Tmp ggf. ändern
  1194. # if ( $time_to_favorite eq "undef")
  1195. # {
  1196. # $time_to_favorite=5;
  1197. # #return;
  1198. # }
  1199. if ($ondirekttime eq "0" || $offdirekttime eq "0") # Fehler division durch 0 abfanken bei ungesetzten attributen
  1200. {
  1201. Log3($name,1,"Siro_Set: set cmd fav -> Favoritberechnung ohne gesetzte Attribute , aktion nicht möglich");
  1202. return;
  1203. }
  1204. $favorit_position =$time_to_favorite/$ondirekttime; # Errechnet nur die Position, die von oben angefahren wurde. pos
  1205. $args[0] = $cmd;
  1206. $args[1] = int($favorit_position);
  1207. if($time_to_favorite eq 'undef')
  1208. {
  1209. Log3($name,1,"Siro_Set: function position limited without attr time_down_to_favorite");
  1210. $time_to_favorite ="1";
  1211. $args[1] ="50";
  1212. # new
  1213. if ($mode ne "physical")
  1214. {
  1215. $args[2] = 'longstop';
  1216. $args[0] = 'stop';
  1217. Siro_SendCommand($hash, @args);
  1218. readingsSingleUpdate($hash, "position",'50', 1);
  1219. readingsSingleUpdate($hash, "state",'50', 1);
  1220. }
  1221. return;
  1222. }
  1223. $args[2] = 'longstop';
  1224. $hash->{helper}{lastMsg} = $aktMsg;
  1225. $hash->{helper}{aktMsg} = $args[0].' '.$args[1].' '.gettimeofday();
  1226. $hash->{helper}{positiontimer} = $timebetweenmsg;
  1227. $cmd ='stop';
  1228. $args[0] = $cmd;
  1229. if ($mode ne "physical")
  1230. {
  1231. Siro_SendCommand($hash, @args);
  1232. }
  1233. my $position = $hash->{helper}{position}; # Position für die Zeitberechnung speichern
  1234. $hash->{helper}{position}=int($favorit_position);
  1235. Siro_UpdateState( $hash, int($favorit_position), '', '', 1 );
  1236. #Fahrtrichtung ermitteln - dafür Position von lastmsg nehmen $beforeaction_position
  1237. $runningtime = 0;
  1238. if ($favorit_position < $position)# Fahrt hoch
  1239. {
  1240. readingsSingleUpdate($hash, "action",'up to favorite', 1); #tmp
  1241. my $change = $position - $favorit_position; # änderung in %
  1242. $runningtime = $change*$offdirekttime;
  1243. }
  1244. if ($favorit_position > $position)# Fahrt runter
  1245. {
  1246. readingsSingleUpdate($hash, "action",'down to favorite', 1); #tmp
  1247. my $change = $favorit_position - $position ; # Änderung in %
  1248. $runningtime = $change*$ondirekttime;
  1249. }
  1250. InternalTimer($testtimestart+$runningtime,"Siro_Position_fav",$hash,0); # state auf Stopp setzen nach Erreichen der Fahrtdauer
  1251. return;
  1252. }
  1253. #########################################
  1254. # Teste auf Position '0' oder '100' -> Mappen auf 'on' oder 'off'
  1255. if ($cmd eq 'on'){$args[1] = "100";}
  1256. if ($cmd eq 'off'){$args[1] = "0";}
  1257. #########################################
  1258. #Aktualisierung des Timers (Zeit zwischen den Befehlen, lastmsg und aktmsg)
  1259. $hash->{helper}{lastMsg} = $hash->{helper}{aktMsg};
  1260. $hash->{helper}{aktMsg} = $args[0].' '.$args[1].' '.gettimeofday();
  1261. $hash->{helper}{positiontimer} = $timebetweenmsg;
  1262. #########################################
  1263. if ( defined($newposstate) )
  1264. {
  1265. if($newposstate eq "0")
  1266. {
  1267. $cmd="off";
  1268. Log3($name,5,"recognized position 0 ");
  1269. }
  1270. elsif ($newposstate eq "100")
  1271. {
  1272. $cmd="on";
  1273. Log3($name,5,"recognized position 100 ");
  1274. }
  1275. }
  1276. # Direkte Positionsanfahrt
  1277. if ($cmd eq 'position')
  1278. {
  1279. Log3($name,5,"Siro_Set: nodrive -> $nodrive");
  1280. if (($ondirekttime eq "0" || $offdirekttime eq "0" || $nodrive eq "true") && $testchannel ne "0" ) # Fehler division durch 0 abfanken bei ungesetzten attributen
  1281. {
  1282. Log3($name,1,"Siro_Set: Positionsanfahrt ohne gesetzte Attribute , aktion nicht möglich -> abbruch");
  1283. return "Positionsanfahrt ohne gesetzte Attribute time_to_open und time_to_close nicht moeglich";
  1284. }
  1285. my $aktposition=$hash->{helper}{position};
  1286. # Fahrt nach oben
  1287. if ($newposstate < $aktposition)
  1288. {
  1289. if ($action eq "no action")
  1290. {
  1291. $action = 'up to position '.$newposstate;
  1292. readingsSingleUpdate($hash, "action",$action, 1); #tmp
  1293. }
  1294. $cmd='off';
  1295. my $percenttorun = $aktposition-$newposstate;
  1296. $runningtime = $percenttorun*$offdirekttime;
  1297. $timetorun=$runningtime;
  1298. Log3($name,5,"Siro_Set: direkt positiondrive: -> timing:($runningtime = $percenttorun*$offdirekttime) -> open runningtime:$runningtime - modification in % :$percenttorun");
  1299. }
  1300. #Fahrt nach unten
  1301. if ($newposstate > $aktposition)
  1302. {
  1303. if ($action eq "no action")
  1304. {
  1305. $action = 'down to position '.$newposstate;
  1306. readingsSingleUpdate($hash, "action",$action, 1); #tmp
  1307. }
  1308. $cmd='on';
  1309. my $percenttorun = $newposstate-$aktposition;
  1310. $runningtime = $percenttorun*$ondirekttime;
  1311. $timetorun=$runningtime;
  1312. Log3($name,5,"Siro_Set: direkt positiondrive: -> timing: ($runningtime = $percenttorun*$ondirekttime) -> close runningtime:$runningtime - modification in % :$percenttorun");
  1313. }
  1314. $virtual = "virtual"; # keine Stateänderung
  1315. Log3($name,5,"Siro_Set: direkt positiondrive: -> setting timer to $runningtime");
  1316. InternalTimer($testtimestart+$runningtime,"Siro_Position_down_stop",$hash,0);
  1317. }
  1318. #########################################
  1319. # abarbeitung weiterer befehle
  1320. if($cmd eq 'on')
  1321. {
  1322. if ($action eq "no action")
  1323. {
  1324. $action = 'down ';
  1325. readingsSingleUpdate($hash, "action",$action, 1); #tmp
  1326. # voraussichtliche fahrzeit berechnen bis 100%
  1327. my $aktposition=$hash->{helper}{position};
  1328. my $percenttorun = 100 - $aktposition;
  1329. $runningtime = $percenttorun*$ondirekttime;
  1330. $timetorun=$runningtime;
  1331. Log3($name,4,"Siro_Set: aktposition -> $aktposition - percenttorun -> $percenttorun - ondirekttime -> $ondirekttime");
  1332. Log3($name,4,"Siro_Set: voraussichtliche fahrdauer bis 100%: -> $runningtime");
  1333. InternalTimer(gettimeofday()+$timetorun+1, "Siro_Stopaction", $hash, 0); # action auf Stopp
  1334. }
  1335. $newState = '100';
  1336. $positiondrive = 100;
  1337. }
  1338. elsif($cmd eq 'off')
  1339. {
  1340. if ($action eq "no action")
  1341. {
  1342. $action = 'up ';
  1343. readingsSingleUpdate($hash, "action",$action, 1); #tmp
  1344. # voraussichtliche fahrzeit berechnen bis 0%
  1345. my $aktposition=$hash->{helper}{position};
  1346. my $percenttorun = $aktposition;
  1347. $runningtime = $percenttorun*$offdirekttime;
  1348. $timetorun=$runningtime;
  1349. Log3($name,4,"Siro_Set: aktposition -> $aktposition - percenttorun -> $percenttorun - offdirekttime -> $offdirekttime");
  1350. Log3($name,4,"Siro_Set: voraussichtliche fahrdauer bis 0%: -> $runningtime");
  1351. InternalTimer(gettimeofday()+$timetorun+1, "Siro_Stopaction", $hash, 0); # action auf Stopp
  1352. }
  1353. $newState = '0';
  1354. $positiondrive = 0;
  1355. }
  1356. elsif($cmd eq 'stop')
  1357. {
  1358. $newState = $finalposition;
  1359. $positiondrive = $finalposition;
  1360. }
  1361. elsif($cmd eq 'fav')
  1362. {
  1363. $newState = $favorit_position;
  1364. $positiondrive = $favorit_position;
  1365. }
  1366. else
  1367. {
  1368. $newState = $state; #todo: Was mache ich mit der Positiondrive?
  1369. }
  1370. #########################################
  1371. if (!defined($virtual)){$virtual = "";}
  1372. if (!defined($newposstate)){$newposstate = 0;}
  1373. if (!defined($newposstate)){$newposstate = 0;}
  1374. if ($virtual ne "virtual") # Kein Stateupdate beim Anfahren einer Position
  1375. {
  1376. if ($newposstate < 0){$newposstate = 0;}
  1377. if ($newposstate > 100){$newposstate = 100;}
  1378. $hash->{helper}{position}=$positiondrive;
  1379. Log3($name,5,"Siro_Set: stateupdate erfolgt -> $positiondrive");
  1380. #########################################
  1381. # invertiere position
  1382. if ( $invers eq "1")
  1383. {
  1384. my $noinvers = $newState;
  1385. my $inversposition = 100 - $newState;
  1386. $newState = $inversposition;
  1387. Log3($name,3,"Siro_Set: invertiere Position vor setstate - berechnet -> $noinvers - inverted -> $newState ");
  1388. }
  1389. #########################################
  1390. Siro_UpdateState( $hash, $newState, '', $updateState, 1 );
  1391. }
  1392. else
  1393. {
  1394. Log3($name,5,"Siro_Set: kein stateupdate erfolgt");
  1395. #Setze readings positiondrive und positiontime
  1396. if ($newposstate < 0){$newposstate = 0;}
  1397. if ($newposstate > 100){$newposstate = 100;}
  1398. $hash->{helper}{position}=$newposstate;
  1399. }
  1400. $args[0] = $cmd;
  1401. if (!defined($mode)){$mode ="virtual"};
  1402. if($debugmode eq "1")
  1403. {
  1404. readingsSingleUpdate($hash, "DEBUG_SET",$debug, 1);
  1405. }
  1406. if ($mode ne "physical")
  1407. {
  1408. Log3($name,3,"Siro_set: handing over to Siro_Send_Command with following arguments: @args");
  1409. Siro_SendCommand($hash, @args);
  1410. }
  1411. $hash->{helper}{MODE} = "virtual";
  1412. $hash->{helper}{LastMODE} = $mode;
  1413. my $testtimeend = gettimeofday();
  1414. $runningtime =$testtimeend - $testtimestart;
  1415. Log3($name,5,"Siro_set: runningtime -> $runningtime");
  1416. return ;
  1417. }
  1418. ###########################################################################
  1419. sub Siro_UpdateState($$$$$)
  1420. {
  1421. my ($hash, $newState, $move, $updateState, $doTrigger) = @_;
  1422. readingsBeginUpdate($hash);
  1423. if ($newState < 0){$newState = 0;}
  1424. if ($newState > 100){$newState = 100;}
  1425. readingsBulkUpdate($hash,"state",$newState);
  1426. readingsBulkUpdate($hash,"position",$newState);
  1427. $hash->{state} = $newState;
  1428. #$hash->{helper}{position} = $newState;
  1429. readingsEndUpdate($hash, $doTrigger);
  1430. }
  1431. #################################################################
  1432. sub Siro_Position_down_start($)
  1433. {
  1434. my ($hash) = @_;
  1435. my $name = $hash->{NAME};
  1436. #my $timetoopen = AttrVal($name,'time_to_open', 'undef'); #tmp
  1437. #my $timetoclose = AttrVal($name,'time_to_close', 'undef');#tmp
  1438. my @args;
  1439. $args[0] = 'on';
  1440. my $virtual='virtual';
  1441. Siro_SendCommand($hash, @args,, $virtual);
  1442. Log3 $name, 5, "Siro_Position_down_start: completed";
  1443. return;
  1444. }
  1445. #################################################################
  1446. sub Siro_Position_down_stop($)
  1447. {
  1448. my ($hash) = @_;
  1449. my $name = $hash->{NAME};
  1450. my @args;
  1451. $args[0] = 'stop';
  1452. if (!defined($args[1])){$args[1]="";}
  1453. my $virtual='virtual';
  1454. Siro_SendCommand($hash, @args, $virtual);
  1455. my $positiondrive=$hash->{helper}{position};
  1456. my $aktMsg = $hash->{helper}{aktMsg};
  1457. $hash->{helper}{lastMsg} = $aktMsg;
  1458. #$hash->{helper}{aktMsg} = $args[0].' '.$args[1].' '.gettimeofday();
  1459. $hash->{helper}{aktMsg} = $args[0].' '.$positiondrive.' '.gettimeofday();
  1460. # invertiere position
  1461. my $invers = AttrVal($name,'invers_position', '0');
  1462. if ( $invers eq "1")
  1463. {
  1464. my $noinvers = $positiondrive;
  1465. my $inversposition = 100 - $positiondrive;
  1466. $positiondrive = $inversposition;
  1467. Log3($name,3,"Siro_Set: invertiere Position vor setstate - berechnet -> $noinvers - inverted -> $positiondrive ");
  1468. }
  1469. readingsSingleUpdate($hash, "action",'no action', 1); #tmp
  1470. Siro_UpdateState( $hash, $positiondrive, '', '', 1 );
  1471. Log3 $name, 5, "Siro_Position_down_stop: completed -> state:$positiondrive ";
  1472. return;
  1473. }
  1474. #################################################################
  1475. sub Siro_Position_fav($)
  1476. {
  1477. my ($hash) = @_;
  1478. my $name = $hash->{NAME};
  1479. my @args;
  1480. my $aktMsg = $hash->{helper}{aktMsg};
  1481. $hash->{helper}{lastMsg} = $aktMsg;
  1482. my @last_action_array=split(/ /,$aktMsg);
  1483. $hash->{helper}{aktMsg} = 'stop'.' '.$last_action_array[1].' '.gettimeofday();
  1484. readingsSingleUpdate($hash, "action",'no action', 1); #tmp
  1485. Log3 $name, 5, "Siro_Position_fav: completed";
  1486. return;
  1487. }
  1488. #################################################################
  1489. sub Siro_Sequence($)
  1490. {
  1491. my $debug;
  1492. my ($hash) = @_;
  1493. my $name = $hash->{NAME};
  1494. Log3($name,1,"Siro_Sequence:START");
  1495. my @args;
  1496. my @sequence = split(/,/,$hash->{sequence});
  1497. my $debugmode = AttrVal($name,'debug_mode', '0');
  1498. my $cmd = shift @sequence;
  1499. my $timer = shift @sequence;
  1500. $debug=$debug.' '.$cmd.' '.$timer.' '.@sequence;
  1501. $hash->{sequence} = join(",",@sequence); # 3 min Programmiermodus
  1502. $args[0]=$cmd;
  1503. Siro_SendCommand($hash, @args, 'virtual');
  1504. if ( defined($timer) )
  1505. {
  1506. InternalTimer(gettimeofday()+$timer, "Siro_Sequence", $hash, 0);
  1507. $debug=$debug.'- Erneute Aufrufsequenz';
  1508. }
  1509. else
  1510. {
  1511. $debug=$debug.'- Sequenz beendet, ATTR time_to _fav neu berechnet und gesetzt, progmode beendet';
  1512. readingsSingleUpdate($hash, "prog_mode", "inaktiv " , 1);
  1513. delete($hash->{sequence});
  1514. my $timetoclose = AttrVal($name,'time_to_close', '10');
  1515. my $ondirekttime = $timetoclose/100; # Zeit für 1 Prozent Runterfahrt
  1516. my $position = $hash->{helper}{position};
  1517. my $newfav = $ondirekttime * $position;
  1518. $attr{$name}{time_down_to_favorite} = $newfav;
  1519. }
  1520. if($debugmode eq "1")
  1521. {
  1522. readingsSingleUpdate($hash, "DEBUG_SEQUENCE",$debug, 1);
  1523. }
  1524. Log3 $name, 5, "Siro_Sequence: completed";
  1525. return;
  1526. }
  1527. ###############################################################
  1528. sub Siro_Setgroup($)
  1529. {
  1530. my ($hash) = @_;
  1531. my $name = $hash->{NAME};
  1532. my $grouphashraw=$hash->{helper}{affected_devices_h};
  1533. my @grouphash=split(/,/,$grouphashraw);
  1534. my $groupnamesraw=$hash->{helper}{affected_devices_n};
  1535. my @groupnames=split(/,/,$groupnamesraw);
  1536. my $groupcommandraw=$hash->{helper}{groupcommand};
  1537. my @groupcommand=split(/,/,$groupcommandraw);
  1538. Log3($name,5,"Siro_Setgroup : @groupnames -> $groupcommandraw ");
  1539. my $count =0;
  1540. foreach my $senddevice(@groupnames)
  1541. {
  1542. my @args;
  1543. #Log3($name,5,"----------------------------");
  1544. Log3($name,5,"Siro_Setgroup: count -> $count ");
  1545. Log3($name,5,"Siro_Setgroup: senddevice -> $senddevice ");
  1546. Log3($name,5,"Siro_Setgroup: testhash -> $grouphash[$count] ");
  1547. Log3($name,5,"Siro_Setgroup: command -> $groupcommand[1] $groupcommand[2] ");
  1548. #Log3($name,5,"----------------------------");
  1549. $args[0]=$groupcommand[1];
  1550. $args[1]=$groupcommand[2];
  1551. Log3($name,5,"Siro_Setgroup: aufruf -> $grouphash[$count],$senddevice, @args ");
  1552. Log3($name,5,"Siro_Setgroup: set $senddevice $groupcommand[1] $groupcommand[2]");
  1553. #my $cs = "set Siro_5B417081 on";
  1554. my $cs ="set $senddevice $groupcommand[0] $groupcommand[2]";
  1555. my $client_hash = $grouphash[$count];
  1556. Log3($name,5,"Siro_Setgroup: command -> ".$cs);
  1557. my $errors = AnalyzeCommandChain(undef, $cs);;
  1558. $count++;
  1559. }
  1560. return;
  1561. }
  1562. ###############################################################
  1563. sub Siro_Stop($)
  1564. {
  1565. my ($hash) = @_;
  1566. my $name = $hash->{NAME};
  1567. my @args;
  1568. $args[0] = "stop";
  1569. #my ( $hash, $name, @args ) = @_;
  1570. readingsSingleUpdate($hash, "action",'no action', 1); #tmp
  1571. Log3($name,0,"Siro_Stop: x-for-timer stop -> @args ");
  1572. Siro_Set($hash, $name, @args);
  1573. return;
  1574. }
  1575. ###############################################################
  1576. sub Siro_Restartcmd($)
  1577. {
  1578. my $incomming = $_[0];
  1579. my @msgarray=split(/ /,$incomming);
  1580. my $name = $msgarray[1];
  1581. #my $hash = $msgarray[1];
  1582. #my $name = $hash->{NAME};
  1583. my $cs ="set $incomming";
  1584. Log3($name,3,"Siro_Restartcmd: incomming -> $incomming ");
  1585. Log3($name,3,"Siro_Restartcmd: command -> ".$cs);
  1586. my $errors = AnalyzeCommandChain(undef, $cs);
  1587. return;
  1588. }
  1589. ###############################################################
  1590. sub Siro_Stopaction($)
  1591. {
  1592. my ($hash) = @_;
  1593. my $name = $hash->{NAME};
  1594. Log3($name,5,"Siro_Stopaction: setze no action ");
  1595. readingsSingleUpdate($hash, "action",'no action', 1); #tmp
  1596. return;
  1597. }
  1598. ###############################################################readingsSingleUpdate($hash, "action",$action, 1); #tmp
  1599. sub Siro_Testgroup($$)
  1600. {
  1601. my ( $hash, $id ) = @_;
  1602. my $name = $hash->{NAME};
  1603. my $testid;
  1604. my $testidchan;
  1605. my @groupnames;
  1606. my @grouphash;
  1607. foreach my $testdevices(keys %{$modules{Siro}{defptr}})#
  1608. {
  1609. $testid = substr($testdevices, 0, 7);
  1610. $testidchan = substr($testdevices, 7, 1);
  1611. Log3($name,5,"Siro_Testgroup: groupdevice search device $testid -> test device -> $testdevices-$testidchan ");
  1612. if ($id eq $testid )
  1613. {
  1614. my $lh = $modules{Siro}{defptr}{$testdevices}; #def
  1615. my $namex = $lh->{NAME};
  1616. my $channelx = $lh->{CHANNEL};
  1617. Log3($name,5,"Siro_Testgroup: device for group found -> $namex lh -$lh");
  1618. if ($channelx ne "0")
  1619. {
  1620. Log3($name,5,"Siro_Testgroup: device for group found -> $namex hash -> $lh");
  1621. push(@groupnames,$namex);
  1622. push(@grouphash,$lh); # betreffendes hash zur gruppe zufügen
  1623. }
  1624. }
  1625. }
  1626. my $hashstring;
  1627. foreach my $target (@grouphash)
  1628. {
  1629. $hashstring=$hashstring.$target.",";
  1630. }
  1631. chop($hashstring);
  1632. $hash->{helper}{affected_devices_h} = "$hashstring";
  1633. my $devicestring;
  1634. foreach my $target (@groupnames)
  1635. {
  1636. $devicestring=$devicestring.$target.",";
  1637. }
  1638. chop($devicestring);
  1639. $hash->{helper}{affected_devices_n} = $devicestring;
  1640. return @groupnames;
  1641. }
  1642. #############################################
  1643. sub Siro_icon($)
  1644. {
  1645. #return 'fts_shutter_1w_'.(int($state/10)*10);
  1646. my ($id) = @_;
  1647. my $lh = $modules{Siro}{defptr}{$id};
  1648. my $position =$lh->{helper}{position};
  1649. my $xsvg ="<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
  1650. <!-- Created with Inkscape (http://www.inkscape.org/) -->
  1651. <svg
  1652. xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
  1653. xmlns:cc=\"http://creativecommons.org/ns#\"
  1654. xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"
  1655. xmlns:svg=\"http://www.w3.org/2000/svg\"
  1656. xmlns=\"http://www.w3.org/2000/svg\"
  1657. version=\"1.0\"
  1658. width=\"585\"
  1659. height=\"585\"
  1660. viewBox=\"0 0 585 585\"
  1661. id=\"svg2\">
  1662. <defs
  1663. id=\"defs12\" />
  1664. <metadata
  1665. id=\"metadata4\">
  1666. Created by potrace 1.8, written by Peter Selinger 2001-2007
  1667. <rdf:RDF>
  1668. <cc:Work
  1669. rdf:about=\"\">
  1670. <dc:format>image/svg+xml</dc:format>
  1671. <dc:type
  1672. rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />
  1673. <dc:title></dc:title>
  1674. </cc:Work>
  1675. </rdf:RDF>
  1676. </metadata>
  1677. <path
  1678. d=\"m 14.173228,80.136391 442.204712,0 0,29.186439 -442.204712,0 z\"
  1679. id=\"rect3764\"
  1680. style=\"fill:#000000;fill-opacity:1;stroke-width:3.1960001;stroke-linecap:round;stroke-miterlimit:4\" />
  1681. </svg>
  1682. ";
  1683. return $xsvg;
  1684. }
  1685. 1;
  1686. =pod
  1687. =item summary Supports rf shutters from Siro
  1688. =item summary_DE Unterst&uumltzt Siro Rollo-Funkmotoren
  1689. =begin html
  1690. <a name="Siro"></a>
  1691. <h3>Siro protocol</h3>
  1692. <ul>
  1693. <br> A <a href="#SIGNALduino">SIGNALduino</a> device (must be defined first).<br>
  1694. <br>
  1695. Since the protocols of Siro and Dooya are very similar, it is currently difficult to operate these systems simultaneously via one "IODev". Sending commands works without any problems, but distinguishing between the remote control signals is hardly possible in SIGNALduino. For the operation of the Siro-Module it is therefore recommended to exclude the Dooya protocol (16) in the SIGNALduino, via the whitelist. In order to detect the remote control signals correctly, it is also necessary to deactivate the "manchesterMC" protocol (disableMessagetype manchesterMC) in the SIGNALduino. If machester-coded commands are required, it is recommended to use a second SIGNALduino.<br>
  1696. <br>
  1697. <br>
  1698. <a name="Sirodefine"></a>
  1699. <br>
  1700. <b>Define</b>
  1701. <br>
  1702. <ul>
  1703. <code>define&lt; name&gt; Siro &lt;id&gt;&lt;channel&gt; </code>
  1704. <br>
  1705. <br>
  1706. The ID is a 7-digit hex code, which is uniquely and firmly assigned to a Siro remote control. Channel is the single-digit channel assignment of the remote control and is also hexadecimal. This results in the possible channels 0 - 15 (hexadecimal 0-F).
  1707. A unique ID must be specified, the channel (channel) must also be specified.
  1708. An autocreate (if enabled) automatically creates the device with the ID of the remote control and the channel.
  1709. <br><br>
  1710. Examples:<br><br>
  1711. <ul>
  1712. <code>define Siro1 Siro AB00FC1</code><br> Creates a Siro-device called Siro1 with the ID: AB00FC and Channel: 1<br>
  1713. </ul>
  1714. </ul>
  1715. <br>
  1716. <a name="Siroset"></a>
  1717. <b>Set </b><br>
  1718. <ul>
  1719. <code>set &lt;name&gt; &lt;value&gt; [&lt;position&gt]</code>
  1720. <br><br>
  1721. where <code>value</code> is one of:<br>
  1722. <pre>
  1723. on
  1724. off
  1725. stop
  1726. pos (0...100)
  1727. prog
  1728. fav
  1729. </pre>
  1730. Examples:<br><br>
  1731. <ul>
  1732. <code>set Siro1 on</code><br>
  1733. <code>set Siro1 off</code><br>
  1734. <code>set Siro1 position 50</code><br>
  1735. <code>set Siro1 fav</code><br>
  1736. <code>set Siro1 stop</code><br>
  1737. <code>set Siro1 set_favorite</code><br>
  1738. </ul>
  1739. <br>
  1740. <ul>
  1741. set Siro1 on moves the roller blind up completely (0%)<br>
  1742. set Siro1 off moves the roller blind down completely (100%)<br>
  1743. set Siro1 stop stops the current movement of the roller blind<br>
  1744. set Siro1 position 45 moves the roller blind to the specified position (45%)<br>
  1745. set Siro1 45 moves the roller blind to the specified position (45%)<br>
  1746. set Siro1 fav moves the blind to the hardware-programmed favourite middle position<br>
  1747. set Siro1 prog corresponds to the "P2" button on the remote control, the module is set to programming mode (3 min).<br>
  1748. set Siro1 set_favorite programs the current roll position as hardware middle position. The attribute time_down_to_favorite is recalculated and set. <br>
  1749. </ul>
  1750. <br>
  1751. Notes:<br><br>
  1752. <ul>
  1753. <li>If the module is in programming mode, the module detects successive stop commands because they are absolutely necessary for programming. In this mode, the readings and state are not updated. The mode is automatically terminated after 3 minutes. The remaining time in programming mode is displayed in the reading "pro_mode". The remaining time in programming mode is displayed in the reading "pro_mode". The programming of the roller blind must be completed during this time, otherwise the module will no longer accept successive stop commands. The display of the position, the state, is a calculated position only, since there is no return channel to status message. Due to a possible missing remote control command, timing problem etc. it may happen that this display shows wrong values sometimes. When moving into an end position without stopping the movement (set Siro1[on/off]), the status display and real position are synchronized each time the position is reached. This is due to the hardware and unfortunately not technically possible.
  1754. </li>
  1755. </ul>
  1756. </ul>
  1757. <br>
  1758. <b>Get</b>
  1759. <ul>N/A</ul><br>
  1760. <a name="Siroattr"></a>
  1761. <b>Attributes</b><br><br>
  1762. <ul>
  1763. <a name="IODev"></a>
  1764. <li>IODev<br>
  1765. The IODev must contain the physical device for sending and receiving the signals. Currently a SIGNALduino or SIGNALesp is supported.
  1766. Without the specification of the "Transmit and receive module" "IODev", a function is not possible.
  1767. </li><br>
  1768. <a name="channel"></a>
  1769. <li>channel (since V1.09 no longer available)<br>
  1770. contains the channel used by the module for sending and receiving.
  1771. This is already set when the device is created.
  1772. </li><br>
  1773. <a name="channel_send_mode_1 "></a>
  1774. <li>channel_send_mode_1 <br>
  1775. contains the channel that is used by the module in "operation_mode 1" to send.
  1776. This attribute is not used in "operation_mode 0"
  1777. </li><br>
  1778. <a name="operation_mode"></a>
  1779. <li>operation_mode<br>
  1780. Mode 0<br><br>
  1781. 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.
  1782. <br><br>Mode 1<br><br>
  1783. 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.<br>
  1784. Instructions for configuring the motor will follow.
  1785. </li><br>
  1786. <a name="time_down_to_favorite"></a>
  1787. <li>time_down_to_favorite<br>
  1788. 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.
  1789. Without this attribute, the module is not fully functional.</li><br>
  1790. <a name="time_to_close"></a>
  1791. <li>time_to_close<br>
  1792. contains the movement time in seconds required by the blind from 0% position to 100% position. This time must be measured and entered manually.
  1793. Without this attribute, the module is not fully functional.</li><br>
  1794. <a name="time_to_open"></a>
  1795. <li>time_to_open<br>
  1796. contains the movement time in seconds required by the blind from 100% position to 0% position. This time must be measured and entered manually.
  1797. Without this attribute, the module is not fully functional.</li><br>
  1798. <a name="prog_fav_sequence"></a>
  1799. <li>prog_fav_sequence<br>
  1800. contains the command sequence for programming the hardware favorite position</li><br>
  1801. <a name="debug_mode [0:1]"></a>
  1802. <li>debug_mode [0:1]<br>
  1803. 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.</li><br>
  1804. <a name="Info"></a>
  1805. <li>Info<br>
  1806. The attributes webcmd and devStateIcon are set once when the device is created and are adapted to the respective mode of the device during operation. The adaptation of these contents only takes place until they have been changed by the user. After that, there is no longer any automatic adjustment.</li><br>
  1807. </ul>
  1808. </ul>
  1809. =end html
  1810. =begin html_DE
  1811. <a name="Siro"></a>
  1812. <h3>Siro protocol</h3>
  1813. <ul>
  1814. <br> Ein <a href="#SIGNALduino">SIGNALduino</a>-Geraet (dieses sollte als erstes angelegt sein).<br>
  1815. <br>
  1816. Da sich die Protokolle von Siro und Dooya sehr &auml;hneln, ist ein gleichzeitiger Betrieb dieser Systeme ueber ein "IODev" derzeit schwierig. Das Senden von Befehlen funktioniert ohne Probleme, aber das Unterscheiden der Fernbedienungssignale ist in Signalduino kaum m&ouml;glich. Zum Betrieb der Siromoduls wird daher empfohlen, das Dooyaprotokoll im SIGNALduino (16) &uuml;ber die Whitelist auszuschliessen. Zur fehlerfreien Erkennung der Fernbedienungssignale ist es weiterhin erforderlich im SIGMALduino das Protokoll "manchesterMC" zu deaktivieren (disableMessagetype manchesterMC). Wird der Empfang von machestercodierten Befehlen benoetigt, wird der Betrieb eines zweiten Signalduinos empfohlen.<br>
  1817. <br>
  1818. <br>
  1819. <a name="Sirodefine"></a>
  1820. <br>
  1821. <b>Define</b>
  1822. <br>
  1823. <ul>
  1824. <code>define &lt;name&gt; Siro &lt;id&gt; &lt;channel&gt;</code>
  1825. <br>
  1826. <br>
  1827. Bei der <code>&lt;ID&gt;</code> handelt es sich um einen 7-stelligen Hexcode, der einer Siro Fernbedienung eindeutig und fest zugewiesen ist. <code>&lt;Channel&gt;</code> ist die einstellige Kanalzuweisung der Fernbedienung und ist ebenfalls hexadezimal. Somit ergeben sich die m&ouml;glichen Kan&auml;le 0 - 15 (hexadezimal 0-F).
  1828. Eine eindeutige ID muss angegeben werden, der Kanal (Channel) muss ebenfalls angegeben werden. <br>
  1829. Ein Autocreate (falls aktiviert), legt das Device mit der ID der Fernbedienung und dem Kanal automatisch an.
  1830. <br><br>
  1831. Beispiele:<br><br>
  1832. <ul>
  1833. <code>define Siro1 Siro AB00FC1</code><br> erstellt ein Siro-Geraet Siro1 mit der ID: AB00FC und dem Kanal: 1<br>
  1834. </ul>
  1835. </ul>
  1836. <br>
  1837. <a name="Siroset"></a>
  1838. <b>Set </b><br>
  1839. <ul>
  1840. <code>set &lt;name&gt; &lt;value&gt; [&lt;position&gt]</code>
  1841. <br><br>
  1842. where <code>value</code> is one of:<br>
  1843. <pre>
  1844. on
  1845. off
  1846. stop
  1847. pos (0..100)
  1848. prog
  1849. fav
  1850. </pre>
  1851. Beispiele:<br><br>
  1852. <ul>
  1853. <code>set Siro1 on</code><br>
  1854. <code>set Siro1 off</code><br>
  1855. <code>set Siro1 position 50</code><br>
  1856. <code>set Siro1 fav</code><br>
  1857. <code>set Siro1 stop</code><br>
  1858. <code>set Siro1 set_favorite</code><br>
  1859. <code>set Siro1 down_for_timer 5</code><br>
  1860. <code>set Siro1 up_for_timer 5</code><br>
  1861. <code>set Siro1 set_favorite</code><br>
  1862. </ul>
  1863. <br>
  1864. <ul>
  1865. set Siro1 on f&auml;hrt das Rollo komplett hoch (0%)<br>
  1866. set Siro1 off f&auml;hrt das Rollo komplett herunter (100%)<br>
  1867. set Siro1 stop stoppt die aktuelle Fahrt des Rollos<br>
  1868. set Siro1 position 45 f&auml;hrt das Rollo zur angegebenen Position (45%)<br>
  1869. set Siro1 45 f&auml;hrt das Rollo zur angegebenen Position (45%)<br>
  1870. set Siro1 fav f&auml;hrt das Rollo in die hardwarem&auml;ssig programmierte Mittelposition<br>
  1871. et Siro1 down_for_timer 5 f&auml;hrt das Rollo 5 Sekunden nach unten<br>
  1872. et Siro1 uown_for_timer 5 f&auml;hrt das Rollo 5 Sekunden nach oben<br>
  1873. set Siro1 prog entspricht der "P2" Taste der Fernbedienung. Das Modul wird in den Programmiermodus versetzt (3 Min.)<br>
  1874. set Siro1 set_favorite programmiert den aktuellen Rollostand als Hardwaremittelposition, das ATTR time_down_to_favorite wird neu berechnet und gesetzt. <br>
  1875. </ul>
  1876. <br>
  1877. Hinweise:<br><br>
  1878. <ul>
  1879. <li>Befindet sich das Modul im Programmiermodus, werden aufeinanderfolgende Stoppbefehle vom Modul erkannt, da diese zur Programmierung zwingend erforderlich sind. In diesem Modus werden die Readings und das State nicht aktualisiert. Der Modus wird nach 3 Minuten automatisch beendet. Die verbleibende Zeit im Programmiermodus wird im Reading "pro_mode" dargestellt. Die Programmierung des Rollos muss in dieser Zeit abgeschlossen sein, da das Modul andernfalls keine aufeinanderfolgenden Stoppbefehle mehr akzeptiert.
  1880. Die Anzeige der Position, des States, ist eine ausschliesslich rechnerisch ermittelte Position, da es keinen R&uumlckkanal zu Statusmeldung gibt. Aufgrund eines ggf. verpassten Fernbedienungsbefehls, Timingproblems etc. kann es vorkommen, dass diese Anzeige ggf. mal falsche Werte anzeigt. Bei einer Fahrt in eine Endposition, ohne die Fahrt zu stoppen (set Siro1 [on/off]), werden Statusanzeige und echte Position bei Erreichen der Position jedes Mal synchronisiert. Diese ist der Hardware geschuldet und technisch leider nicht anders l&ouml;sbar.
  1881. </li>
  1882. </ul>
  1883. </ul>
  1884. <br>
  1885. <b>Get</b>
  1886. <ul>N/A</ul><br>
  1887. <a name="Siroattr"></a>
  1888. <b>Attributes</b><br><br>
  1889. <ul>
  1890. <a name="IODev"></a>
  1891. <li>IODev<br>
  1892. Das IODev muss das physische Ger&auml;t zum Senden und Empfangen der Signale enthalten. Derzeit wird ein SIGNALduino bzw. SIGNALesp unterstützt.
  1893. Ohne der Angabe des "Sende- und Empfangsmodul" "IODev" ist keine Funktion moeglich.</li><br>
  1894. <a name="channel_send_mode_1 "></a>
  1895. <li>channel_send_mode_1 <br>
  1896. Beinhaltet den Kanal, der vom Modul im "operation_mode 1" zum Senden genutzt wird.
  1897. Dieses Attribut wird in "operation_mode 0" nicht genutzt
  1898. </li><br>
  1899. <a name="down_limit_mode_1 "></a>
  1900. <li>down_limit_mode_1 <br>
  1901. Bei gesetztem Attribut wird das Rollo bei einem Fahrt nach unten nur bis zur angegebenen Position gefahren, egal ob das Kommando über das Modul oder die Fernbedienung ausgloest wurde. Diese Funktion ist nur im Mode 1 aktiv.
  1902. </li><br>
  1903. <a name="down_auto_stop "></a>
  1904. <li>down_auto_stop <br>
  1905. Bei gesetztem Attribut fährt das Rollo bei einer Fahrt nach unten nur bis zur angegebenen Position. Eine weiterfahrt erfolgt nach nochmaligem Befehl. Diese Funktion greift nur bei dem Kommando on ( close ) . Hierbei ist es egal, ob das Kommando über das Modul oder die Fernbedienung ausgelöst wird.
  1906. </li><br>
  1907. <a name="operation_mode"></a>
  1908. <li>operation_mode<br>
  1909. Mode 0<br><br>
  1910. Dies ist der Standardmodus. In diesem Modus nutz das Modul nur den Kanal, der von der Fernbedienung vorgegeben ist. Hier kann es durch von FHEM verpasste Signale, Timingproblemen etc. im schlechtesten Fall zu falschen States und Positionsreadings kommen. Diese werden bei Anfahrt einer Endposition wieder synchronisiert.
  1911. <br><br>Mode 1<br><br>
  1912. Erweiterter Modus. In diesem Modus nutzt das Modul zwei Kan&auml;le. Den Standardkanal "channel" zum Empfangen der Fernbedienung. Dieser sollte nicht mehr durch das Rollo selbst empfangen werden. Und den "channel_send_mode_1", zum Senden an den Rollomotor. Hierzu ist eine Umkonfigurierung des Motors erforderlich. Dieser Modus ist in Bezug auf die Darstellung der States "deutlich sicherer", da ein Verpassen eines Signals durch FHEM nicht dazu f&uumlhrt, das falsche Positionen angezeigt werden. Das Rollo f&auml;hrt nur dann, wenn FHEM das Signal empfangen hat und an den Motor weiterreicht.
  1913. Eine Anleitung zur Konfiguration des Motors folgt.
  1914. </li><br>
  1915. <a name="time_down_to_favorite"></a>
  1916. <li>time_down_to_favorite<br>
  1917. beinhaltet die Fahrtzeit in Sekunden, die das Rollo von der 0% Position bis zur Hardware-Favoriten-Mittelposition ben&ouml;tigt. Diese Zeit muss manuell gemessen werden und eingetragen werden.
  1918. Ohne dieses Attribut ist das Modul nur eingeschr&auml;nkt funktionsf&auml;hig.</li><br>
  1919. <a name="time_to_close"></a>
  1920. <li>time_to_close<br>
  1921. beinhaltet die Fahrtzeit in Sekunden, die das Rollo von der 0% Position bis zur 100% Position ben&ouml;tigt. Diese Zeit muss manuell gemessen werden und eingetragen werden.
  1922. Ohne dieses Attribut ist das Modul nur eingeschr&auml;nkt funktionsf&auml;hig.</li><br>
  1923. <a name="time_to_open"></a>
  1924. <li>time_to_open<br>
  1925. beinhaltet die Fahrtzeit in Sekunden, die das Rollo von der 100% Position bis zur 0% Position ben&ouml;tigt. Diese Zeit muss manuell gemessen werden und eingetragen werden.
  1926. Ohne dieses Attribut ist das Modul nur eingeschr&auml;nkt funktionsf&auml;hig.</li><br>
  1927. <a name="prog_fav_sequence"></a>
  1928. <li>prog_fav_sequence<br>
  1929. beinhaltet die Kommandosequenz zum Programmieren der Harware-Favoritenposition</li><br>
  1930. <a name="debug_mode [0:1]"></a>
  1931. <li>debug_mode [0:1] <br>
  1932. Im Mode 1 werden zus&auml;tzliche Readings zur Fehlerbehebung angelegt, in denen die Ausgabe aller Modulelemente ausgegeben werden. Kommandos werden NICHT physisch gesendet.</li><br>
  1933. <a name="Info"></a>
  1934. <li>Info<br>
  1935. Die Attribute webcmd und devStateIcon werden beim Anlegen des Devices einmalig gesetzt und im auch im Betrieb an den jeweiligen Mode des Devices angepasst. Die Anpassung dieser Inhalte geschieht nur solange, bis diese durch den Nutzer ge&auml;ndert wurden. Danach erfolgt keine automatische Anpassung mehr.</li><br>
  1936. </ul>
  1937. </ul>
  1938. =end html_DE
  1939. =cut