| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244 |
- ################################################################
- #
- # Copyright notice
- #
- # (c) 2018 Oliver Georgi
- #
- # This script is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # The GNU General Public License can be found at
- # http://www.gnu.org/copyleft/gpl.html.
- # A copy is found in the textfile GPL.txt and important notices to the license
- # from the author is found in LICENSE.txt distributed with these scripts.
- #
- # This script is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # This copyright notice MUST APPEAR in all copies of the script!
- #
- ################################################################
- # $Id: 39_Talk2Fhem.pm 16337 2018-03-05 22:30:22Z Phill $
- #
- # 13.12.2017 0.0.2 diverses
- #
- # 16.12.2017 0.0.3 neuer pass check: else in @ sowie %
- # nicht alle pass keys werden durchlaufen sondern nur die geforderten
- # pass ^()$ ergänzt
- #
- # 19.12.2017 0.1.0 FHEM-Modul Funktionen eingefügt
- # Attribute T2F_keywordlist und T2F_modwordlist erzeugt
- ## 30.12.2017 0.2.0 Umgebungssuchen in regexp unterstützt
- # # Kommentierung ermöglicht
- # Syntaxcheck der Definition
- # Multiple Datumsangaben korrigiert
- # Wochentagsangaben korrigiert
- # Syntaxvereinfachung
- # Regexp-Listen erweitert
- # Multilingual DE EN
- # 02.01.2018 0.2.1 Liste der erase Wörter erweitert
- # problem bei wordlist ergänzung
- # multideviceable
- # Regexp in HASH auswertung
- # Automatische Umlautescaping
- # komma in wordlists
- # 26.01.2018 0.3.2 extra word search && in phrase
- # reihenfolge der DEF wird berücksichtigt
- # FHEM helper hash für globale verwendet
- # Code aufgeräumt
- # including definition files
- # zugriff auf Umgebungsmuster und Zeitphrasen
- # Phraseindikator ? und !
- # $n@ for keylistsaccess added
- # Zahlenwörter in Zeitphrase konvertieren
- # Eventgesteurte Befehle
- # Leerer set parameter löst den letzten befehl nochmal aus
- # 10.02.2018 0.4.0
- # set CLEARTRIGGERS
- # wieder Erkennung verbessert
- # Logikfehler bei verschachtelten Sätzen mit "und" behoben
- # Neue pass checks float, numeral
- # Extraktion des Klammernarrays auch bei Keylistenselector $n@
- # Bug on none existing namelists
- # Fhem $_ modifikations bug behoben
- # Log ausgaben verbessert
- # Neues Attribut T2F_if
- # Neues Attribut T2F_origin
- # Neuer GET standardfilter
- # Neuer GET log
- # Neue Variable $IF
- # Errormessages detaliert
- # Neuer Get @keylist @modlist
- # 12.02.2018 0.4.1
- # Community Notes
- # Nested Modifikations
- # Neuer Get modificationtypes
- # 19.02.2018 0.4.2
- # pass word changed
- # english adjust
- # nested bracket crash in arraymod fixed
- # syntaxissues on extendet commands fixed
- # umlautfix
- # 20.02.2018 0.4.3
- # Bug that not load attributes at bootup fixed
- # Function normalication updated
- # 21.02.2018 0.4.4
- # bracket extraction bug fixed
- # def not load at bootup fixed
- # 03.03.2018 0.4.5
- # timephrase modified
- # recognize order in hash replacement
- # Commandref fix unwanted characters
- # possibility of nested brackets in modifiacator
- # stabitility fixes in user regexp
- # replace ; to ;; in timecommands
- # Add 1 day if timecode is in past in hour phrases
- # Added async warning if keywordlist is unkown
- # 04.03.2018 0.4.6
- # Breacket decoding bug fixed
- # 04.02.2018 0.5.0
- # Feature: Object radiusing
- # 05.02.2018 0.5.1
- # Semicolon adding concretized
- # Problem with first letter umlaut in type modificator fixed
- # Fixed problems Attributes not ready
- # Matched/Unmatched corrected
- # Else in arraymodifikation expanded
- ################################################################
- # TODO:
- #
- # device verundung durch regexp klammern? eher durch try and error
- # answerx
- #
- # klammern in keywordlists sollen die $n nummerierung nicht beeinflussen
- # in keywordlists sind vermutlich nur maximal eine klammerebene möglich direkte regex arrays sind endlos verschachtelbar
- # zusätzlich unmodifizierte zeit greifbar machen
- # timephrase kombies morgen früh um 9 uhr ist unzuverlässig. evtl order einführen, dann kann auch die splittung weg
- # viertel zeitphrasen
- # - regexp
- #vordefinierte regex zu verfügung stellen
- # (i[nm]|vor|auf|unter|hinter)? ?(de[rmn]|die|das)? ?
- package main;
- use strict;
- use warnings;
- use POSIX;
- use Data::Dumper;
- use Time::Local;
- use Text::ParseWords;
- use Text::Balanced qw(extract_multiple extract_bracketed);
- use Encode qw(decode encode);
- my %Talk2Fhem_globals;
- $Talk2Fhem_globals{version}="0.5.1";
- $Talk2Fhem_globals{EN}{erase} = ['\bplease\b', '\balso\b', '^msgtext:'];
- $Talk2Fhem_globals{EN}{numbers} = {
- 'zero' => 0
- ,'^one\S*' => 1
- ,'^(two|twice)' => 2
- ,'^(three|third)' => 3
- ,'^four\S*' => 4
- ,'^five\S*' => 5
- ,'^six\S*' => 6
- ,'^seven\S*' => 7
- ,'^eight\S*' => 8
- ,'^nine\S*' => 9
- ,'^ten\S*' => 10
- ,'^eleven\S*' => 11
- ,'^twelve\S*' => 12
- };
- $Talk2Fhem_globals{DE}{numberre} = join("|", ('\d+', keys %{$Talk2Fhem_globals{DE}{numbers}}));
- $Talk2Fhem_globals{EN}{pass} = {
- true => '^(yes|1|true|on|open|up|bright.*)$',
- false => '^(no|0|false|off|close|down|dark.*)$',
- numeral => {re=>"($Talk2Fhem_globals{EN}{numberre})",fc=>sub{
- return ($_[0]) if $_[0] =~ /\d+/;
- my $v = $_[0];
- foreach ( keys %{$Talk2Fhem_globals{EN}{numbers}} ) {
- my $tmp = Talk2Fhem_escapeumlauts($_);
- last if ($v =~ s/$tmp/$Talk2Fhem_globals{EN}{numbers}{$_}/i);
- }
- return($v);}
- },
- integer => '\b(\d+)\b',
- float => {re=>'\b(\d+)(\s*[,.])?(\s*(\d+))?\b',fc=>'"$1".("$4"?".$4":"")'},
- word => '\b(\w{4,})\b',
- empty => '^\s*$'
- };
- $Talk2Fhem_globals{EN}{datephrase} = {
- 'tomorrow'=> {days=>1}
- , 'day after tomorrow'=> {days=>2}
- , 'yesterday'=> {days=>-1}
- , 'the day before yesterday'=> {days=>-2}
- , 'in (\d+) week\S?'=> {days=>'(7*$1)'}
- , 'in (\d+) month(\S\S)?'=> {month=>'"$1"'}
- , 'in (\d+) year(\S\S)?'=> {year=>'"$1"'}
- , 'next week'=> {days=>7}
- , 'next month'=> {month=>1}
- , 'next year'=> {year=>1}
- , '(on )?sunday'=> {wday=>0}
- , '(on )?monday'=> {wday=>1}
- , '(on )?tuesday'=> {wday=>2}
- , '(on )?Wednesday'=> {wday=>3}
- , '(on )?thursday'=> {wday=>4}
- , '(on )?friday'=> {wday=>5}
- , '(on )?saturday'=> {wday=>6}
- , 'in (\d+) days?'=> {days=>'"$1"'}
- , 'on (\d\S*(\s\d+)?)'=> {date=>'"$1"'}
- };
- $Talk2Fhem_globals{EN}{timephrase} = {
- '(in|and|after)? (\d+) hours?' => {hour=>'"$2"'}
- , '(in|and|after)? (\d+) minutes?' => {min=>'"$2"'}
- , '(in|and|after)? (\d+) seconds?' => {sec=>'"$2"'}
- , 'now' => {min=>3}
- , 'after' => {min=>30}
- , 'later' => {hour=>1}
- , 'right now' => {unix=>'time'}
- , 'immediately' => {unix=>'time'}
- , 'by (\d+) (o.clock)?' => {time=>'"$1"'}
- , 'at (\d+) (o.clock)?' => {time=>'"$1"'}
- , 'morning' => {time=>'"09:00"'}
- , 'evening' => {time=>'"18:00"'}
- , 'afternoon' => {time=>'"16:00"'}
- , 'morning' => {time=>'"10:30"'}
- , 'noon' => {time=>'"12:00"'}
- , 'at lunchtime' => {time=>'"12:00"'}
- , 'today' => {time=>'"12:00"'}
- };
- #$Talk2Fhem_globals{DE}{erase} = ['\bbitte\b', '\bauch\b', '\smachen\b', '\sschalten\b', '\sfahren\b', '\bkann\b', '\bsoll\b', '\bnach\b', '^msgtext:'];
- $Talk2Fhem_globals{DE}{erase} = ['\bbitte\b', '\bauch\b','\bkann\b', '\bsoll\b'];
- # true => '^(ja|1|true|wahr|ein|eins.*|auf.*|öffnen|an.*|rauf.*|hoch.*|laut.*|hell.*)$',
- # false => '^(nein|0|false|falsch|aus.*|null|zu.*|schlie\S\S?en|runter.*|ab.*|leise.*|dunk.*)$',
- $Talk2Fhem_globals{DE}{numbers} = {
- 'null' => 0
- ,'(ein\S*|erste\S*)' => 1
- ,'zwei\S*' => 2
- ,'(drei\S*|dritt\S*)' => 3
- ,'vier\S*' => 4
- ,'fünf\S*' => 5
- ,'sechs\S*' => 6
- ,'sieb\S*' => 7
- ,'acht\S*' => 8
- ,'neun\S*' => 9
- ,'zehn\S*' => 10
- ,'elf\S*' => 11
- ,'zwölf\S*' => 12
- };
- $Talk2Fhem_globals{DE}{numberre} = join("|", ('\d+', keys %{$Talk2Fhem_globals{DE}{numbers}}));
- $Talk2Fhem_globals{DE}{pass} = {
- true => '\b(ja|1|true|wahr|ein|eins.*|auf.*|\S*ffnen|an.*|rauf.*|hoch.*|laut.*|hell.*|start.*|(ab)?spiele\S?)\b',
- false => '\b(nein|0|false|falsch|aus.*|null|zu.*|schlie\S\S?en|runter.*|ab.*|leise.*|dunk.*|stop.*|beende\S?)\b',
- numeral => {re=>"($Talk2Fhem_globals{DE}{numberre})",fc=>sub{
- return ($_[0]) if $_[0] =~ /\d+/;
- my $v = $_[0];
- foreach ( keys %{$Talk2Fhem_globals{DE}{numbers}} ) {
- my $tmp = Talk2Fhem_escapeumlauts($_);
- last if ($v =~ s/$tmp/$Talk2Fhem_globals{DE}{numbers}{$_}/i);
- }
- return($v);}
- },
- integer => '\b(\d+)\b',
- float => {re=>'\b(\d+)(\s*[,.])?(\s*(\d+))?\b',fc=>'"$1".("$4"?".$4":"")'},
- word => '\b(\w{4,})\b',
- empty => '^\s*$'
- };
- $Talk2Fhem_globals{DE}{datephrase} = {
- 'morgen'=> {days=>1}
- , 'übermorgen'=> {days=>2}
- , 'gestern'=> {days=>-1}
- , 'vorgestern'=> {days=>-2}
- , 'in ('.$Talk2Fhem_globals{DE}{numberre}.') woche\S?'=> {days=>'(7*$1)'}
- , 'in ('.$Talk2Fhem_globals{DE}{numberre}.') monat(\S\S)?'=> {month=>'"$1"'}
- , 'in ('.$Talk2Fhem_globals{DE}{numberre}.') jahr(\S\S)?'=> {year=>'"$1"'}
- , 'nächste.? woche'=> {days=>7}
- , 'nächste.? monat'=> {month=>1}
- , 'nächste.? jahr'=> {year=>1}
- , '(am )?sonntag'=> {wday=>0}
- , '(am )?montag'=> {wday=>1}
- , '(am )?dienstag'=> {wday=>2}
- , '(am )?mittwoch'=> {wday=>3}
- , '(am )?donnerstag'=> {wday=>4}
- , '(am )?freitag'=> {wday=>5}
- , '(am )?samstag'=> {wday=>6}
- , 'in ('.$Talk2Fhem_globals{DE}{numberre}.') tag(\S\S)?'=> {days=>'"$1"'}
- , 'am (\d\S*(\s\d+)?)'=> {date=>'"$1"'}
- };
- # fc modify time. $_[0] = ermittelte zeit. Zugriff auf $1 $2 usw
- $Talk2Fhem_globals{DE}{timephrase} = {
- '(in|und|nach)? ('.$Talk2Fhem_globals{DE}{numberre}.') stunde.?' => {hour=>'"$2"'}
- , '(in|und|nach)? ('.$Talk2Fhem_globals{DE}{numberre}.') minute.?' => {min=>'"$2"'}
- , '(in|und|nach)? ('.$Talk2Fhem_globals{DE}{numberre}.') sekunde.?' => {sec=>'"$2"'}
- , 'gleich' => {min=>3}
- , 'nachher' => {min=>30}
- , 'später' => {hour=>1}
- , 'jetzt' => {unix=>'time'}
- , 'sofort' => {unix=>'time'}
- , 'um (\d+\s?\:\s?\d+|'.$Talk2Fhem_globals{DE}{numberre}.') (uhr)?' => {
- time=>'"$1"',
- fc=>sub () {(($_[0] + 3600) < time) ? ($_[0]+3600*24) : $_[0] }
- }
- , 'um ('.$Talk2Fhem_globals{DE}{numberre}.') uhr ('.$Talk2Fhem_globals{DE}{numberre}.')' => {
- hour=>'"$1"',
- min=>'"$1"',
- fc=>sub () {(($_[0] + 3600) < time) ? ($_[0]+3600*24) : $_[0] }
- } ############ ZU TESTEN
- , 'früh' => {time=>'"09:00"'}
- , 'abends?' => {time=>'"18:00"'}
- , 'nachmittags?' => {time=>'"16:00"'}
- , 'vormittags?' => {time=>'"10:30"'}
- , 'mittags?' => {time=>'"12:00"'}
- , 'heute' => {time=>'"12:00"'}
- };
- sub Talk2Fhem_Initialize($);
- sub Talk2Fhem_Define($$);
- sub Talk2Fhem_Undef($$);
- sub Talk2Fhem_Delete($$);
- sub Talk2Fhem_Notify($$);
- sub Talk2Fhem_Set($@);
- sub Talk2Fhem_addND($);
- sub Talk2Fhem_UpdND($);
- sub Talk2Fhem_Get($$@);
- sub Talk2Fhem_Attr(@);
- sub Talk2Fhem_Loadphrase($$$);
- sub Talk2Fhem_parseParams($);
- sub Talk2Fhem_realtrim($);
- sub Talk2Fhem_normalize($);
- sub Talk2Fhem_parseArray($;$$);
- sub Talk2Fhem_loadList($$;$);
- sub Talk2Fhem_language($);
- sub Talk2Fhem_mkattime($$);
- sub Talk2Fhem_exec($$$);
- sub T2FL($$$);
- sub Talk2Fhem_Initialize($)
- {
- my ($hash) = @_;
- $hash->{DefFn} = "Talk2Fhem_Define";
- $hash->{UndefFn} = "Talk2Fhem_Undef";
- # $hash->{DeleteFn} = "X_Delete";
- $hash->{SetFn} = "Talk2Fhem_Set";
- $hash->{GetFn} = "Talk2Fhem_Get";
- # $hash->{ReadFn} = "X_Read";
- # $hash->{ReadyFn} = "X_Ready";
- $hash->{AttrFn} = "Talk2Fhem_Attr";
- $hash->{NotifyFn} = "Talk2Fhem_Notify";
- # $hash->{RenameFn} = "X_Rename";
- # $hash->{ShutdownFn} = "X_Shutdown";
- $hash->{AttrList} =
- "disable:0,1 T2F_disableumlautescaping:0,1 T2F_origin T2F_filter T2F_if:textField-long T2F_keywordlist:textField-long T2F_modwordlist:textField-long T2F_language:EN,DE";
-
- }
- sub Talk2Fhem_Define($$)
- {
- my ( $hash, $def ) = @_;
-
- $hash->{STATE} = "Loading";
-
- if ($def =~ /^\S+ Talk2Fhem$/) {
- $hash->{DEF} = "# <regex> = <command>\n# Examples:\n# timer (löschen|zurück)\t= set \$NAME cleartimers\n# ereignis\\S* (löschen|zurück)\t= set \$NAME cleartriggers";
-
- return;
- }
-
- my $error = undef;
- my @def = split(/ /, $def);
- my $name = shift(@def);
- my $dev = shift(@def);
- $hash->{STATE} = "Initialized";
- if ($init_done) {
- ($_ = Talk2Fhem_loadList($hash, "T2F_keywordlist")) && return;
- ($_ = Talk2Fhem_loadList($hash, "T2F_modwordlist")) && return;
- $error = Talk2Fhem_Loadphrase($hash, "phrase", "@def");
- T2FL($name, 1, $error) if $error;
- # T2FL($name, 5, "T2F Phrasehash:\n".Dumper($Talk2Fhem_phrase{$name})) unless $error;
- T2FL($name, 5, "T2F Phrasehash:\n".Dumper($hash->{helper}{phrase})) unless $error;
- $hash->{STATE} = "Ready";
- }
-
- return $error;
- }
- sub Talk2Fhem_Loadphrase($$$) {
-
- my $hash = shift;
- my $target = shift;
- my $text = "@_";
- my @h = Talk2Fhem_parseParams($text);
- return ("Error while parsing Definition.\n$h[0]"."\n\n$text" ) unless(ref($h[0]) eq "HASH");
- # Not ready yet
- return unless $hash->{helper};
-
- my $disu =AttrVal($hash, "T2F_disableumlautescaping", 0);
- my %keylist = %{$hash->{helper}{T2F_keywordlist}} if $hash->{helper}{T2F_keywordlist};
- my $i=0;
- while ($i <= $#h) {
- my $elmnt = $h[$i];
- my @a = $$elmnt{key}=~/(?<!\\)\(/g;
- my @b = $$elmnt{key}=~/(?<!\\)\)/g;
- return("Error while parsing Definition HASH.\nOdd numbers of brackets ():\n".$$elmnt{key}) unless $#a eq $#b;
- if ($$elmnt{key} eq '$include') {
- T2FL $hash->{NAME}, 4, "Loading Configfile $$elmnt{val}";
- # open(my $fh, '<:encoding(UTF-8)', $$elmnt{val})
- # open fh, "<", $$elmnt{val}
- # or return "Could not open file '$$elmnt{val}' $!";
- my ($error, @content) = FileRead($$elmnt{val});
- return "$error '$$elmnt{val}'" if $error;
-
- #local $/;
- my @file = Talk2Fhem_parseParams(join("\n",@content));
- #close("fh");
- return ("Error while parsing File $$elmnt{val}.\n$file[0]"."\n\n$text" ) unless(ref($file[0]) eq "HASH");
- splice @h, $i, 1;
- splice @h, $i, 0, @file;
- # push(@h, @file);
- next;
- }
-
-
- if ($$elmnt{val} =~ /^\((.*)\)/) {
- #my %r = eval($$elmnt{val});
- #Log 1, "Hallo: ".$1;
- my %r;
- my $harr = Talk2Fhem_parseArray($1, undef, 1);
- for my $el (@$harr) {
- my @test = split(/[\s\t]*=>[\t\s\n]*/,$el,2);
- my $t = $test[1] =~ /^[^"']/;
- #Log 1, Dumper @test;
- #Log 1, Dumper $t;
- my $h = Talk2Fhem_parseArray($el, '\s*=>[\t\s\n]*', $t);
- #my @arr = /(.*?)=>(.*)/;
- #$h = Talk2Fhem_parseArray($_, "=>", 1) if $$h[0]=~ /answer/;
-
- $r{$$h[0]} = $$h[1];
- }
- return("Error while parsing Definition HASH.\n".$$elmnt{val}."\n\n$text") unless (%r);
- $$elmnt{val} = \%r;
- }elsif ($$elmnt{val} =~ /^\(.*[^)]$/) {
- return("Error while parsing Definition HASH.\nDid you forget closing ')' in:\n".$$elmnt{val}."\n\n$text");
- } else {
- my $tmp=$$elmnt{val};
- $$elmnt{val} = undef;
- $$elmnt{val}{($target eq "phrase") ? "cmd" : $target} = $tmp;
- }
-
- #alternative syntax wenn nur ein value
- # elsif ($$elmnt{key} =~ /^\$if.*?\s+(.*)/) {
- #return("Syntax Error. Can't locate IF condition.") unless $1;
- #return("Syntax Error. Can't locate IF regexp.") unless $$elmnt{val};
- #$hash->{helper}{ifs} = { IF=>$$elmnt{val}, regexp=>"$1" };
- #splice @h, $i, 1;
- #next;
- # }
- $i++;
-
- # Regexp Auflösung und Analyse
- my $d=0;
- my @hitnokeylist=(AttrVal($hash->{NAME}, "T2F_origin", undef));
- my @phrs = map { Talk2Fhem_realtrim($_) } split(/[\t\s]*\&\&[\t\s]*/, $$elmnt{key});
- for my $phr (@phrs) {
- my $keylistname;
- my $tmp = $phr;
- # klammern zählen die nicht geslasht sind und kein spezialklammern sind (?
- while ($tmp =~ /(?<!\\)\((?!\?)(@(\w+))?/g) {
- $d++;
- if ($1) {
- $keylistname = $2;
- unless ($keylist{$keylistname}) {
- asyncOutput($hash->{CL}, "Warning: Unkown keywordlist $1. In phrase: $phr");
- next;
- #return(T2FL($hash, 1, "Unkown keywordlist $1. In phrase: $phr"));
- }
- my $re = join("|", @{$keylist{$keylistname}});
- $phr =~ s/@(\w+)/$re/;
- #speichern welcher array in welcher klammer steht
- $hitnokeylist[$d] = $keylistname;
- }
- }
- push(@{$$elmnt{regexps}}, Talk2Fhem_escapeumlauts($phr, $disu));
- $$elmnt{hitnokeylist} = \@hitnokeylist;
- }
- }
-
- # for (@h) {
- # next unless ($$_{val}{if});
- # my $test = AnalyzeCommandChain ($hash, "IF ((".$$_{val}{if}.")) ({1})");
- # if ($test and $test ne "1") {
- # T2FL $hash, 1, "Condition ".$$_{val}{if}." failed: ".$test;
- # return($test."\n\n".$text);
- # }
- # }
-
-
- $hash->{helper}{$target} = \@h;
- return(undef);
- }
- sub Talk2Fhem_Undef($$)
- {
- my ( $hash, $name) = @_;
- $hash->{helper} = undef;
-
- return undef;
- }
- sub Talk2Fhem_Delete($$)
- {
- my ( $hash, $name ) = @_;
-
- return undef;
- }
- sub Talk2Fhem_Notify($$)
- {
- my ($own_hash, $dev_hash) = @_;
- my $ownName = $own_hash->{NAME};
-
- my $devName; # Device that created the events
- for (@{$$own_hash{helper}{notifiers}}) {
- $devName = $dev_hash->{NAME} if $_ eq $dev_hash->{NAME};
- }
- return "" unless $devName;
- my $events = deviceEvents($dev_hash, 1);
- my @nots = @{$$own_hash{helper}{notifies}};
- my $i=0;
- # for my $i (0 .. $#nots) {
- while ($i <= $#{$$own_hash{helper}{notifies}}) {
- my $not = ${$$own_hash{helper}{notifies}}[$i];
- if (grep { $devName eq $_ } (@{$$not{devs}})) {
- T2FL $own_hash, 4, "Event detected ".$$not{if};
- my $res = fhem($$not{if});
- T2FL $own_hash, 5, "Result: ".$res;
- if ($res == 1) {
- T2FL $own_hash, 3, "Execute command: ".$$not{cmd};
-
- my $fhemres = fhem($$not{cmd});
- readingsSingleUpdate($own_hash, "response", $fhemres, 1);
- splice(@{$$own_hash{helper}{notifies}}, $i--, 1);
- Talk2Fhem_UpdND($own_hash);
- } elsif ($res) {
- T2FL $own_hash, 1, "Error on condition ($$not{if}): $res";
- readingsSingleUpdate($own_hash, "response", $res, 1);
- splice(@{$$own_hash{helper}{notifies}}, $i--, 1);
- Talk2Fhem_UpdND($own_hash);
- }
- }
- $i++;
- }
-
- return "" if(IsDisabled($ownName));
-
- if($devName eq "global" && grep(m/^INITIALIZED|REREADCFG$/, @{$events}))
- {
- #Talk2Fhem_parseKeys($own_hash);
- }
- }
- sub Talk2Fhem_Set($@)
- {
- my ( $hash, $name, @args ) = @_;
- (return "\"set $name\" needs at least one argument") unless(scalar(@args));
- (return "Unknown argument ?, choose one of ! cleartriggers:noArg cleartimers:noArg") if($args[0] eq "?");
-
- if ($hash->{STATE} ne "Ready") {
- #Fülle nur cmds array
- } elsif ($args[0] eq "cleartimers") {
- AnalyzeCommand($hash->{CL}, "delete at_".$name."_.*");
- } elsif ($args[0] eq "cleartriggers") {
-
- $$hash{helper}{notifies} = [];
- Talk2Fhem_UpdND($hash);
- } else {
- $hash->{STATE} = "Loading";
- shift @args if $args[0] eq "!";
- @args = ReadingsVal($name, "set", undef) unless(scalar(@args));
-
- #my $txt = s/[^\x00-\xFF]//g;
- #my $txt = decode("utf8", "@args");
- my $txt = "@args";
- Talk2Fhem_loadList($hash, "T2F_keywordlist") unless $hash->{helper}{T2F_keywordlist};
- Talk2Fhem_loadList($hash, "T2F_modwordlist") unless $hash->{helper}{T2F_modwordlist};
- Talk2Fhem_Loadphrase($hash, "phrase", $hash->{DEF}) unless $hash->{helper}{phrase};
- Talk2Fhem_Loadphrase($hash, "if", AttrVal($name, "T2F_if","")) if (AttrVal($name, "T2F_if",0) and ! $hash->{helper}{if});
-
- readingsSingleUpdate($hash, "set", "$txt", 1);
- $hash->{STATE} = "Ready";
-
- $hash->{STATE} = "Working";
-
-
-
- my %res = Talk2Fhem_exec("$txt", $hash, $name);
- if (%res && ! $res{err} && $res{cmds}) {
- #Ausführen
- if ($res{cmds}) {
- for my $h (@{$res{cmds}}) {
- my $fhemcmd = ($$h{at}?Talk2Fhem_mkattime($name, $$h{at})." ":"").($$h{at}?($$h{cmd} =~ s/;/;;/gr):$$h{cmd});
-
- unless ($$h{ifs}) { # kein IF
-
- T2FL $name, 5, "Executing Command: ".$fhemcmd;
- my $fhemres = AnalyzeCommandChain ($hash->{CL}, $fhemcmd) unless (IsDisabled($name));
- $$h{"fhemcmd"} = $fhemcmd;
- push(@{$res{fhemres}}, $fhemres) if ($fhemres);
- T2FL $name, 5, "Pushed: ".$fhemcmd;
- } else { # If
- #Event erstellen
- my %r;
- $r{hash} = $hash;
- $r{if} = "IF ((".(join(") and (", @{$$h{ifs}})).")) ({1})";
- my $test = AnalyzeCommandChain ($hash->{CL}, $r{if});
- if ($test and $test ne "1") {
- T2FL $name, 1, "Condition $r{if} failed: ".$test;
- push(@{$res{fhemres}}, $test);
- next;
- } my %s = (); # make it unique
- push(@{$r{devs}}, grep { ! $s{$_}++ } map {/\[(.*?)[:\]]/g} @{$$h{ifs}});
- $r{cmd} = $fhemcmd;
- Talk2Fhem_addND(\%r);
- }
- }
- }
- } else {
- # Nothing to do
- T2FL $name, 1, "Nothing to do: ".$txt;
- }
-
- #push(@{$res{err}}, "FHEM: ".$fhemres) if $fhemres;
-
- my $status;
- if ($res{fhemres}) { $status = "response" }
- elsif (IsDisabled($name)) {$status = "disabled"}
- elsif ($res{err}) {$status = "err"}
- elsif ($res{answers}) {$status = "answers"}
- else {$status = "done"}
-
- readingsBeginUpdate($hash);
- #T2FL($hash, 1, "CL:\n".Dumper($hash->{CL}));
- #readingsBulkUpdate($hash, "client", $hash->{CL}{NAME});
- readingsBulkUpdate($hash, "ifs", join(" and ", @{$res{ifs}})) if $res{ifs};
- #readingsBulkUpdate($hash, "cmds", join(";\n", map { ($$_{at}?Talk2Fhem_mkattime($name, $$_{at})." ":"").$$_{cmd} } @{$res{cmds}})) if $res{cmds};
- readingsBulkUpdate($hash, "cmds", join(";\n", map { $$_{"fhemcmd"} } @{$res{cmds}})) if $res{cmds};
- readingsBulkUpdate($hash, "answers", join(" und ", @{$res{answers}})) if $res{answers};
- readingsBulkUpdate($hash, "err", join("\n", @{$res{err}})) if $res{err};
- readingsBulkUpdate($hash, "response", join("\n", @{$res{fhemres}})) if $res{fhemres};
- readingsBulkUpdate($hash, "status", $status);
- ### in done könnte
- readingsEndUpdate($hash, 1);
-
- }
- $hash->{STATE} = "Ready";
- return;
- }
- sub Talk2Fhem_addND($) {
- #Log 1, Dumper $_[0]{cmds};
- my $hash = $_[0]{hash};
- unless(IsDisabled($$hash{NAME})) {
- my %h;
- for (keys %{$_[0]}) {
- next if /hash/;
- $h{$_} = $_[0]{$_};
- }
- push(@{$$hash{helper}{notifies}}, \%h);
- Talk2Fhem_UpdND($hash);
- }
- }
- sub Talk2Fhem_UpdND($) {
- my ($hash) = @_;
- my %s = (); # make it unique
- my @ntfs = @{$$hash{helper}{notifies}};
- @{$$hash{helper}{notifiers}} = grep { ! $s{$_}++ } map { @{$$_{devs}} } @ntfs;
- #$$hash{NOTIFYDEV} = join ",",@{$$hash{helper}{notifiers}};
- notifyRegexpChanged($hash, join "|",@{$$hash{helper}{notifiers}});
- readingsSingleUpdate($hash, "notifies", join( "\\n", map {$$_{if}} @ntfs), 1);
- T2FL $hash, 4, "Updated NotifyDev: ".join( "|", @{$$hash{helper}{notifiers}});
- T2FL $hash, 5, "Updated NotifyDev: ".Dumper @ntfs;
- }
- sub Talk2Fhem_Get($$@)
- {
- my ( $hash, $name, $opt, @args ) = @_;
- my $lang = Talk2Fhem_language($hash);
- return "\"get $name\" needs at least one argument" unless(defined($opt));
- if($opt eq "keylistno")
- {
- my $res;
- my $keylist = Talk2Fhem_parseParams(AttrVal($name, "T2F_keywordlist", ""));
- foreach (keys %$keylist) {
- $res .= $_.":\n";
- my $arr = Talk2Fhem_parseArray($$keylist{$_});
- for (my $i=0;$i<=$#$arr;$i++) {
- $res .= ($i+1).": ".$arr->[$i]."\n";
- }
- }
- return $res;
- }
- elsif($opt =~ /^\@/)
- {
- my $keylist = Talk2Fhem_parseParams(AttrVal($name, "T2F_keywordlist", ""));
- my $modlist = Talk2Fhem_parseParams(AttrVal($name, "T2F_modwordlist", ""));
-
- my $r;
- (my $kwl = $opt) =~ s/^\@//;
- (my $mwl = $args[0]) =~ s/^\@//;
- my $kw = Talk2Fhem_parseArray($$keylist{$kwl});
- my $mw = Talk2Fhem_parseArray($$modlist{$mwl});
- my $l=11;
- map { $l = length($_) if length($_) > $l } (@$kw);
- $r .= "Keywordlist".(" " x ($l-11))." : "."Modwordlist\n";
- $r .= $opt.(" " x ($l-length($opt)))." : ".$args[0]."\n\n";
- for my $i (0..$#$kw) {
- $r .= ($$kw[$i]//"").(" " x ($l-length(($$kw[$i]//""))))." : ".($$mw[$i]//"")."\n";
- }
-
-
- return($r);
- }
- elsif($opt eq "standardfilter")
- {
- my $atr=AttrVal($name, "T2F_filter", 0);
- my $filter = join(',',@{$Talk2Fhem_globals{Talk2Fhem_language($name)}{erase}});
- if ($atr) {
- return("Attribute T2F_filter is not empty please delete it.");
- } else {
- fhem("attr $name T2F_filter $filter");
- return("Filterattribute set to standard.");
- }
- }
- elsif($opt eq "log")
- {
- return($hash->{helper}{LOG});
- }
- elsif($opt eq "modificationtypes")
- {
- my $res = ref $Talk2Fhem_globals{$lang}{pass}{$args[0]} && $Talk2Fhem_globals{$lang}{pass}{$args[0]}{re} || $Talk2Fhem_globals{$lang}{pass}{$args[0]};
- return(($lang eq "DE" ? "Folgende RegExp wird erwartet:\n" : "The following regexp is expected:\n").$res);
- }
- elsif($opt eq "datedefinitions")
- {
- return(Dumper %{$Talk2Fhem_globals{$lang}{datephrase}});
- }
- elsif($opt eq "timedefinitions")
- {
- return(Dumper %{$Talk2Fhem_globals{$lang}{timephrase}});
- }
- elsif($opt eq "version")
- {
- return(Dumper $Talk2Fhem_globals{version});
- }
- # ...
- else
- {
- my $keylist = Talk2Fhem_parseParams(AttrVal($name, "T2F_keywordlist", ""));
- my $modlist = Talk2Fhem_parseParams(AttrVal($name, "T2F_modwordlist", ""));
- return "Unknown argument $opt, choose one of keylistno:noArg log:noArg standardfilter:noArg version:noArg".
- " @".join(" @",map { $_.":@".join(",@", sort keys %$modlist) } sort keys %$keylist).
- " modificationtypes:".join(",", sort keys %{$Talk2Fhem_globals{$lang}{pass}}).
- " datedefinitions:noArg timedefinitions:noArg";
- }
- }
- sub Talk2Fhem_Attr(@)
- {
- my ( $cmd, $name, $attrName, $attrValue ) = @_;
-
- # $cmd - Vorgangsart - kann die Werte "del" (löschen) oder "set" (setzen) annehmen
- # $name - Gerätename
- # $attrName/$attrValue sind Attribut-Name und Attribut-Wert
- return unless $init_done;
- #Log 1, Dumper @_;
- if ($attrName eq "T2F_keywordlist" or $attrName eq "T2F_modwordlist") {
- $defs{$name}{helper}{phrase} = undef;
- $defs{$name}{helper}{if} = undef;
- if ($cmd eq "set") {
- T2FL $name, 4, "Attribute checking!";
- return Talk2Fhem_loadList($defs{$name}, $attrName, $attrValue);
- } else {
- delete $defs{$name}{helper}{$attrName};
- }
- }
- if ($attrName eq "T2F_if") {
- if ($cmd eq "set") {
- return(Talk2Fhem_Loadphrase($defs{$name}, "if", $attrValue));
- } else {
- delete $defs{$name}{helper}{if};
- }
- }
-
-
- #elsif ($attrName eq "T2F_filter") {
- #Log 1, "HALLO".$defs{global}{STATE};
- #my $preattr = AttrVal($name, "T2F_filter", "");
- #if ($preattr eq "") {
- # $_[3] = join(",", @{$Talk2Fhem_globals{Talk2Fhem_language($name)}{erase}}).",".$attrValue;
- #}}
- return undef;
- }
- sub Talk2Fhem_parseParams_old($)
- {
- my ($val) = @_;
- my %res; my $i=0;
- foreach my $v (split(/\n/,$val)) {
- # if ($v =~ /^[ \t]*(?!#)(.*?)[ \t]+=[ \t]+(.*?)[ \t]*$/) {
- $i++;
- $v =~ s/#.*//;
- next unless $v;
- if ($v =~ /^[ \t]*(.*?)[ \t]+=[ \t]+(.*?)[ \t]*$/) {
- return ("#$i Missing REGEXP '$v'") unless ($1);
- return ("#$i Missing Command '$v'") unless ($2);
- $res{$1} = $2;
- } else {
- return ("#$i Syntaxerror. '$v'\nDid you forget whitespace before or after '='");
- }
- }
- return(\%res);
- }
- sub Talk2Fhem_realtrim($)
- {
- my $string = shift;
- $string =~ s/^[\s\t\n]*|[\s\t\n]*$//g;
- # $string =~ s/^[\s\t\n]*|[\s\t\n]*$//g;
- return $string;
- }
- sub Talk2Fhem_normalize($)
- {
- my $string = shift;
- #mach probleme bei "ue"
- # $string =~ s/\s{2,}|\b\w\b|\t|\n|['".,;:\!\?]/ /g;
- $string =~ s/\s{2,}|\t|\n|['".,;\!\?]/ /g;
- return $string;
- }
- sub Talk2Fhem_parseParams($)
- {
- my ($def) = @_;
- my $val = $def;
- my $i=0;
- my %hres;
- my @res;
- while ($val =~ /(.*?)[ \t]+=[ \t\n]+((.|\n)*?)(?=(\n.*?[ \t]+=[ \t\n]|$))/) {
- my $pre = Talk2Fhem_realtrim($`);
- if ($pre) {
- return ("Syntaxerror: $pre") if ($pre !~ /^#/);
- }
- $val = $';
- next if (Talk2Fhem_realtrim($1) =~ /^#/);
- my $key = $1;
- my $val = $2; my $r;
- $key = Talk2Fhem_realtrim($key);
- foreach my $line (split("\n", $val)) {
- $line =~ s/#.*//;
- $line = Talk2Fhem_realtrim($line);
- $r .= $line;
- }
- if ( wantarray ) {
- push(@res, {key => $key, val => $r});
- } else {
- $hres{$key} = $r;
- }
-
- }
- return ("Syntaxerror: $val") if (Talk2Fhem_realtrim($val));
-
- return(@res) if ( wantarray );
- return(\%hres);
-
- }
- sub Talk2Fhem_parseArray($;$$)
- {
- my ($val, $split, $keep) = @_;
- $split = "," unless $split;
- my @r = map {Talk2Fhem_realtrim($_)} quotewords($split, $keep, $val);
- return(\@r);
- }
- sub Talk2Fhem_loadList($$;$)
- {
- my $hash = shift;
- my $type = shift;
- my $list = (shift || AttrVal($hash->{NAME}, $type, ""));
- $list = Talk2Fhem_parseParams($list);
- return ("Error while parsing Keywordlist.\n$list" ) unless(ref($list) eq "HASH");
- delete $hash->{helper}{T2F_andwordlist} if $type eq "T2F_keywordlist";
- delete $hash->{helper}{$type};
- foreach (keys %$list) {
- # $$list{$_} = Talk2Fhem_parseArray($$list{$_});
- $hash->{helper}{T2F_andwordlist}{$_} = Talk2Fhem_parseArray($$list{$_}) if /^\&/;
- $hash->{helper}{$type}{s/^\&//r} = Talk2Fhem_parseArray($$list{$_});
- }
-
-
- # my $modlist = Talk2Fhem_parseParams(AttrVal($name, "T2F_modwordlist", ""));;
- # return ("Error while parsing Modwordlist.\n$modlist" ) unless(ref($modlist) eq "HASH");
- # foreach (keys %$modlist) {
- ## $$modlist{$_} = Talk2Fhem_parseArray($$modlist{$_});
- # $hash->{helper}{modlist}{$_} = Talk2Fhem_parseArray($$modlist{$_});
- # }
- }
- sub Talk2Fhem_language($)
- {
- my ($name) = @_;
- my $lang = AttrVal($name, "T2F_language", AttrVal("global", "language", "DE"));
- $lang=uc($lang);
- $lang = "DE" unless $lang =~ /DE|EN/;
- return($lang);
- }
- sub Talk2Fhem_mkattime($$) {
- my $myname = $_[0];
- my $i = $_[1];
- my @ltevt = localtime($i);
- my $d=0; my $dev="at_".$myname."_".$i."_".$d;
- while ($defs{$dev}) {$dev = "at_".$myname."_".$i."_".++$d}
-
- return("define at_".$myname."_".$i."_".$d." at "
- .($ltevt[5]+1900)
- ."-".sprintf("%02d", ($ltevt[4]+1))
- ."-".sprintf("%02d", $ltevt[3])
- ."T".sprintf("%02d", $ltevt[2])
- .":".sprintf("%02d", $ltevt[1])
- .":".sprintf("%02d", $ltevt[0]));
- }
- sub Talk2Fhem_exec($$$) {
- my %assires;
- my %lastcmd;
- sub Talk2Fhem_get_time_by_phrase($$$$$%);
- sub Talk2Fhem_addevt($$$$;$$);
- sub Talk2Fhem_err($$$;$);
- sub Talk2Fhem_filter($$);
- sub Talk2Fhem_escapeumlauts($;$);
- sub Talk2Fhem_test($$);
- my ($txt, $me, $myname) = @_;
- $me->{helper}{LOG}="";
- #my $kl = $me->{helper}{T2F_keywordlist};
- #my $ml = $me->{helper}{T2F_modwordlist};
- (Talk2Fhem_err($myname, "No Text given!",\%assires,1) && return(%assires)) unless $txt;
- my $lang = Talk2Fhem_language($myname);
- my %Talk2Fhem = %{$Talk2Fhem_globals{$lang}};
- T2FL($myname, 5, "Talk2Fhem Version: ".$Talk2Fhem_globals{version});
- T2FL($myname, 3, "Decoding Text: ".$txt);
- my $t2ffilter = AttrVal($myname,"T2F_filter",0);
- T2FL($me, 5, "Using User Filter: ".$t2ffilter) if $t2ffilter;
- my $lastevt;
- my $lastif;
- my $lastifmatch;
- my $origin = AttrVal($myname, "T2F_origin", "");
- $txt =~ s/$origin//;
- $origin = $&;
- $txt = Talk2Fhem_normalize(Talk2Fhem_realtrim($txt));
- readingsSingleUpdate($me, "origin", $origin, 1);
- #:START
- #Zeiten könnten auch ein und enthalten deswegen nicht wenn auf und eine Zahl folgt
- my @cmds = split(/ und (?!$Talk2Fhem_globals{DE}{numberre})/, $txt);
- # CHECK if $cmd[0] hit Talk2Fhem_test. Unless dont split. And make a deeper analysis.
- #if ($#cmd)
- # before test remove time and if phrases simple
- # unless (Talk2Fhem_test($me, $cmds[0]))
- # Nun schauen wir mal was vor und nach dem und ist.
- # könnte phrasentreffer auf kompletten satz ausschluss geben
- @cmds = grep { $_ } @cmds;
- # Tiefe UND analyse
- # Präposition und Artikel
- my $art = '(([ai][nm]|beim?|auf|unter|hinter|über|vo[rnm]) )?((de[rmns]|die|das) )?';
- my $uart = '(eine?[smnr]?)';
- my @regtargets;
- for (keys %{$me->{helper}{T2F_andwordlist}}) { push(@regtargets, \@{$me->{helper}{T2F_andwordlist}{$_}}) };
- my $reg = '\b'.${art}.'('.join("|",map { @$_ } @regtargets).')\b';
- Log 1, $reg;
- my @andlockinfo; #my @sets;
- for (@regtargets) {
- my $regtarget = join("|", @$_);
- Log 1, $regtarget;
- # d Satzteil x Teilposition y cmds Position
- my $d=0; my $x=0; my $y=0; my $prepost; my $prepre;
- for (@cmds) {
- # erkenne target
- if (/\s?\b(${art})(${regtarget})\b/i)
- {
- my ($pre,$post,$target) = ($`,$',$&);
- my @targets=($target);
- # weitere targets. Bei Auflistungen ohne und
- while ($post =~ s/(,|\s)+(${art}(${regtarget}))\b//i) {
- push(@targets, $2);
- };
- my $xx = -1;
- # Fülle andlockinfo hash
- for (@targets) {
- my $s = $andlockinfo[$d]{count}++;
- my $ref = \%{$andlockinfo[$d]{part}[$x+(++$xx)]};
- # füge targets hinzu mit korregierten leerzeichen
- $$ref{target} .= ((($$ref{target}||"")!~/\s$/ and $_!~/^\s/)?" ":"").$_;
- $$ref{no} = $y;
- $$ref{pre} = $pre || undef;
- if ($post) {
- #entferne Targets anderer Kategorien
- $post =~ s/\s?$reg\s?/ /gi;
- $post = undef if $post =~ /^\s*$/;
- $$ref{post} = $post || undef;
- }
- }
- $x += $xx if $xx ne -1;
- $andlockinfo[$d]{pre} = ($pre || $prepre) if $pre || $prepre;# and !$andlockinfo[$d]{pre};
- $andlockinfo[$d]{post} = ($post || $prepost) if $post || $prepost;# and !$andlockinfo[$d]{post};
- $prepost=undef; $prepre=undef;
- # wenn es ein post existiert fange neuen Satzteil an und speichere pre und post
- if ($andlockinfo[$d]{count} > 1 and $post) {
- $prepost = $andlockinfo[$d]{post};
- $prepre = $andlockinfo[$d]{pre};
- $d++;
- $x=-1;
- }
- }
- else {
- $d++; $x=-1;
- }
- $x++; $y++;
- }
- }
- #print Dumper @andlockinfo;
- #Bilde komplette Sätze und füge nicht berücksichtigte sätze an richtiger position ein
- my @ncmds; my $o=0;
- for (my $i=0;$i<=$#andlockinfo;$i++) {
- my $a = $andlockinfo[$i];
- if (ref $a) {
- for ($o..($$a{part}[0]{no}-1)) {
- push(@ncmds, $cmds[$_]);
- }
- for my $p (@{$$a{part}}) {
- push(@ncmds, ($$p{pre}//$$a{pre}||"").$$p{target}.($$p{post}//$$a{post}||""));
- $o = $$p{no}+1;
- }
- }
- }
- push(@ncmds, splice(@cmds,$o));
- @cmds = @ncmds ? @ncmds : @cmds;
- T2FL($myname, 4, "After correction:\n".(join("\n", @cmds)));
- foreach (@cmds) {
- next unless $_;
- my $cmd = $_;
- my $specials;
- $$specials{origin} = $origin;
-
-
- T2FL($myname, 4, "Command part: '$cmd'");
- my $rawcmd = $cmd;
- my $time = time;
- ### wieder und dann/danach am Anfang legen die zeit auf das vorherige event
- if ($lastevt and ($cmd =~ /\bwieder |^(dann|danach).*/i)) {
- T2FL($myname, 5, "Word again found. Reusing timeevent. ".localtime($lastevt));
- $time = $lastevt;
- }
- my $evtime = Talk2Fhem_get_time_by_phrase($myname, $time, $time, \$cmd, \$specials, %{$Talk2Fhem{datephrase}});
- $evtime = Talk2Fhem_get_time_by_phrase($myname, $evtime, $time, \$cmd, \$specials, %{$Talk2Fhem{timephrase}});
- #T2FL($myname, 4, "Extracted Timephrase. '$$specials{timephrase}'") if $$specials{timephrase};
- T2FL($myname, 4, "Extracted Timephrase. '$$specials{timephrase}'") if $$specials{timephrase};
- T2FL($myname, 5, "Commandpart after datedecoding. '$cmd'") if $cmd ne $rawcmd;
- unless($evtime) {
- Talk2Fhem_err($myname, "Error while time calculating: $rawcmd",\%assires,1);
- next;
- }
- $cmd = Talk2Fhem_filter($myname, $cmd);
- if ($time < $evtime) {
- T2FL($myname, 4, "Eventtime found: ".localtime($evtime));
- $lastevt=$evtime;
- } elsif ($time-10 > $evtime) {
- T2FL($myname, 3, "Time is in past: $time $evtime");
- $lastevt=0;
- } elsif ($lastevt) {$lastevt++}
- foreach my $phr (@{$me->{helper}{if}}) {
- my $sc = Talk2Fhem_addevt($myname, $phr, $lastevt, $cmd, \%assires, $specials);
- }
- push(@{$$specials{ifs}} , @{$lastif}) if ($lastif);
- $lastif = $$specials{ifs};
- $lastifmatch .= ($lastifmatch ? " und " : " ").$$specials{match};
- $$specials{ifmatch} = $lastifmatch;
- $cmd = Talk2Fhem_normalize(Talk2Fhem_realtrim($cmd));
- # Maximal 2 Wörter vor dem wieder, ansonsten wird von einem neuen Kommando ausgegangen.
- # dann wird nach der letzten Zahl, wort länger als 3 buchstaben oder wahr falsch wörter gesucht.
- #if ($cmd =~ /^.?(\S+\s){0,2}wieder.* (\S+)$/i) {
- if (%lastcmd and
- ( $cmd =~ /wieder\b.*($Talk2Fhem{pass}{float})/i ||
- $cmd =~ /wieder\b.*($Talk2Fhem{pass}{integer})/i ||
- $cmd =~ /wieder\b.*($Talk2Fhem{pass}{word})/i ||
- $cmd =~ /wieder\b.*($Talk2Fhem{pass}{true})/i ||
- $cmd =~ /wieder\b.*($Talk2Fhem{pass}{false})/i ||
- $cmd =~ /wieder\b.*($Talk2Fhem{numberre})/i)) {
- $$specials{dir} = $1;
- # hier erfolgt ein hitcheck, damit erkannt wird ob das kommando ohne wieder ein eigenständiger befehl ist.
- # frage ist ob zusätzlich über specials eine rückgabe gegeben werden soll ob die konfig "wieder" fähig ist. z.b. überhaupt ein $n vorhanden ist.
- # ist der 2 wörter check noch notwendig?
- unless (Talk2Fhem_test($me, $cmd =~ s/\s?wieder\s/ /r)) {
- #Vorhiges Kommando mit letztem wort als "direction"
- # Log 1, Dumper Talk2Fhem_test($me, $_ =~ s/\s?wieder\s/ /r);
- T2FL($myname, 4, "Word again with direction ($$specials{dir}) found. Using last command. ${$lastcmd{phr}}{key}");
- Talk2Fhem_addevt($myname, $lastcmd{phr}, $lastevt, $lastcmd{cmd}, \%assires, $specials);
- next;
- } else {
- T2FL($myname, 3, "Again word ignored because Command matches own Phrase!");
- $$specials{dir} = undef;
- }
- }
- #wieder wird nicht mehr benötigt
- $cmd =~ s/\bwieder\b|^(dann|danach) / /g;
- $cmd = Talk2Fhem_normalize(Talk2Fhem_realtrim(Talk2Fhem_filter($myname, $cmd)));
- T2FL($myname, 4, "Command left: '$cmd'") if $rawcmd ne $cmd;
-
- my $sc;
-
- #foreach my $phr (keys(%{$Talk2Fhem_phrase{$myname}})) {
- foreach my $phr (@{$me->{helper}{phrase}}) {
- #Teste Phrasenregex
- $lastcmd{phr} = $phr;
- $lastcmd{cmd} = $cmd;
- $sc = Talk2Fhem_addevt($myname, $phr, $lastevt, $cmd, \%assires, $specials);
- # undef nicht gefunden, 0 fehler beim umwandeln, 1 erfolgreich
- last if defined($sc);
- }
- unless ($sc) {
- unless(defined($sc)) {
- # undef
- Talk2Fhem_err($myname, "No match: '$rawcmd'",\%assires,1);
- } else {
- # 0
- Talk2Fhem_err($myname, "Error on Command: '$rawcmd'",\%assires,1) unless $assires{err};
- last;
- }
- }
- # eventuell ganz abbrechen bei fehler, jetzt wird noch das nächste und ausgewertet
- next;
-
- }
- return(%assires);
- sub Talk2Fhem_filter($$) {
- my ($name, $cmd) = @_;
- my $filter = AttrVal($name,"T2F_filter",$Talk2Fhem_globals{Talk2Fhem_language($name)}{erase});
- unless (ref($filter) eq "ARRAY") {
- $filter = Talk2Fhem_parseArray($filter);
- };
-
- for (@$filter) {
- $cmd =~ s/$_/ /gi;
- }
- $cmd =~ s/\s{2,}/ /g;
- return(Talk2Fhem_realtrim($cmd));
- }
- sub Talk2Fhem_get_time_by_phrase($$$$$%) {
- my ($myname, $evt, $now, $cmd, $spec, %tp) = @_;
- #T2FL($myname, 5, "get_time_by_phrase. Using eventtime: ".localtime($evt)." now: ".localtime($now)." command: ".$$cmd);
- return(0) unless ($evt);
- my @lt = localtime($evt);
- my @now = localtime($now);
- my $disu = AttrVal($myname, "T2F_disableumlautescaping", 0);
- foreach my $key (keys(%tp)) {
- my $esckey = Talk2Fhem_escapeumlauts($key, $disu);
- my @opt = ($$cmd =~ /\b$esckey\b/i);
- while ($$cmd =~ s/\b$esckey\b/ /i) {
- $$$spec{timephrase} .= $&." ";
- my %tf = %{$tp{$key}};
- T2FL($myname, 4, "Timephrase found: =~ s/\\b$key\\b/");
- foreach my $datemod (keys(%tf)) {
- next if $datemod eq "fc";
- # Suche Ersetzungsvariablen
- my $dmstore = $tf{$datemod};
- while ($tf{$datemod} =~ /\$(\d+)/) {
- my $d=$1;
- my $v = $opt[($d-1)];
- if ($v !~ /^\d+$/) {
- #Log 1, "KEINE Zahl ".$v;
- foreach ( keys %{$Talk2Fhem_globals{DE}{numbers}} ) {
- my $tmp = Talk2Fhem_escapeumlauts($_, $disu);
- last if ($v =~ s/$tmp/$Talk2Fhem_globals{DE}{numbers}{$_}/i);
- }
- }
- $tf{$datemod} =~ s/\$\d+/$v/;
- }
- $tf{$datemod} = eval($tf{$datemod});
- T2FL($myname, 5, "TIMEPHRASEDATA mod: '$datemod' raw: '$dmstore' result: '$tf{$datemod}' opt: '@opt'");
- if ($datemod eq "days") {
- $evt = POSIX::mktime(0,0,12,($lt[3]+$tf{days}),$lt[4],$lt[5]) || 0;
- } elsif ($datemod eq "wday") {
- $evt = POSIX::mktime(0,0,12,($lt[3]-$lt[6]+$tf{wday}+(( $tf{wday} <= $lt[6] )?7:0)),$lt[4],$lt[5]) || 0;
- } elsif ($datemod eq "year") {
- $evt = POSIX::mktime(0,0,12,$lt[3],$lt[4],($lt[5]+$tf{year})) || 0;
- } elsif ($datemod eq "month") {
- $evt = POSIX::mktime(0,0,12,$lt[3],($lt[4]+$tf{month}),$lt[5]) || 0;
- } elsif ($datemod eq "sec") {
- $evt = POSIX::mktime(($now[0]+$tf{sec}),$now[1],$now[2],$lt[3],$lt[4],$lt[5]) || 0;
- } elsif ($datemod eq "min") {
- $evt = POSIX::mktime($now[0],($now[1]+$tf{min}),$now[2],$lt[3],$lt[4],$lt[5]) || 0;
- } elsif ($datemod eq "hour") {
- $evt = POSIX::mktime($now[0],$now[1],($now[2]+$tf{hour}),$lt[3],$lt[4],$lt[5]) || 0;
- } elsif ($datemod eq "time") {
- my @t = map { s/\s//gr } split(":", $tf{time});
- $evt = POSIX::mktime($t[2] || 0,$t[1] || 0,$t[0],$lt[3],$lt[4],$lt[5]) || 0;
- } elsif ($datemod eq "date") {
- my @t = split(/\.|\s/, $tf{date});
- if ($t[1]) {$t[1]--} else {$t[1] = $now[4]+1}
- if ($t[2]) {if (length($t[2]) eq 2) { $t[2] = "20".$t[2] }; $t[2]=$t[2]-1900} else {$t[2] = $now[5]}
- $evt = POSIX::mktime(0,0,12,$t[0], $t[1], $t[2]) || 0;
- } elsif ($datemod eq "unix") {
- $evt = localtime($tf{unix});
- }
- @now = localtime($evt);
- }
- @lt = localtime($evt);
- }
-
- if ($tp{$key}{fc}) {
- if (ref $tp{$key}{fc} eq "CODE") {
- my $lock = $evt;
- $evt = &{$tp{$key}{fc}}($evt);
- T2FL($myname, 4, "Time modified by function. ".$evt) if $lock != $evt;
- }
- }
- }
- return($evt);
- }
- sub Talk2Fhem_test($$) {
- my ($hash, $cmd) = @_;
- foreach my $phr (@{$hash->{helper}{phrase}}) {
- my $r = Talk2Fhem_addevt($hash->{NAME}, $phr, undef, $cmd);
- return $r if $r;
- }
- }
- sub Talk2Fhem_addevt($$$$;$$) {
- #print Dumper @_;
- my ($myname, $phr, $lastevt, $cmd, $res, $spec) = @_;
- my $success;
- my $rawcmd = $cmd;
- my $cmdref = \$_[3];
- my $disu =AttrVal($myname, "T2F_disableumlautescaping", 0);
- my %keylist = %{$defs{$myname}{helper}{T2F_keywordlist}} if $defs{$myname}{helper}{T2F_keywordlist};
- my %modlist = %{$defs{$myname}{helper}{T2F_modwordlist}} if $defs{$myname}{helper}{T2F_modwordlist};
- #T2FL($me, 5, "Using lists:\n".Dumper(%keylist, %modlist));
- # my @phrs = map { Talk2Fhem_realtrim($_) } split(/[\t\s]*\&\&[\t\s]*/, $$phr{key});
- my @hitnokeylist = @{$$phr{hitnokeylist}};
- my @fphrs = @{$$phr{regexps}};
- my $pmatch;
- my $punmatch = $cmd;
- my @dir = ($$spec{origin});
- T2FL($myname, 5, "$myname Evaluate search:\n$cmd =~ /$$phr{key}/i") if ref $res;
- for my $fphr (@fphrs) {
- # if (my @d = ($cmd =~ qr/$fphr/i))
- if ($fphr =~ s/^\?//){
- my @d = ($cmd =~ /$fphr/i);
- my $m = $&;
- #Log 1, "A: ".$fphr;
- #Log 1, "A: ".Dumper $m;
- #Log 1, "B: ".Dumper @d;
- my $b = () = $fphr =~ m/(?<!\\)\((?!\?)/g;
- #Log 1, "C: $#d".Dumper $b;
- # Wenn die klammer kein erfolg hat wird auch @d nicht gefüllt und muß manuell gefüllt werden
- if ($#d == -1) {
- for (1..$b) {
- push(@d, undef);
- # push(@d, "");
- }
- }
- push(@dir, @d);
-
- next if $m eq "?";
- $pmatch .= $m;
- $punmatch =~ s/$m//gi;
- #$cmd =~ s/$m//gi;
- } elsif ($fphr =~ /^\!/) {
- return if (eval { $cmd =~ /$'/i });
- } elsif (my @d = ($cmd =~ /$fphr/i ) ){
- my $m = $&;
- $pmatch .= $m;
- $punmatch =~ s/$m//gi;
- #$cmd =~ s/$m//gi;
- # Klammerinhalt speichern wenn Klammer vorhanden
- push(@dir, @d) if $fphr =~ /(?<!\\)\((?!\?)/;
- # push(@dir, @d) if $fphr =~ /\((?!\?)/;
-
- } else {
- #T2FL($myname, 5, "$myname No hit with:\n$cmd =~ /$fphr/i");
- return;
- }
- }
- $$spec{match} = $pmatch;
- $$spec{unmatch} = $punmatch;
- return(1) unless ref $res;
- T2FL($myname, 5, "Command after Phrasecheck: ".$cmd) if $cmd ne $rawcmd;
- T2FL($myname, 5, "Keylists: ".Dumper @hitnokeylist);
- T2FL($myname, 5, "Filled lists: ".Dumper @fphrs);
- T2FL($myname, 5, "Words: ".Dumper @dir);
- #$pmatch=Talk2Fhem_realtrim($pmatch);
- $punmatch=Talk2Fhem_realtrim($punmatch);
- T2FL($myname, 5, "Match: ".$pmatch);
- T2FL($myname, 5, "Unmatch: ".$punmatch);
- #$success;
- T2FL($myname, 4, "Hit with phrase: qr/$$phr{key}/i");
- my %react;
- %react=%{$$phr{val}};
- ####### TODO:
- ####### $[1..n,n,...] für multiple hit auswahl !!! Was ist das trennzeichen in der ausgabe?
-
- my %exec;
- my @types = ("if", "cmd","answer");
- my $mainbracket;
- foreach my $type (@types) {
- my $raw = $react{$type};
- next unless $raw;
- my $mainbracket = (sort { $b <=> $a } ($raw =~ /\$(\d+)/g))[0] unless ($mainbracket);
- my $do = $raw;
- my $dirbracket = $react{offset};
- T2FL($myname, 5, "Handle reaction $type: $raw");
- if ($raw) {
- # Suche Ersetzungsvariablen
-
- $do =~ s/\!\$\&/$punmatch/g;
- $do =~ s/\$\&/$pmatch/g;
- $do =~ s/\$DATE/$$spec{timephrase}/g;
- my $tagain = ($$spec{dir} ? "wieder" : "");
- $do =~ s/\$AGAIN/$tagain/g;
- $do =~ s/\$TIME/$lastevt/g;
- $do =~ s/\$NAME/$myname/g;
- # $do =~ s/\$ORIGIN/$$spec{origin}/g;
- $do =~ s/\$IF/$$spec{ifmatch}/g;
-
- while ($do =~ /\$(\d+)\@/) {
- my $no = $1;
- my @keywords;
- # wenn kein @array in klammer clipno
- unless ($hitnokeylist[$no]) {
- T2FL($myname, 5, "Clipnumber $no is no array! Try to extract by seperator '|'");
- my @cs = map { my @t = split('\|', $_ =~ s/^\(|\)$//gr); \@t } $$phr{key} =~ /(?<!\\)\((?!\?).*?\)/g;
- @keywords = @{$cs[($no-1)]};
- #wenn keine Liste in Klammer ist
- if ($#keywords == -1) {
- Talk2Fhem_err($myname, T2FL($myname, 1, "Clipnumber $no includes no array in '$$phr{key}!"),$res,1);
- return(0);
- }
- } elsif ($hitnokeylist[$no]) {
- @keywords = map { Talk2Fhem_escapeumlauts($_, $disu) } @{$keylist{$hitnokeylist[$no]}};
- }
- my $i;
- for($i=0;$i<=$#keywords;$i++){
- last if $dir[$no] =~ /^$keywords[$i]$/i;
- }
- my $k = ($$spec{dir} and ($no) == $mainbracket) ? $$spec{dir} : $keywords[$i];
- T2FL($myname, 5, "Simple bracket selection (No. $no) with Keyword $i: '$k'");
- $do =~ s/\$$no\@(?!(\[|\{|\(|\d))/$k/;
- }
- # Einfache Variablenersetzung ohne Array oder Hash
- while ($do =~ /\$(\d+)(?!(\[|\{|\(|\d))/) {
- my $r = ($$spec{dir} and ($1) == $mainbracket) ? $$spec{dir} : $dir[$1];
- T2FL($myname, 5, "Simple bracket selection (No. $1): '$r'") if $r;
- $do =~ s/\$$1(?!(\[|\{|\(|\d))/${r}/;
- }
- T2FL($myname, 4, "Replaced bracket: $raw -> $do") if $raw ne $do;
- # while ($do =~ s/(.*)\$(\d+)(\[|\{|\()(.*?)(?3)/$1###/) {
- # while ($do =~ s/(.*)\$(\d+)(\[|\{|\()(.*?)(\]|\}|\))/$1###/) {
- while ($do =~ /(.*)\$(\d+)(?=\[|\{|\()/) {
- my $pre = $1;
- my $clipno = $2;
- my $post = $';
- my ($found, $rest) = extract_bracketed( $post, '{}[]()' );
- unless ($found) {
- Talk2Fhem_err($myname, T2FL($myname, 1, "'$raw': Fehler in Kommandoteilmodifikator Nr. '\$$clipno' nach: '$pre'"),$res,1);
- return(0);
- }
- #Klammer aus Value in Hash überführen
- $do = $pre."###".$rest;
- $found =~ /(.)(.*)./;
- my $utype = $1;
- my $uhash = $2;
-
-
- T2FL($myname, 4, "Advanced bracket replacement. \$$clipno$uhash = $do");
- if ($uhash =~ /@(\w+)/) {
- if ($modlist{$1}) {
- $uhash = $`.'"'.Talk2Fhem_escapeumlauts(join('","', @{$modlist{$1}}), $disu).'"'.$' ;
- #ersetze ,, durch "","",
- # zwei mal weil immer eins zu weit geschoben wird
- #### ist noch notwendig???
- $uhash =~ s/([\[,])([,\]])/$1""$2/g;
- $uhash =~ s/([\[,])([,\]])/$1""$2/g;
- T2FL($myname, 5, "Adding modlist: ".$uhash);
- } else {
- Talk2Fhem_err($myname, T2FL($myname, 1, "Unbekannte modwordlist in '$$phr{key}' \@$1"),$res,1);
- return(0);
- }
- }
-
- my $hash;
- if ($utype eq "[") {
- $hash = Talk2Fhem_parseArray($uhash)
- } elsif ($utype eq "{") {
- #$hash = eval($uhash)
- my $harr = Talk2Fhem_parseArray($uhash); my $i=0;
- for (@$harr) {
- my $h = Talk2Fhem_parseArray($_, "=>");
- $$hash{$$h[0]} = {val=>$$h[1],order=>$i++};
-
- }
- } elsif ($utype eq "(") {
- ##### klappt nicht weil in while regex nicht bis zur schließenden klammer getriggert wird wenn vorher ein } oder ] kommt
- #$hash = eval($uhash);
- T2FL($myname, 1, '$n() has no function at this moment. Possible worng Syntax: '.$$phr{key});
- next;
-
- } else {
- #sollte eigentlich nie eintreffen weil auf die zeichen explizit gesucht wird
- T2FL($myname, 1, "Unkown modwordtype ($utype) in '$$phr{key}'");
- next;
- }
- #aktuelles Wort im Key auswählen
- if (($clipno-1) > $#dir) {
- T2FL($myname, 1, "Not enough clips in phrase '$$phr{key} =~ $raw'");
- next;
- }
- my $d = ($$spec{dir} and ($clipno) == $mainbracket) ? $$spec{dir} : $dir[$clipno];
-
- T2FL($myname, 4, "Keyword (".($clipno)."): '$d'");
-
- # Wort übersetzen
- if (ref($hash) eq "HASH") {
- T2FL($myname, 5, "HASH evaluation:\n".Dumper($hash));
- #my $passed=0;
- foreach my $h (sort {$$hash{$a}{order} <=> $$hash{$b}{order} } keys(%$hash)) {
- #sollte eigentlich in den syntaxcheck
- unless (defined $$hash{$h}{val}) {
- T2FL($myname, 1, "Empty replacementstring! $h");
- #return(0);
- next;
- };
- next if ($h eq "else");
- unless ($h =~ /^\/.*\/$/ or defined ${$Talk2Fhem{pass}}{$h}) {
- T2FL($myname, 1, "Replacementtype unkown! $h");
- #return(0);
- next;
- };
-
- #$passed=1;
- next if ($h eq "empty");
- next unless $d;
- my $re;
- my $fc;
- if ($h =~ /^\/(.*)\/$/) {
- $re = $1;
- } else {
- $re = ${$Talk2Fhem{pass}}{$h};
- if (ref($re) eq "HASH") {
- $fc=$$re{fc};
- $re=$$re{re};
- }
- }
-
- $re = Talk2Fhem_escapeumlauts($re, $disu);
-
- if ($d =~ qr/$re/i) {
- my $rp = $$hash{$h}{val};
- if (ref $fc eq "CODE") {
- T2FL($myname,5,"Functionmod '$fc' $rp");
- my @res = $d =~ qr/$re/i;
- $rp = &$fc(@res);
- } elsif ($fc) {
- T2FL($myname,5,"Functionmod '$$fc' $rp");
- my $ev = eval($fc);
- $rp =~ s/$re/$ev/gi;
- }
- T2FL($myname, 5, "Word found ($h): '$d' replace with '$rp'");
- $do =~ s/###/$rp/;
- last;
- }
- }
- # empty != undef
- # if (defined($d) and $d =~ qr/${$Talk2Fhem{pass}}{empty}/ and ($$hash{empty}{val} or (! $$hash{empty}{val} and $$hash{else}{val}))) {
- # empty undef
- if (! defined($d) or $d =~ qr/${$Talk2Fhem{pass}}{empty}/) {
- #$d existiert nicht
- my $e = ($$hash{empty}{val} || $$hash{else}{val});
- T2FL($myname, 5, "Empty word replace with '$e'");
- $do =~ s/###/$e/;
- }
-
-
- #########
- if ($do =~ /###/) {
- #Vergleich fehlgeschlagen
- if ($$hash{else}{val}) {
- T2FL($myname, 5, "Unkown word '$d' replace with '$$hash{else}{val}'");
- $do =~ s/###/$$hash{else}{val}/;
- } else {
- T2FL($myname, 1, "HASH Replacement Failed! $do");
- #%$res = undef;
- #return();
- }
- }
- }
-
- if (ref($hash) eq "ARRAY") {
- my $else="";
- my $empty="";
- # keywords else und empty löschen und nächsten wert als parameter nehmen
- @$hash = grep {
- if ("$_" eq "else") { $else = " "; 0 }
- else { if ($else eq " ") { $else = $_; 0 }
- else { 1 } } } @$hash;
- @$hash = grep {
- if ("$_" eq "empty") { $empty = " "; 0 }
- else { if ($empty eq " ") { $empty = $_; 0 }
- else { 1 } } } @$hash;
- T2FL($myname, 5, "ARRAY evaluation: else: $else empty: $empty\narray: @$hash");
- # if (($d =~ qr/${$Talk2Fhem{pass}}{empty}/) and defined($d)) {
- my $intd = $d;
- foreach ( keys %{$Talk2Fhem_globals{Talk2Fhem_language($myname)}{numbers}} ) {
- my $tmp = Talk2Fhem_escapeumlauts($_, $disu);
- if ($d =~ /$tmp/i) {
- $intd = $Talk2Fhem_globals{Talk2Fhem_language($myname)}{numbers}{$_};
- last;
- };
- }
- T2FL($myname, 5, "Numeral word found. '$d' converted to; $intd");
- if (($d =~ qr/${$Talk2Fhem{pass}}{empty}/) or ! defined($d)) {
- T2FL($myname, 5, "Empty word replace with! $empty");
- $do =~ s/###/$empty/;
- } elsif (IsInt($intd)) {
- unless ($$hash[$intd]) {
- my $err = T2FL($myname, 3, "Field #$intd doesn't exist in Array!");
- if ($else eq "") {
- Talk2Fhem_err($myname, $err, $res,1);
- return(0);
- }
-
- } else {
- T2FL($myname, 5, "Integer ($intd) used for array selection! $$hash[$intd]");
- $do =~ s/###/$$hash[$intd]/ if $$hash[$intd];
- }
- } elsif ($d) {
- my @keywords;
- # wenn kein @array in klammer clipno
- unless (defined($hitnokeylist[$clipno])) {
- T2FL($myname, 5, "Clipnumber $clipno is no array! Try to extract by seperator '|'");
- # my @cs = map { my @t = split('\|', $_ =~ s/^\(|\)$//gr); \@t } $$phr{key} =~ /(?<!\\)\((?!\?).*?\)/g;
- # my @cs = map { my @t = split('\|', $_ =~ s/^\(|\)$//gr); \@t } $$phr{key} =~ /(?<! \\ ) \( (?! \? ) (?: (?R) | [^()]+ )+ \) /xg;
- # Klammern extrahieren
- my @cs = ("onlysometext".$$phr{key});
- #unshift(@cs, undef) if $$phr{key} =~ /^\(/;
- for (my $i=0; $i<=$#cs; $i++) {
- my $c = $cs[$i];
- #T2FL($myname, 5, "C: ".Dumper $c);
- if ($c =~ /^\(\?.*\)$/) {
- # Perl Special bracket delete it.
- splice(@cs, $i, 1);
- $c = $cs[$i];
- }
- (my $locked = $c) =~ s/^\((.*)\)$/$1/g;
- my @add = extract_multiple($locked, [sub { extract_bracketed($_[0], '()') }],undef, 1);
- splice(@cs, ($i+1) ,0 , @add);
- last if $i > 10;
- }
-
- #T2FL($myname, 5, "CS: ".Dumper @cs);
-
- # @keywords = @{$cs[($clipno-1)]};
- # Log 1, Dumper @cs;
- # @cs = grep { /^\(/ } @cs;
- # Log 1, Dumper @cs;
- # Log 1, "-----> ".$cs[($clipno-1)];
- (my $clip = $cs[($clipno)]) =~ s/^\(|\)$//g;
- #T2FL($myname, 5, "clip: ".Dumper $clip);
- # push(@keywords, split('\|', $clip) extract_bracketed($clip, '()'));
- my @extract;
- for (extract_multiple($clip, [sub { extract_bracketed($_[0], '()') }])) {
- #T2FL($myname, 5, "EM: ".Dumper $_);
- if ($_ =~ /^\(/) {
- push (@extract, "") if ($#extract eq -1);
- $extract[$#extract] .= $_;
- next;}
- if (s/^\|// or /^[^(]/) {
- if ($_ ne "") {
- push(@extract, split('\|', $_));
- } else {
- push(@extract, "");
- }
- } else {
- push (@extract, "") if ($#extract eq -1);
- $extract[$#extract] .= $_;
- }
- }
- #T2FL($myname, 5, "A: ".Dumper @extract);
- #@keywords = map { /^\(/ ? $_ : split('\|', $_=~s/^\||\|$//gr) } extract_multiple($clip, [sub { extract_bracketed($_[0], '()') }]);
- @keywords = @extract;
- #T2FL($myname, 5, "keywords: ".Dumper @keywords);
- # @keywords = split('\|',);
-
- #Log 1, Dumper @keywords;
- #wenn keine Liste in Klammer ist
- my $err = T2FL($myname, 1, "Clipnumber $clipno includes no array or integer in '$$phr{key}!");
- if ($#keywords == -1 and $else eq "") {
- Talk2Fhem_err($myname, $err,$res,1);
- return(0);
- }
- } else {
- @keywords = @{$keylist{$hitnokeylist[$clipno]}};
- }
- # T2FL($myname, 4, "Searching position of $d in @keywords");
- @keywords = map { Talk2Fhem_escapeumlauts($_, $disu) } @keywords;
- T2FL($myname, 4, "Searching position of '$d' in '@keywords'");
- my $i=0;
- foreach (@keywords) {
- # if ($d =~ /^\Q$_\E$/i) {
- if (eval{$d =~ /^$_$/i}) {
- unless (defined($$hash[$i])) {
- my $err = T2FL($myname, 1, "Not enough elements in modwordlist! Position $i in (@$hash) doesn't exist.");
- if ($else eq "") {
- Talk2Fhem_err($myname, $err, $res,1);
- return(0);
- }
- } else {
- T2FL($myname, 5, "Found '$d' at position $i");
- $do =~ s/###/$$hash[$i]/;
- }
- }
- $i++;
- }
- }
- if ($do =~ /###/) {
- if ($else ne "") {
- T2FL($myname, 5, "Unkown word '$d' replace with '$else'");
- $do =~ s/###/$else/;
- } else {
- T2FL($myname, 1, "ARRAY Replacement Failed! $do");
- }
- }
- }
- }
- if ($do and ($do !~ /###/)) {
- my $result;
- #2016-01-25T02:02:00
- if ($type eq "if") {
- push(@{$$spec{ifs}}, $do);
- #push(@{$exec{$type}}, $do);
- $$cmdref = $punmatch;
- T2FL($myname, 3, "New Command after IF: ".$$cmdref);
- } elsif ($type eq "cmd") {
- my $at;
- # $at=Talk2Fhem_mkattime($myname, ($react{offset}) ? ($lastevt+$react{offset}) : $lastevt) if ($lastevt);
- $$result{cmd} = $do;
- $$result{at} = (($react{offset}) ? ($lastevt+$react{offset}) : $lastevt) if ($lastevt);
- $$result{ifs} = $$spec{ifs} if $$spec{ifs};
- #$$spec{ifs} = undef;
- $success = 1;
-
- } elsif ($type eq "answer") {
- T2FL($myname, 4, "Answer eval: $do");
- my $answ = eval("$do");
- if (defined($answ)) {
- $result = $answ;
- #$exec{$type} = $answ;
- $success = 1;
- } else {
- Talk2Fhem_err($myname, T2FL($myname, 1, "Error in answer eval: ".$do),$res,1);
- return(0);
- }
- } elsif ($type eq "offset") {
- } else {
- T2FL($myname, 1, "Unkown KEY $type in Commandhash");
- }
-
- T2FL($myname, 3, "Result of $type: ".Dumper $result);
- $exec{$type."s"} = $result if ($result);
- #push(@{$$res{$type."s"}}, $result) if ($result);
- } else {
- T2FL($myname, 1, "No hit on advanced bracket selection: ".($do || $raw));
- #%{$res} = undef;
- $success = undef;
- last;
- }
- }
- }
-
-
- #Hier Befehle ausführen.
-
- if ($success) {
- for (keys %exec) {
- push(@{$$res{$_}}, $exec{$_});
- }
- }
- return($success);
-
- }
- sub Talk2Fhem_err($$$;$) {
- my ($myname, $t, $res, $v) = @_;
- $v = 1 unless $v;
- T2FL($myname, $v, $t);
- push(@{${$res}{err}}, $t);
- }
- sub Talk2Fhem_escapeumlauts($;$) {
- my ($cmd, $disable) = @_;
- return($cmd) if $disable;
- (my $res = $cmd) =~ s/[äöüß]/\\S\\S?/gi;
- #Umlaute sind Arschlöcher
- $res =~ s/(\\S\\S\?){2}/\\S\\S?/g;
- return($res);
- }
- }
- sub T2FL($$$) {
- Log3($_[0], $_[1], $_[2]);
- my $h = $_[0];
- $h = ref $h && $h || $defs{$h} || return;
- if ($defs{$h->{NAME}}) {
- $h->{helper}{LOG} .= $_[2]."\n";
- }
- return($_[2]);
- }
- 1;
- # Beginn der Commandref
- =pod
- =item helper
- =item summary A RegExp based language control module
- =item summary_DE Ein auf RegExp basierendes Sprachsteuerung Modul
- =begin html
- <a name="Talk2Fhem"></a>
- <h3>Talk2Fhem</h3>
- <ul>
- The module <i>Talk2Fhem</i> is a connection between natural language and FHEM commands.
- The configuration is carried out conveniently via the FHEM web frontend.<br>
- For a more detailed description and further examples see <a href="http://wiki.fhem.de/wiki/Modul_Talk2Fhem">Talk2Fhem Wiki</a>.
- <br><br>
- <a name="Talk2Fhemdefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> Talk2Fhem</code>
- <br><br>
- Example: <code>define talk Talk2Fhem</code>
- <br><br>
- The actual configuration should first be done on the FHEM side.
- <br><br>
- The individual language phrases are configured line by line. A configuration
- always starts by the regular expression, followed by at least one space or tab
- from an equal sign. <br>
- The command part begins after the equals sign with a space, tab, or newline. <br> <br>
- <code><regexp> = <command></code>
- <br><br>
- <b>Short refernce:</b>
- <br>
- <code><RegExpPart> [&& [?!]<RegExpPart_n>] = [ <FHEM command> | { <Perl code> } | (<option> => '<wert>' , ... ) ]</code>
- <br><br>
- Example: <code>helo world = {Log 1, Helo World}</code>
- <br><br>
- Everything after a hashtag '#' is ignored until the end of the line.
- <br><br>
- <regexp>
- <ul>Regular expression describing the text at which the command should be executed</ul>
- <br><br>
- <command>
- <ul>
- The executive part. The following formats are allowed:
- <li>FHEM Command</li>
- <li>{Perlcode}</li>
- <li>(<option> => '<value>' , ... )</li>
- <ul>
- <br><i><option></i><br>
- <li><b>cmd</b><br>FHEM command as above</li>
- <li><b>offset</b><br>Integer value in seconds that is added at the time</li>
- <li><b>answer</b><br>Perl code whose return is written in the Reading answer</li>
- </ul>
- </ul>
- <br>
- Bracket transfer:
- <ul>
- Brackets set in the regular expression can be transferred to the command section with $1, $2, [...], $n and
- be modified. The following modification options are available here.
- <li>$n <br>Get the word straight without change.</li>
- <li>$n{<type> => <value>}<br>
- Types are:<br>
- true, false, integer, empty, else<br>
- true, false, integer, float, numeral, /<regexp>/, word, empty, else<br>
- <b>true</b> corresponds to: ja|1|true|wahr|ein|eins.*|auf.*|..?ffnen|an.*|rauf.*|hoch.*|laut.*|hell.*<br>
- <b>false</b> corresponds to: nein|0|false|falsch|aus.*|null|zu.*|schlie..?en|runter.*|ab.*|leise.*|dunk.*<br>
- <b>integer</b> Word is an integer<br>
- <b>float</b> Word is a float number<br>
- <b>numeral</b> Word is numeral or an integer<br>
- <b>/<regexp>/</b> Word is matching <regexp><br>
- <b>word</b> Word contains 4 or more letters<br>
- <b>empty</b> Word Contains an empty string<br>
- <b>else</b> If none of the cases apply<br>
- If a <type> is identified for $n the <value> is beeing used.
- Example: <code>light (\S*) = set light $1{true => on,false => off}</code>
- </li>
- <li>$n[<list>]<br>
- Comma separated list: [value1,value2,...,[else,value], [empty,value]] or [@modwordlist]<br>
- If $n is a number, the word at that position in <list> is selected.<br><br>
- If $n is a text, it searches for a list in its parenthesis in the <regexp> part. (a|b|c) or (@keywordlist)
- In this list, $n is searched for and successively positioned in <list> chosen for $n.
- <br>Example: <code>light .* (kitchen|corridor|bad) (\S*) on = set $1[dev_a,dev_b,dev_c] $2{true => on,false => off}</code>
- </li>
- <li>$n@<br>The word is adopted as it is written in the list in the <regexp>-part.</li>
- </ul>
- <br>
- Environment variables::
- <ul>
- There are a number of variables that can be accessed in the <command>-part.
- <li><b>$&</b> Contains all found words </li>
- <li><b>!$&</b> Contains the rest that was not included by RegExp</li>
- <li><b>$DATE</b> Contains the time and date text of the voice </li>
- <li><b>$AGAIN</b> Contains the word again if it is a command again</li>
- <li><b>$TIME</b> Contains the found time.</li>
- <li><b>$NAME</b> Contains the devicename.</li>
- <li><b>$IF</b> Contains the text of the detected T2F_if configuration.</li>
- <li><b>$0</b> Contains the text of the detected T2F_origin regexp.</li>
- </ul>
- </ul>
- <br>
-
- <a name="Talk2Fhemset"></a>
- <b>Set</b><br>
- <ul>
- <code>set <name> [!]<text></code>
- <br><br>
- The text is sent to the module via the <i>set</i> command.
- See <a href="http://fhem.de/commandref.html#set">commandref#set</a> for more help.
- <li>cleartimers</li> Removes the pending time-related commands
- <li>cleartriggers</li> Removes the pending event-related commands
- </ul>
- <br>
- <a name="Talk2Fhemget"></a>
- <b>Get</b><br>
- <code>get <name> <option></code>
- <br><br>
- Information can be read from the module via <i>get</i>.
- See <a href="http://fhem.de/commandref.html#get">commandref#get</a> for more information on "get". <br><br>
- <option>
- <ul>
- <li><i>@keywordlist</i> <i>@modwordlist</i><br>
- Compare the two lists word by word.</li>
- <li><i>keylistno</i><br>
- A list of the configured "keyword" lists. For easier positioning of "modword" lists </li>
- <li><i>log</i><br>
- Shows the log entries of the last command </li>
- <li><i>modificationtypes</i><br>
- Shows the regexp of the modificationtypes. </li>
- <li><i>standardfilter</i><br>
- Load the standartfilter and print it in the Attribute T2F_filter if its empty </li>
- <li><i>version</i><br>
- The module version</li>
- </ul>
- <br>
- <a name="Talk2Fhemreadings"></a>
- <b>Readings</b>
- <ul>
- <li><i>set</i><br>
- Contains the last text sent via "set".
- </li>
- <li><i>cmds</i><br>
- Contains the last executed command. Is also set with disable = 1.
- </li>
- <li><i>answer</i><br>
- Contains the response text of the last command.
- </li>
- <li><i>err</i><br>
- Contains the last error message. <br>
- "No match" match with no RegExp. <br>
- "Error on Command" see FHEM log.
- </li>
- <li><i>response</i><br>
- Got the response of the fhem Command.
- </li>
- <li><i>origin</i><br>
- Contains the found string of the RegExp defined in the attribute T2F_origin.
- </li>
- <li><i>status</i><br>
- Got the status of the request.
- response, disabled, err, answers, done
- </li>
- <li><i>ifs</i><br>
- Contains the conditions at which the command will be executed.
- </li>
- <li><i>notifies</i><br>
- Contains a list of the devices that are relevant for the currently waiting conditional commands. There is an internal notify on these devices.
- </li>
- </ul>
- <br>
-
- <a name="Talk2Fhemattr"></a>
- <b>Attribute</b>
- <ul>
- <code>attr <name> <attribute> <value></code>
- <br><br>
- See <a href="http://fhem.de/commandref.html#attr">commandref#attr</a> for more information about the attributes.
- <br><br>
- Attributes:
- <ul>
- <li><i>T2F_keywordlist</i> <name> = <list><br>
- A comma-separated list of keywords such as: rooms, names, colors, etc ... <br>
- In other words, things named with a natural name. </li>
- <li><i>T2F_modwordlist</i> <name> = <list><br>
- A comma seperated list of substitution words used for the keywords.
- For example: device names in FHEM <br> </li>
- <li><i>T2F_if</i><br>
- A collection of event-driven configurations. The syntax is that of the definition. Command part is an IF condition. <br>
- z.B.: (when|if) .*?door = [door] eq "open"
- </li>
- <li><i>T2F_filter</i><br>
- Comma-separated list of RegExp generally removed. <br>
- Standard: \bplease\b,\balso\b
- </li>
- <li><i>T2F_origin</i><br>
- A RegExp which is generally removed and whose output can be accessed via $0. <br>
- Can be used for user mapping.</li>
- <li><i>T2F_language</i>DE|EN<br>
- The used language can be set via the global attribute "language". Or overwritten with this attribute.
- </li>
- <li><i>T2F_disableumlautescaping</i> <0|1><br>
- Disable convertimg umlauts to "\S\S?"</li>
- <li><i>disable</i> <0|1><br>
- Can be used for test purposes. If the attribute is set to 1, the FHEM command is not executed
- but written in reading cmds.
- </li>
- </ul>
- </ul>
- </ul>
- =end html
- =begin html_DE
- <a name="Talk2Fhem"></a>
- <h3>Talk2Fhem</h3>
- <ul>
- Das Modul <i>Talk2Fhem</i> stellt eine Verbindung zwischen natürlicher Sprache und FHEM Befehlen her.
- Die Konfiguration erfolgt dabei komfortabel über das FHEM Webfrontend.<br>
- Für eine genauere Beschreibung und weiterführende Beispiele siehe <a href="http://wiki.fhem.de/wiki/Modul_Talk2Fhem">Talk2Fhem Wiki</a>.
- <br><br>
- <a name="Talk2Fhemdefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> Talk2Fhem</code>
- <br><br>
- Beispiel: <code>define talk Talk2Fhem</code>
- <br><br>
- Die eigentliche Konfigration sollte erst auf der FHEM Seite erfolgen.
- <br><br>
- Die einzelnen Sprachphrasen werden Zeile für Zeile konfiguriert. Hierbei fängt eine Konfiguration
- immer mit dem Regulärem Ausdruck an, gefolgt von mindestens einem Leerzeichen oder Tabulator gefolgt
- von einem Gleichheitszeichen.<br>
- Der Kommandoteil fängt nach dem Gleichheitszeichen mit einem Leerzeichen, Tabulator oder Zeilenumbruch an.<br><br>
- <code><regexp> = <command></code>
- <br><br>
- <b>Kurzreferenz:</b>
- <br>
- <code><RegExpPart> [&& [?!]<RegExpPart_n>] = [ <FHEM command> | { <Perl code> } | (<option> => '<wert>' , ... ) ]</code>
- <br><br>
- Beispiel: <code>hallo welt = {Log 1, Hallo Welt}</code>
- <br><br>
- Alles nach einem Hashtag '#' wird bis zum Zeilenende ignoriert.
- <br><br>
- <regexp>
- <ul>Regulärer Ausdruck der den Text beschreibt, bei dem das Kommando ausgeführt werden soll</ul>
- <br><br>
- <command>
- <ul>
- Der ausführende Teil. Folgende Formate sind Zulässig:
- <li>FHEM Kommando</li>
- <li>{Perlcode}</li>
- <li>(<option> => '<wert>' , ... )</li>
- <ul>
- <br><i><option></i><br>
- <li><b>cmd</b><br>FHEM Kommando wie oben</li>
- <li><b>offset</b><br>Ganzzahliger Wert in Sekunden der auf den Zeitpunkt addiert wird</li>
- <li><b>answer</b><br>Perl Code dessen Rückgabe in das Reading answer geschrieben wird</li>
- </ul>
- </ul>
- <br>
- Klammerüberführung:
- <ul>
- Im Regulärem Ausdruck gesetzte Klammern können in den Kommandoteil mit $1, $2, [...], $n überführt und
- modifiziert werden. Folgende Modifizierungsmöglichkeiten stehen hierbei zur Verfügung.
- <li>$n<br>Ohne Änderung direkt das Wort überführen.</li>
- <li>$n{<typ> => <wert>}<br>
- Die Typen sind:<br>
- true, false, integer, float, numeral, /<regexp>/, word, empty, else<br>
- <b>true</b> entspricht: ja|1|true|wahr|ein|eins.*|auf.*|..?ffnen|an.*|rauf.*|hoch.*|laut.*|hell.*<br>
- <b>false</b> entspricht: nein|0|false|falsch|aus.*|null|zu.*|schlie..?en|runter.*|ab.*|leise.*|dunk.*<br>
- <b>integer</b> Wort enthält eine Zahl
- <b>float</b> Wort enthält eine Gleitkommazahl
- <b>numeral</b> Word ist ein Zahlenwort oder Zahl <br>
- <b>/<regexp>/</b> Wort entspricht der <regexp>
- <b>word</b> Wort enthält gleich oder mehr als 4 Zeichen
- <b>empty</b> Wort enthält eine Leere Zeichenkette
- <b>else</b> Falls keines der Fälle zutrifft
- Wird ein <typ> identifiziert wird für $n der <wert> eingesetzt<br>
- Beispiel: <code>licht (\S*) = set light $1{true => on,false => off}</code>
- </li>
- <li>$n[<list>]<br>
- Kommaseparierte Liste: [wert1,wert2,...,[else,value], [empty,value]] oder [@modwordlist]<br>
- Ist $n eine Zahl, wird das Wort das an dieser Position in <list> steht gewählt.<br><br>
- Ist $n ein Text wird in der zugehörigen Klammer im <regexp>-Teil nach einer Liste gesucht. (a|b|c) oder (@keywordlist)
- In dieser Liste, wird nach $n gesucht und bei erfolg dessen Position in <list> für $n gewählt.
- <br>Beispiel: <code>licht .* (küche|flur|bad) (\S*) an = set $1[dev_a,dev_b,dev_c] $2{true => on,false => off}</code>
- </li>
- <li>$n@<br>Das Wort wird so übernommen wie es in der Liste im <regexp>-Teil steht.</li>
- </ul>
- <br>
- Umgebungsvariablen:
- <ul>
- Es stehen eine Reihe von Variablen zur Verfügung auf die im <command>-Teil zugegriffen werden können.
- <li><b>$&</b> Enthält alle gefundenen Wörter</li>
- <li><b>!$&</b> Enthält den Rest der nicht von der RegExp eingeschlossen wurde</li>
- <li><b>$DATE</b> Enthält den Zeit und Datumstext des Sprachbefehls</li>
- <li><b>$AGAIN</b> Enthält das Wort wieder wenn es sich um ein wieder Kommando handelt</li>
- <li><b>$TIME</b> Enthält die erkannte Zeit.</li>
- <li><b>$NAME</b> Enthält den Devicenamen.</li>
- <li><b>$IF</b> Enthält den Text der erkannten T2F_if Konfiguration.</li>
- <li><b>$0</b> Enthält den Text der erkannten T2F_origin RegExp.</li>
- </ul>
-
- </ul>
- <br>
-
- <a name="Talk2Fhemset"></a>
- <b>Set</b><br>
- <ul>
- <code>set <name> [!]<text></code>
- <br><br>
- Über das <i>set</i> Kommando wird der zu interpretierende Text an das Modul gesendet.
- Schaue unter <a href="http://fhem.de/commandref.html#set">commandref#set</a> für weiterführende Hilfe.
- <li>cleartimers</li> Entfernt die wartenden zeitbezogenen Kommandos
- <li>cleartriggers</li> Entfernt die wartenden ereignisbezogenen Kommandos
- </ul>
- <br>
- <a name="Talk2Fhemget"></a>
- <b>Get</b><br>
- <code>get <name> <option></code>
- <br><br>
- Über <i>get</i> lassen sich Informationen aus dem Modul auslesen.
- Siehe <a href="http://fhem.de/commandref.html#get">commandref#get</a> für weitere Informationen zu "get".
- <br><br>
- <option>
- <ul>
- <li><i>@keywordlist</i> <i>@modwordlist</i><br>
- Vergleich der zwei Listen Wort für Wort</li>
- <li><i>keylistno</i><br>
- Eine Auflistung der Konfigurierten "Keyword"-Listen. Zur einfacheren Positionierung der "Modword"-Listen</li>
- <li><i>log</i><br>
- Zeigt die Logeinträge des letzten Kommandos</li>
- <li><i>modificationtypes</i><br>
- Zeigt die RegExp der Modifikationstypen. </li>
- <li><i>standardfilter</i><br>
- Lädt den Standardfilter und schreibt ihn in das Attribut T2F_filter wenn er leer ist</li>
- <li><i>version</i><br>
- Die Modulversion</li>
- </ul>
- <br>
- <a name="Talk2Fhemreadings"></a>
- <b>Readings</b>
- <ul>
- <li><i>set</i><br>
- Enthält den zuletzt über "set" gesendeten Text.
- </li>
- <li><i>cmds</i><br>
- Enthält das zuletzt ausgeführte Kommando. Wird auch bei disable=1 gesetzt.
- </li>
- <li><i>answer</i><br>
- Enthält den Antworttext des letzten Befehls.
- </li>
- <li><i>err</i><br>
- Enthält die letzte Fehlermeldung.<br>
- "No match" Übereinstimmung mit keiner RegExp.<br>
- "Error on Command" siehe FHEM log.
- </li>
- <li><i>response</i><br>
- Enthällt die Rückgabe des FHEM Befhels.
- </li>
- <li><i>origin</i><br>
- Enthält die gefundene Zeichenkette der in dem Attribut T2F_origin definierten RegExp.
- </li>
- <li><i>status</i><br>
- Enthält den Status der Ausgabe.
- response, disabled, err, answers, done
- </li>
- <li><i>ifs</i><br>
- Enthält die Bedingungen bei denen das Kommando ausgeführt werden wird.
- </li>
- <li><i>notifies</i><br>
- Enthält eine Auflistung der Devices die für die aktuell wartenden bedingten Kommandos relevant sind. Auf diesen Devices liegt ein internes notify.
- </li>
- </ul>
- <br>
-
- <a name="Talk2Fhemattr"></a>
- <b>Attribute</b>
- <ul>
- <code>attr <name> <attribute> <value></code>
- <br><br>
- Siehe <a href="http://fhem.de/commandref.html#attr">commandref#attr</a> für weitere Informationen zu den Attributen.
- <br><br>
- Attribute:
- <ul>
- <li><i>T2F_keywordlist</i> <name> = <list><br>
- Eine Komma seperierte Liste von Schlüsselwörtern wie z.B.: Räumen, Namen, Farben usw...<br>
- Mit anderen Worten, mit natürlichem Namen benannte Sachen.
- </li>
- <li><i>T2F_modwordlist</i> <name> = <list><br>
- Eine Komma seperierte Liste von Ersetzungswörten die für die Schlüsselwörter eingesetzt werden.
- z.B.: Gerätenamen in FHEM<br>
- </li>
- <li><i>T2F_if</i><br>
- Eine Auflistung von ereignisgesteuerten Konfigurationen. Die Syntax ist die der Definition. Kommandoteil ist eine IF Bedingung.<br>
- z.B.: wenn .*?tür = [door] eq "open"
- </li>
- <li><i>T2F_filter</i><br>
- Kommaseparierte Liste von RegExp die generell entfernt werden.<br>
- Standard: \bbitte\b,\bauch\b,\bkann\b,\bsoll\b
- </li>
- <li><i>T2F_origin</i><br>
- Eine RegExp die generell entfernt wird und deren Ausgabe über $0 angesprochen werden kann.<br>
- Kann für eine Benutzerzuordnung verwendet werden.
- </li>
- <li><i>T2F_language</i>DE|EN<br>
- Die verwendete Sprache kann über das globale Attribut "language" gesetzt werden. Oder über dieses Attribut überschrieben werden.
- </li>
- <li><i>T2F_disableumlautescaping</i> <0|1><br>
- Deaktiviert das Konvertieren der Umlaute in "\S\S?"</li>
- <li><i>disable</i> <0|1><br>
- Kann zu Testzwecken verwendet werden. Steht das Attribut auf 1, wird das FHEM-Kommando nicht ausgeführt
- aber in das Reading cmds geschrieben.
- </li>
- </ul>
- </ul>
- </ul>
- =end html_DE
- =cut
|