| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496 |
- ###############################################################################
- # $Id: 75_MSG.pm 15222 2017-10-10 06:47:28Z loredo $
- #
- #TODO
- # - be able to use type "default" to let read from attr
- # - forceType/forceDevice in user parameters
- # - implement default messages in RESIDENTS using msg command
- # - queue message until recipient is available again (e.g. when absent)
- # also see https://forum.fhem.de/index.php/topic,69683.0.html
- # - new msgType "queue"
- # - escalation to type "queue" when n/a
- # - automatically trigger to release queue messages by arriving at home
- # (ROOMMATE)
- # - allow some other ? to only reach people when they are at home
- # - if ROOMMATE is asleep, queue message for next day
- # (usefull escalate for screen with PostMe?)
- # - delivery options as attributes (like ! or ? to gateways, devices or types)
- # - all messages should be queued and then delivered so a timer may come back
- # and check the gateway device for successful delivery
- # - fix readings: store texts with \x{0000} notation
- # - end user documentation / commandref !!
- #
- package main;
- use strict;
- use warnings;
- use Data::Dumper;
- use Time::HiRes qw(time);
- use utf8;
- # initialize ##################################################################
- sub MSG_Initialize($$) {
- my %hash = (
- Fn => "CommandMsg",
- Hlp =>
- "[<type>] [<\@device>|<e-mail address>] [<priority>] [|<title>|] <message-text>",
- );
- $cmds{msg} = \%hash;
- require "$attr{global}{modpath}/FHEM/msgSchema.pm";
- }
- # regular Fn ##################################################################
- sub CommandMsg($$;$$);
- sub CommandMsg($$;$$) {
- my ( $cl, $msg, $testMode ) = @_;
- my $return = "";
- if ( $featurelevel >= 5.7 ) {
- my %dummy;
- my ( $err, @a ) = ReplaceSetMagic( \%dummy, 0, ($msg) );
- $msg = join( " ", @a )
- unless ($err);
- }
- # find existing msgConfig device or create a new instance
- my $globalDevName = "globalMsg";
- if ( defined( $modules{msgConfig}{defptr} ) ) {
- $globalDevName = $modules{msgConfig}{defptr}{NAME};
- }
- else {
- fhem "define $globalDevName msgConfig";
- $return .=
- "Global configuration device $globalDevName was created.\n\n";
- }
- if ( $msg eq "" || $msg =~ /^\?[\s\t ]*$/ || $msg eq "help" ) {
- return $return
- . "Usage: msg [<type>] [<\@device>|<e-mail address>] [<priority>] [|<title>|] <message>";
- }
- # default settings
- my $cmdSchema = msgSchema::get();
- my $settings = {
- audio => {
- typeEscalation => {
- gwUnavailable => 'text',
- emergency => 'text',
- residentGone => 'text',
- residentAbsent => 'text',
- },
- },
- light => {
- typeEscalation => {
- gwUnavailable => 'audio',
- emergency => 'audio',
- residentGone => 'audio',
- residentAbsent => 'audio',
- },
- },
- push => {
- typeEscalation => {
- gwUnavailable => 'mail',
- emergency => 'mail',
- },
- },
- screen => {
- typeEscalation => {
- gwUnavailable => 'light',
- emergency => 'light',
- residentGone => 'light',
- residentAbsent => 'light',
- },
- },
- };
- ################################################################
- ### extract message details
- ###
- my ( $msgA, $params ) = parseParams($msg, "[^\\S\\n]", " ");
- # only use output from parseParams when
- # parameters where found
- if ( ref($params) eq "HASH" && keys %$params ) {
- if ( scalar @$msgA > 0 ) {
- $msg = join( " ", @$msgA );
- }
- else {
- $msg = "";
- }
- }
- if ( defined( $params->{msgText} ) ) {
- Log3 $globalDevName, 5,
- "msg: Adding message text from given user parameters";
- $msg .= " " unless ( $msg eq "" );
- $msg .= $params->{msgText};
- delete $params->{msgText};
- }
- return $return
- . "Usage: msg [<type>] [<\@device>|<e-mail address>] [<priority>] [|<title>|] <message>"
- if ( $msg =~ m/^[\s\t\n ]*$/ );
- Log3 $globalDevName, 5, "msg: Extracted user parameters\n" . Dumper($params)
- if ( ref($params) eq "HASH" && keys %$params );
- my $types = "";
- my $recipients = "";
- my $priority = "";
- my $title = "-";
- my $priorityCat = "";
- # check for message types
- if ( $params->{msgType} ) {
- Log3 $globalDevName, 5, "msg: given types=$params->{msgType}";
- $types = $params->{msgType};
- $types =~ s/[\s\t ]+//g;
- delete $params->{msgType};
- }
- elsif ( $msg =~
- s/^[\s\t ]*([a-z,]*!?(screen|light|audio|text|push|mail|queue)[\w,!?&|]*)[\s\t ]+//i
- )
- {
- Log3 $globalDevName, 5, "msg: found types=$1"
- unless ( defined($testMode) && $testMode eq "1" );
- $types = $1;
- }
- # programatic exception:
- # e.g. recipients were given automatically from empty readings
- if (
- $msg =~ m/^[\s\t ]*([!]?(([A-Za-z0-9%+._-])*@([,\-:|]+)))[\s\t ]+/
- || ( $params->{msgRcpt}
- && $params->{msgRcpt} =~
- m/^[\s\t ]*([!]?(([A-Za-z0-9%+._-])*@([,\-:|]+)))[\s\t ]+/ )
- )
- {
- Log3 $globalDevName, 4,
- "msg: message won't be sent - recipient '$1' contains special"
- . " characters like ',-:|' or behind the @ character is simply"
- . " emptiness. This might be okay, e.g. if you are using something"
- . " like a reading from RESIDENTS/ROOMMATE/GUEST to address present"
- . " or absent residents and this list is simply empty at this time."
- . " ($msg)";
- return;
- }
- # check for given recipients
- if ( $params->{msgRcpt} ) {
- Log3 $globalDevName, 5, "msg: given recipient=$params->{msgRcpt}";
- $recipients = $params->{msgRcpt};
- $recipients =~ s/[\s\t ]+//g;
- delete $params->{msgRcpt};
- }
- elsif ( $msg =~
- s/^[\s\t ]*([!]?(([A-Za-z0-9%+._-])*@([%+a-z0-9A-Z.-]+))[\w,@.!?|:]*)[\s\t ]+//
- )
- {
- Log3 $globalDevName, 5, "msg: found recipient=$1"
- unless ( defined($testMode) && $testMode eq "1" );
- $recipients = $1;
- }
- # check for given priority
- if ( defined( $params->{msgPrio} ) ) {
- Log3 $globalDevName, 5, "msg: given priority=$params->{msgPrio}";
- $priority = $params->{msgPrio};
- $priority =~ s/[\s\t ]+//g;
- delete $params->{msgPrio};
- }
- elsif ( $msg =~ s/^[\s\t ]*([-+]{0,1}\d+[\.\d]*)[\s\t ]*// ) {
- Log3 $globalDevName, 5, "msg: found priority=$1"
- unless ( defined($testMode) && $testMode eq "1" );
- $priority = $1;
- }
- $priority = int($priority) if ( $priority =~ /^[-+]{0,1}\d+\.\d*$/ );
- return "Invalid priority $priority: Needs to be an integer value"
- unless ( $priority eq "" || $priority =~ /^[-+]{0,1}\d+$/ );
- # check for given message title
- if ( defined( $params->{msgTitle} ) ) {
- Log3 $globalDevName, 5, "msg: given title=$params->{msgTitle}";
- $title = $params->{msgTitle};
- $title =~ s/^[\s\t ]*\|(.*?)\|[\s\t ]*/$1/;
- delete $params->{msgTitle};
- }
- elsif ( $msg =~ s/^[\s\t ]*\|(.*?)\|[\s\t ]*// ) {
- Log3 $globalDevName, 5, "msg: found title=$1"
- unless ( defined($testMode) && $testMode eq "1" );
- $title = $1;
- }
- # check for user parameters (DEPRECATED / legacy compatibility only)
- if ( $msg =~ s/[\s\t ]*O(\[\{.*\}\])[\s\t ]*$// ) {
- Log3 $globalDevName, 5, "msg: found options=$1"
- unless ( defined($testMode) && $testMode eq "1" );
- # Use JSON module if possible
- eval {
- require JSON;
- import JSON qw( decode_json );
- };
- if ($@) {
- Log3 $globalDevName, 3,
- "msg: Error loading Perl::JSON. "
- . "Please switch to new syntax to use user parameters";
- }
- else {
- Log3 $globalDevName, 4,
- "msg: Please switch to new syntax to use user parameters";
- my $o;
- eval '$o = decode_json( Encode::encode_utf8($1) ); 1';
- if ($@) {
- Log3 $globalDevName, 5,
- "msg: Error decoding JSON for user parameters: $@";
- }
- elsif ( ref($o) eq "ARRAY" ) {
- for my $item (@$o) {
- next unless ( ref($item) eq "HASH" );
- for my $key ( keys(%$item) ) {
- next if ( ref( $item->{$key} ) );
- my $val = $item->{$key};
- $params->{$key} = $item->{$key}
- unless ( $params->{$key} );
- }
- }
- Log3 $globalDevName, 5,
- "msg: Decoded user parameters\n" . Dumper($params)
- if ($params);
- }
- }
- }
- $types = "default"
- if ( $types eq "" );
- my $msgSent = 0;
- my $forwarded = "";
- my %sentTypesPerDevice;
- my $sentCounter = 0;
- my $msgID = time();
- my $msgDateTime = TimeNow();
- my $isTypeOr = 1;
- my $isRecipientOr = 1;
- my $hasTypeOr = 0;
- my $hasRecipientOr = 0;
- my $softFail = 0;
- $recipients = "\@" . $globalDevName if ( $recipients eq "" );
- ################################################################
- ### recipient loop
- ###
- my @recipientsOr = split( /\|/, $recipients );
- Log3 $globalDevName, 6,
- "msg: recipientOr total is " . scalar( grep { defined $_ } @recipientsOr )
- unless ( defined($testMode) && $testMode eq "1" );
- for (
- my $iRecipOr = 0 ;
- $iRecipOr < scalar( grep { defined $_ } @recipientsOr ) ;
- $iRecipOr++
- )
- {
- Log3 $globalDevName, 6,
- "msg: "
- . "running loop recipientsOr for recipient(s) $recipientsOr[$iRecipOr]"
- unless ( defined($testMode) && $testMode eq "1" );
- my $loopReturn1 = "";
- $hasRecipientOr = 1
- if ( scalar( grep { defined $_ } @recipientsOr ) > 1 );
- my @recipient = split( /,/, $recipientsOr[$iRecipOr] );
- foreach my $device (@recipient) {
- Log3 $globalDevName, 6, "msg: running loop for device $device"
- unless ( defined($testMode) && $testMode eq "1" );
- my $loopReturn2 = "";
- ################################################################
- ### type loop
- ###
- my @typesOr = split( /\|/, $types );
- Log3 $globalDevName, 6,
- "msg: typeOr total is " . scalar( grep { defined $_ } @typesOr )
- unless ( defined($testMode) && $testMode eq "1" );
- for (
- my $iTypesOr = 0 ;
- $iTypesOr < scalar( grep { defined $_ } @typesOr ) ;
- $iTypesOr++
- )
- {
- Log3 $globalDevName, 6,
- "msg: running loop typeOr for type(s) $typesOr[$iTypesOr]"
- unless ( defined($testMode) && $testMode eq "1" );
- my $loopReturn3 = "";
- $hasTypeOr = 1
- if ( scalar( grep { defined $_ } @typesOr ) > 1 );
- my @type = split( /,/, lc( $typesOr[$iTypesOr] ) );
- for (
- my $i = 0 ;
- $i < scalar( grep { defined $_ } @type ) ;
- $i++
- )
- {
- Log3 $globalDevName, 6,
- "msg: running loop for type $type[$i]"
- unless ( defined($testMode) && $testMode eq "1" );
- last unless ( defined( $type[$i] ) );
- # check for correct type
- my @msgCmds = (
- "screen", "light", "audio", "text",
- "push", "mail", "queue", "default"
- );
- unless ( grep { $type[$i] =~ /^$_/i } @msgCmds ) {
- $loopReturn3 .= "Unknown message type $type[$i]\n";
- next;
- }
- ###
- ### /type loop
- ################################################################
- my @unavailabilityIndicators = (
- "0", "false",
- "absent", "disappeared",
- "unauthorized", "unavailable",
- "unreachable", "disconnected"
- );
- my $logDevice;
- $logDevice = $globalDevName;
- $logDevice = $device
- if (
- MSG_FindAttrVal( $device, "verbose", undef, undef ) );
- my $msgSentDev = 0;
- my $gatewayDevs = "";
- my $forceDevice = 0;
- my $forceQueue = 0;
- # for device type
- my $deviceType = "device";
- if ( $device =~
- m/^(([A-Za-z0-9%+._-])+@+([%+a-z0-9A-Z.-]*))$/ )
- {
- $gatewayDevs = $1;
- $deviceType = "email";
- }
- elsif ( $device =~
- m/^@?([A-Za-z\d_\.\-\/]+)([^A-Za-z\d_\.\-\/]+)[\s\t ]*$/
- )
- {
- $device = $1;
- foreach ( split( /(\S)/, $2 ) ) {
- $forceDevice = 1 if ( $_ eq "!" );
- $softFail = 1 if ( $_ eq "?" );
- $forceQueue = 1 if ( $_ eq "&" );
- }
- Log3 $logDevice, 5,
- "msg $device: forceDevice=$forceDevice (from device contact)"
- if ($forceDevice);
- Log3 $logDevice, 5,
- "msg $device: softFail=$softFail (from device contact)"
- if ($softFail);
- Log3 $logDevice, 5,
- "msg $device: forceQueue=$forceQueue (from device contact)"
- if ($forceQueue);
- }
- elsif ( $device =~ /^@(.*)/ ) {
- $device = $1;
- }
- # sub-recipient
- my $subRecipient = "";
- my $termRecipient = "";
- if ( $device =~
- m/^@?([A-Za-z0-9._]+):([A-Za-z0-9._\-\/@+]*):?([A-Za-z0-9._\-\/@+]*)$/
- )
- {
- $device = $1;
- $subRecipient = $2;
- $termRecipient = $3;
- }
- # FATAL ERROR: device does not exist
- if ( !IsDevice($device)
- && $deviceType eq "device" )
- {
- $loopReturn3 .= "Device $device does not exist\n"
- unless ($softFail);
- unless ( defined($testMode) && $testMode eq "1" ) {
- Log3 $logDevice, 2,
- "msg $device: Device does not exist"
- unless ($softFail);
- Log3 $logDevice, 5,
- "msg $device: Device does not exist"
- if ($softFail);
- }
- my $regex1 =
- "\\s*!?@?" . $device . "[,|]"; # at the beginning
- my $regex2 = "[,|]!?@?" . $device . "\\s*"; # at the end
- my $regex3 =
- ",!?@?" . $device . ","; # in the middle with comma
- my $regex4 =
- "[\|,]!?@?"
- . $device
- . "[\|,]"; # in the middle with pipe and/or comma
- $recipients =~ s/^$regex1//gi;
- $recipients =~ s/$regex2$/|/gi;
- $recipients =~ s/$regex3/,/gi;
- $recipients =~ s/$regex4/|/gi;
- next;
- }
- # Find custom types for devices
- if ( $type[$i] eq "default" ) {
- delete $typesOr[$iTypesOr]
- if ( $typesOr[$iTypesOr] eq "default" );
- delete $type[$i];
- Log3 $logDevice, 5,
- "msg $device: msgType lookup for $device:";
- my @t = split(
- m/\|/,
- MSG_FindAttrVal(
- $device, "msgType", undef, "text"
- )
- );
- $hasTypeOr = 1
- if ( scalar( grep { defined $_ } @t ) > 1 );
- foreach (@t) {
- Log3 $logDevice, 5,
- "msg $device: Adding to \@typesOr: $_";
- push @typesOr, $_;
- foreach ( split( /,/, lc($_) ) ) {
- Log3 $logDevice, 5,
- "msg $device: Adding to \@type: $_";
- push @type, $_;
- }
- }
- }
- my $forceType = 0;
- if ( $type[$i] =~
- m/^([A-Za-z\d_\.\-\/]+)([^A-Za-z\d_\.\-\/]+)[\s\t ]*$/ )
- {
- $type[$i] = $1;
- foreach ( split( /(\S)/, $2 ) ) {
- $forceType = 1 if ( $_ eq "!" );
- $softFail = 1 if ( $_ eq "?" );
- $forceQueue = 1 if ( $_ eq "&" );
- }
- Log3 $logDevice, 5,
- "msg $device: forceType=$forceType (from type)"
- if ($forceType);
- Log3 $logDevice, 5,
- "msg $device: softFail=$softFail (from type)"
- if ($softFail);
- Log3 $logDevice, 5,
- "msg $device: forceQueue=$forceQueue (from type)"
- if ($forceQueue);
- }
- # next type loop if device is an email address
- # and this is not the mail type loop run
- if ( $deviceType eq "email"
- && $type[$i] ne "mail"
- && $type[$i] ne "text" )
- {
- Log3 $logDevice, 5,
- "msg $device: "
- . "Skipping loop for device type 'email' with unmatched message type '"
- . $type[$i] . "'";
- next;
- }
- my $typeUc = ucfirst( $type[$i] );
- my $catchall = 0;
- my $useLocation = 0;
- ################################################################
- ### get target information from device location
- ###
- # search for location references
- my @locationDevs;
- @locationDevs = split(
- /,/,
- MSG_FindAttrVal(
- $device, "msgLocationDevs", $typeUc, ""
- )
- );
- if ( $deviceType eq "device" ) {
- # get device location
- my $deviceLocation =
- msgConfig_FindReadingsVal( $device, "location",
- $typeUc, "" );
- my $locationDev = "";
- if ( $deviceLocation ne "" && $deviceType eq "device" )
- {
- # lookup matching location
- foreach (@locationDevs) {
- if ( $featurelevel >= 5.7 ) {
- my %dummy;
- my ( $err, @a ) =
- ReplaceSetMagic( \%dummy, 0, ($_) );
- $_ = join( " ", @a )
- unless ($err);
- }
- my $lName =
- AttrVal( $_, "msgLocationName", "" );
- if ( $lName ne "" && $lName eq $deviceLocation )
- {
- $locationDev = $_;
- last;
- }
- }
- if ( $featurelevel >= 5.7 ) {
- my %dummy;
- my ( $err, @a ) =
- ReplaceSetMagic( \%dummy, 0, ($locationDev) );
- $locationDev = join( " ", @a )
- unless ($err);
- }
- # look for gateway device
- $gatewayDevs =
- MSG_FindAttrVal( $locationDev, "msgContact",
- $typeUc, "" );
- # at least one of the location gateways needs to
- # be available. Otherwise we fall back to
- # non-location contacts
- if ( $gatewayDevs ne "" ) {
- if ( $featurelevel >= 5.7 ) {
- my %dummy;
- my ( $err, @a ) =
- ReplaceSetMagic( \%dummy, 0,
- ($gatewayDevs) );
- $gatewayDevs = join( " ", @a )
- unless ($err);
- }
- foreach
- my $gatewayDevOr ( split /\|/, $gatewayDevs )
- {
- foreach my $gatewayDev ( split /,/,
- $gatewayDevOr )
- {
- my $tmpSubRecipient;
- if ( $gatewayDev =~ /:(.*)/ ) {
- $tmpSubRecipient = $1;
- }
- if ( $type[$i] ne "mail"
- && !IsDevice($gatewayDev)
- && $deviceType eq "device" )
- {
- $useLocation = 2
- if ( $useLocation == 0 );
- }
- elsif ( $type[$i] ne "mail"
- && IsDisabled($gatewayDev) )
- {
- $useLocation = 2
- if ( $useLocation == 0 );
- }
- elsif (
- $type[$i] ne "mail"
- && (
- (
- grep {
- ReadingsVal(
- $gatewayDev,
- "presence",
- "present"
- ) eq $_
- } @unavailabilityIndicators
- )
- || (
- grep {
- ReadingsVal(
- $gatewayDev,
- "state",
- "present"
- ) eq $_
- } @unavailabilityIndicators
- )
- || (
- defined(
- $defs{$gatewayDev}
- )
- && defined(
- $defs{$gatewayDev}
- {STATE}
- )
- && (
- grep {
- $defs{$gatewayDev}
- {STATE} eq $_
- } @unavailabilityIndicators
- )
- )
- || ReadingsVal(
- $gatewayDev, "available",
- "yes"
- ) =~ m/^(0|no|false)$/i
- || ReadingsVal(
- $gatewayDev, "reachable",
- "yes"
- ) =~ m/^(0|no|false)$/i
- )
- )
- {
- $useLocation = 2
- if ( $useLocation == 0 );
- }
- else {
- $useLocation = 1;
- }
- }
- }
- # use gatewayDevs from location only
- # if it has been confirmed to be available
- if ( $useLocation == 1 ) {
- Log3 $logDevice, 4, "msg $device: "
- . "Matching location definition found";
- }
- else {
- $gatewayDevs = "";
- }
- }
- }
- }
- ################################################################
- ### given device name is already a gateway device itself
- ###
- my $deviceType2 = GetType($device);
- if (
- $gatewayDevs eq ""
- && $deviceType eq "device"
- && $deviceType2 ne ""
- && (
- (
- $type[$i] eq "audio" && defined(
- $cmdSchema->{ $type[$i] }{$deviceType2}
- )
- )
- || (
- $type[$i] eq "light"
- && defined(
- $cmdSchema->{ $type[$i] }{$deviceType2}
- )
- )
- || (
- $type[$i] eq "push"
- && defined(
- $cmdSchema->{ $type[$i] }{$deviceType2}
- )
- )
- || (
- $type[$i] eq "screen"
- && defined(
- $cmdSchema->{ $type[$i] }{$deviceType2}
- )
- )
- || (
- $type[$i] eq "queue"
- && defined(
- $cmdSchema->{ $type[$i] }{$deviceType2}
- )
- )
- )
- )
- {
- Log3 $logDevice, 4,
- "msg $device: Recipient type $deviceType2 "
- . "is a gateway device itself for message type "
- . $type[$i]
- . ". Still checking for any delegates ..."
- unless ( defined($testMode) && $testMode eq "1" );
- $gatewayDevs =
- MSG_FindAttrVal( $device, "msgContact", $typeUc,
- $device );
- }
- ################################################################
- ### get target information from device
- ###
- elsif ( $deviceType eq "device" && $gatewayDevs eq "" ) {
- # look for gateway device
- $gatewayDevs =
- MSG_FindAttrVal( $device, "msgContact", $typeUc, "" );
- # fallback/catchall
- if ( $gatewayDevs eq "" ) {
- $catchall = 1
- if ( $device ne $globalDevName );
- Log3 $logDevice, 6,
- "msg $device: (No $typeUc contact defined, "
- . "trying global instead)"
- if ( $catchall == 1 );
- $gatewayDevs =
- MSG_FindAttrVal( $globalDevName, "msgContact",
- $typeUc, "" );
- }
- }
- # Find priority if none was explicitly specified
- my $loopPriority = $priority;
- $loopPriority =
- MSG_FindAttrVal( $device, "msgPriority$typeUc", $typeUc,
- MSG_FindAttrVal( $device, "msgPriority", $typeUc, 0 ) )
- if ( $priority eq "" );
- # check for available routes
- #
- my %routes;
- $routes{screen} = 0;
- $routes{light} = 0;
- $routes{audio} = 0;
- $routes{text} = 0;
- $routes{push} = 0;
- $routes{mail} = 0;
- $routes{queue} = 1;
- if (
- !defined($testMode)
- || ( $testMode ne "1"
- && $testMode ne "2" )
- )
- {
- Log3 $logDevice, 5,
- "msg $device: Checking for available routes "
- . "(triggered by type $type[$i])";
- $routes{screen} = 1
- if (
- $deviceType eq "device"
- && CommandMsg( "screen",
- "screen \@$device $priority Routing Test", 1 )
- eq "ROUTE_AVAILABLE"
- );
- $routes{light} = 1
- if (
- $deviceType eq "device"
- && CommandMsg( "light",
- "light \@$device $priority Routing Test", 1 )
- eq "ROUTE_AVAILABLE"
- );
- $routes{audio} = 1
- if (
- $deviceType eq "device"
- && CommandMsg( "audio",
- "audio \@$device $priority Routing Test", 1 )
- eq "ROUTE_AVAILABLE"
- );
- if (
- $deviceType eq "device"
- && CommandMsg( "push",
- "push \@$device $priority Routing Test", 1 ) eq
- "ROUTE_AVAILABLE"
- )
- {
- $routes{push} = 1;
- $routes{text} = 1;
- }
- if (
- CommandMsg( "mail",
- "mail \@$device $priority Routing Test", 1 ) eq
- "ROUTE_AVAILABLE"
- )
- {
- $routes{mail} = 1;
- $routes{text} = 1;
- }
- $routes{mail} = 1
- if ( $deviceType eq "email" );
- Log3 $logDevice, 4,
- "msg $device: Available routes: screen="
- . $routes{screen}
- . " light="
- . $routes{light}
- . " audio="
- . $routes{audio}
- . " text="
- . $routes{text}
- . " push="
- . $routes{push}
- . " mail="
- . $routes{mail};
- }
- ##################################################
- ### dynamic routing for text (->push, ->mail)
- ###
- if ( $type[$i] eq "text" ) {
- # user selected emergency priority text threshold
- my $prioThresTextEmg =
- MSG_FindAttrVal( $device, "msgThPrioTextEmergency",
- $typeUc, 2 );
- # user selected low priority text threshold
- my $prioThresTextNormal =
- MSG_FindAttrVal( $device, "msgThPrioTextNormal",
- $typeUc, -2 );
- # Decide push and/or e-mail destination based
- # on priorities
- if ( $loopPriority >= $prioThresTextEmg
- && $routes{push} == 1
- && $routes{mail} == 1 )
- {
- Log3 $logDevice, 4,
- "msg $device: "
- . "Text routing decision: push+mail(1)";
- $forwarded .= ","
- if ( $forwarded ne "" );
- $forwarded .= "text>push+mail";
- push @type, "push"
- unless grep { "push" eq $_ } @type;
- push @type, "mail"
- unless grep { "mail" eq $_ } @type;
- }
- elsif ($loopPriority >= $prioThresTextEmg
- && $routes{push} == 1
- && $routes{mail} == 0 )
- {
- Log3 $logDevice, 4,
- "msg $device: Text routing decision: push(2)";
- $forwarded .= ","
- if ( $forwarded ne "" );
- $forwarded .= "text>push";
- push @type, "push"
- unless grep { "push" eq $_ } @type;
- }
- elsif ($loopPriority >= $prioThresTextEmg
- && $routes{push} == 0
- && $routes{mail} == 1 )
- {
- Log3 $logDevice, 4,
- "msg $device: Text routing decision: mail(3)";
- $forwarded .= ","
- if ( $forwarded ne "" );
- $forwarded .= "text>mail";
- push @type, "mail"
- unless grep { "mail" eq $_ } @type;
- }
- elsif ($loopPriority >= $prioThresTextNormal
- && $routes{push} == 1 )
- {
- Log3 $logDevice, 4,
- "msg $device: Text routing decision: push(4)";
- $forwarded .= ","
- if ( $forwarded ne "" );
- $forwarded .= "text>push";
- push @type, "push"
- unless grep { "push" eq $_ } @type;
- }
- elsif ($loopPriority >= $prioThresTextNormal
- && $routes{mail} == 1 )
- {
- Log3 $logDevice, 4,
- "msg $device: Text routing decision: mail(5)";
- $forwarded .= ","
- if ( $forwarded ne "" );
- $forwarded .= "text>mail";
- push @type, "mail"
- unless grep { "mail" eq $_ } @type;
- }
- elsif ( $routes{mail} == 1 ) {
- Log3 $logDevice, 4,
- "msg $device: Text routing decision: mail(6)";
- $forwarded .= ","
- if ( $forwarded ne "" );
- $forwarded .= "text>mail";
- push @type, "mail"
- unless grep { "mail" eq $_ } @type;
- }
- elsif ( $routes{push} == 1 ) {
- Log3 $logDevice, 4,
- "msg $device: Text routing decision: push(7)";
- $forwarded .= ","
- if ( $forwarded ne "" );
- $forwarded .= "text>push";
- push @type, "push"
- unless grep { "push" eq $_ } @type;
- }
- # FATAL ERROR: routing decision failed
- else {
- Log3 $logDevice, 4,
- "msg $device: "
- . "Text routing FAILED - priority=$loopPriority push="
- . $routes{push}
- . " mail="
- . $routes{mail};
- $loopReturn3 .=
- "ERROR: Could not find any Push or Mail contact "
- . "for device $device - set attributes: msgContactPush "
- . "| msgContactMail | msgContactText | msgRecipientPush "
- . "| msgRecipientMail | msgRecipientText | msgRecipient\n";
- }
- next;
- }
- # FATAL ERROR: we could not find any targets for
- # user specified device...
- if ( $gatewayDevs eq ""
- && $device ne $globalDevName )
- {
- $loopReturn3 .=
- "ERROR: Could not find any $typeUc contact "
- . "for device $device - set attributes: msgContact$typeUc | msgRecipient$typeUc | msgRecipient\n"
- unless ( $type[$i] eq "queue" );
- }
- # FATAL ERROR: we could not find any targets at all
- elsif ( $gatewayDevs eq "" ) {
- $loopReturn3 .=
- "ERROR: Could not find any general $typeUc contact. "
- . "Please specify a destination device or set attributes in general msg configuration device $globalDevName : msgContact$typeUc | msgRecipient$typeUc | msgRecipient\n"
- unless ( $type[$i] eq "queue" );
- }
- # user selected audio-visual announcement state
- my $annState = ReadingsVal(
- MSG_FindAttrVal(
- $device, "msgSwitcherDev", $typeUc, ""
- ),
- "state", "long"
- );
- # user selected emergency priority audio threshold
- my $prioThresAudioEmg =
- MSG_FindAttrVal( $device, "msgThPrioAudioEmergency",
- $typeUc, 2 );
- # user selected high priority audio threshold
- my $prioThresAudioHigh =
- MSG_FindAttrVal( $device, "msgThPrioAudioHigh", $typeUc,
- 1 );
- # user selected high priority threshold
- my $prioThresHigh =
- MSG_FindAttrVal( $device, "msgThPrioHigh", $typeUc, 2 );
- # user selected normal priority threshold
- my $prioThresNormal =
- MSG_FindAttrVal( $device, "msgThPrioNormal", $typeUc, 0 );
- if ( $type[$i] eq "audio" ) {
- if ( $annState eq "long"
- || $forceType == 1
- || $forceDevice == 1
- || $loopPriority >= $prioThresAudioEmg )
- {
- $priorityCat = "";
- }
- elsif ( $loopPriority >= $prioThresAudioHigh ) {
- $priorityCat = "ShortPrio";
- }
- else {
- $priorityCat = "Short";
- }
- }
- else {
- if ( $loopPriority >= $prioThresHigh ) {
- $priorityCat = "High";
- }
- elsif ( $loopPriority >= $prioThresNormal ) {
- $priorityCat = "";
- }
- else {
- $priorityCat = "Low";
- }
- }
- # get resident presence information
- #
- my $residentDevState = "";
- my $residentDevPresence = "";
- # device
- if ( ReadingsVal( $device, "presence", "-" ) ne "-" ) {
- $residentDevState = ReadingsVal( $device, "state", "" );
- $residentDevPresence =
- ReadingsVal( $device, "presence", "" );
- }
- # device indirect
- if (
- (
- $residentDevState eq ""
- || $residentDevPresence eq ""
- )
- && ReadingsVal(
- AttrVal( $device, "msgRecipient$typeUc", "" ),
- "presence", "-" ) ne "-"
- )
- {
- $residentDevState =
- ReadingsVal(
- AttrVal( $device, "msgRecipient$typeUc", "" ),
- "state", "" )
- if ( $residentDevState eq "" );
- $residentDevPresence =
- ReadingsVal(
- AttrVal( $device, "msgRecipient$typeUc", "" ),
- "presence", "" )
- if ( $residentDevPresence eq "" );
- }
- # device indirect general
- if (
- (
- $residentDevState eq ""
- || $residentDevPresence eq ""
- )
- && ReadingsVal( AttrVal( $device, "msgRecipient", "" ),
- "presence", "-" ) ne "-"
- )
- {
- $residentDevState =
- ReadingsVal( AttrVal( $device, "msgRecipient", "" ),
- "state", "" )
- if ( $residentDevState eq "" );
- $residentDevPresence =
- ReadingsVal( AttrVal( $device, "msgRecipient", "" ),
- "presence", "" )
- if ( $residentDevPresence eq "" );
- }
- # device explicit
- if (
- (
- $residentDevState eq ""
- || $residentDevPresence eq ""
- )
- && ReadingsVal(
- AttrVal( $device, "msgResidentsDev", "" ),
- "presence", "-" ) ne "-"
- )
- {
- $residentDevState =
- ReadingsVal(
- AttrVal( $device, "msgResidentsDev", "" ),
- "state", "" )
- if ( $residentDevState eq "" );
- $residentDevPresence =
- ReadingsVal(
- AttrVal( $device, "msgResidentsDev", "" ),
- "presence", "" )
- if ( $residentDevPresence eq "" );
- }
- # global indirect
- if (
- (
- $residentDevState eq ""
- || $residentDevPresence eq ""
- )
- && ReadingsVal(
- AttrVal(
- $globalDevName, "msgRecipient$typeUc", ""
- ),
- "presence",
- "-"
- ) ne "-"
- )
- {
- $residentDevState = ReadingsVal(
- AttrVal(
- $globalDevName, "msgRecipient$typeUc", ""
- ),
- "state", ""
- ) if ( $residentDevState eq "" );
- $residentDevPresence = ReadingsVal(
- AttrVal(
- $globalDevName, "msgRecipient$typeUc", ""
- ),
- "presence",
- ""
- ) if ( $residentDevPresence eq "" );
- }
- # global indirect general
- if (
- (
- $residentDevState eq ""
- || $residentDevPresence eq ""
- )
- && ReadingsVal(
- AttrVal( $globalDevName, "msgRecipient", "" ),
- "presence", "-" ) ne "-"
- )
- {
- $residentDevState =
- ReadingsVal(
- AttrVal( $globalDevName, "msgRecipient", "" ),
- "state", "" )
- if ( $residentDevState eq "" );
- $residentDevPresence =
- ReadingsVal(
- AttrVal( $globalDevName, "msgRecipient", "" ),
- "presence", "" )
- if ( $residentDevPresence eq "" );
- }
- # global explicit
- if (
- (
- $residentDevState eq ""
- || $residentDevPresence eq ""
- )
- && ReadingsVal(
- AttrVal( $globalDevName, "msgResidentsDev", "" ),
- "presence", "-" ) ne "-"
- )
- {
- $residentDevState =
- ReadingsVal(
- AttrVal( $globalDevName, "msgResidentsDev", "" ),
- "state", "" )
- if ( $residentDevState eq "" );
- $residentDevPresence =
- ReadingsVal(
- AttrVal( $globalDevName, "msgResidentsDev", "" ),
- "presence", "" )
- if ( $residentDevPresence eq "" );
- }
- ################################################################
- ### Send message
- ###
- my $queued = 0;
- # user selected emergency priority text threshold
- my $prioThresGwEmg =
- MSG_FindAttrVal( $device, "msgThPrioGwEmergency",
- $typeUc, 2 );
- if ( $featurelevel >= 5.7 ) {
- my %dummy;
- my ( $err, @a ) =
- ReplaceSetMagic( \%dummy, 0, ($gatewayDevs) );
- $gatewayDevs = join( " ", @a )
- unless ($err);
- }
- my %gatewaysStatus;
- $gatewayDevs = $globalDevName if ( $type[$i] eq "queue" );
- foreach my $gatewayDevOr ( split /\|/, $gatewayDevs ) {
- foreach my $gatewayDev ( split /,/, $gatewayDevOr ) {
- if ( $gatewayDev =~
- m/^@?([A-Za-z0-9._]+):([A-Za-z0-9._\-\/@+]*):?([A-Za-z0-9._\-\/@+]*)$/
- )
- {
- $gatewayDev = $1;
- $subRecipient = $2 if ( $subRecipient eq "" );
- $termRecipient = $3 if ( $termRecipient eq "" );
- }
- my $logMsg =
- "msg $device: "
- . "Trying to send message via gateway $gatewayDev";
- $logMsg .= " to recipient $subRecipient"
- if ( $subRecipient ne "" );
- $logMsg .= ", terminal device $termRecipient"
- if ( $termRecipient ne "" );
- Log3 $logDevice, 5, $logMsg
- unless ( defined($testMode) && $testMode eq "1" );
- ##############
- # check for gateway availability and set route status
- #
- my $routeStatus = "OK";
- if ( $type[$i] eq "queue" ) {
- $routeStatus = "OK_QUEUE";
- }
- elsif ($type[$i] ne "mail"
- && !IsDevice($gatewayDev)
- && $deviceType eq "device" )
- {
- $routeStatus = "UNDEFINED";
- }
- elsif ( $type[$i] ne "mail"
- && IsDisabled($gatewayDev) )
- {
- $routeStatus = "DISABLED";
- }
- elsif (
- $type[$i] ne "mail"
- && (
- (
- grep {
- ReadingsVal( $gatewayDev,
- "presence", "present" ) eq $_
- } @unavailabilityIndicators
- )
- || (
- grep {
- ReadingsVal( $gatewayDev, "state",
- "present" ) eq $_
- } @unavailabilityIndicators
- )
- || (
- IsDevice($gatewayDev)
- && defined( $defs{$gatewayDev}{STATE} )
- && (
- grep {
- $defs{$gatewayDev}{STATE} eq $_
- } @unavailabilityIndicators
- )
- )
- || ReadingsVal( $gatewayDev, "available",
- "yes" ) =~ m/^(0|no|false)$/i
- || ReadingsVal( $gatewayDev, "reachable",
- "yes" ) =~ m/^(0|no|false)$/i
- )
- )
- {
- $routeStatus = "UNAVAILABLE";
- }
- elsif (
- $type[$i] ne "mail"
- && (
- ReadingsVal( $gatewayDev, "presence",
- "present" ) =~
- m/^(0|false|absent|disappeared|unauthorized|disconnected|unreachable)$/i
- || ReadingsVal( $gatewayDev, "state",
- "present" ) =~
- m/^(absent|disappeared|unauthorized|disconnected|unreachable)$/i
- || ( IsDevice($gatewayDev)
- && defined( $defs{$gatewayDev}{STATE} )
- && $defs{$gatewayDev}{STATE} =~
- m/^(absent|disappeared|unauthorized|disconnected|unreachable)$/i
- )
- || ReadingsVal( $gatewayDev, "available",
- "yes" ) =~ m/^(0|no|off|false)$/i
- || ReadingsVal( $gatewayDev, "reachable",
- "yes" ) =~ m/^(0|no|off|false)$/i
- )
- )
- {
- $routeStatus = "UNAVAILABLE";
- }
- elsif ( $type[$i] eq "screen"
- && ReadingsVal( $gatewayDev, "power", "on" ) =~
- m/^(0|off)$/i )
- {
- $routeStatus = "OFF";
- }
- elsif ($type[$i] eq "audio"
- && $annState ne "long"
- && $annState ne "short" )
- {
- $routeStatus = "USER_DISABLED";
- }
- elsif ( $type[$i] eq "light" && $annState eq "off" )
- {
- $routeStatus = "USER_DISABLED";
- }
- elsif ($type[$i] ne "push"
- && $type[$i] ne "mail"
- && $residentDevPresence eq "absent" )
- {
- $routeStatus = "USER_ABSENT";
- }
- elsif ($type[$i] ne "push"
- && $type[$i] ne "mail"
- && $residentDevState eq "asleep" )
- {
- $routeStatus = "USER_ASLEEP";
- }
- # enforce by user request
- if (
- (
- $routeStatus eq "USER_DISABLED"
- || $routeStatus eq "USER_ABSENT"
- || $routeStatus eq "USER_ASLEEP"
- )
- && ( $forceType == 1 || $forceDevice == 1 )
- )
- {
- $routeStatus = "OK_ENFORCED";
- }
- # enforce by priority
- if (
- (
- $routeStatus eq "USER_DISABLED"
- || $routeStatus eq "USER_ABSENT"
- || $routeStatus eq "USER_ASLEEP"
- )
- && $loopPriority >= $prioThresGwEmg
- )
- {
- $routeStatus = "OK_EMERGENCY";
- }
- # add location status
- if ( $useLocation == 2 ) {
- $routeStatus .= "+LOCATION-UNAVAILABLE";
- }
- elsif ( $useLocation == 1 ) {
- $routeStatus .= "+LOCATION";
- }
- # # add to queue
- # if (
- # (
- # $routeStatus eq "USER_DISABLED"
- # || $routeStatus eq "USER_ABSENT"
- # || $routeStatus eq "USER_ASLEEP"
- # )
- # && $routeStatus !~ /^OK/
- # && !$softFail
- # )
- # {
- # $routeStatus .= "+QUEUE";
- # }
- my $gatewayType =
- $type[$i] eq "mail"
- ? "fhemMsgMail"
- : GetType( $gatewayDev, "UNDEFINED" );
- my $defTitle = "";
- $defTitle =
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {defaultValues}{$priorityCat}{TITLE}
- if (
- defined(
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {defaultValues}{$priorityCat}{TITLE}
- )
- && $priorityCat ne ""
- );
- $defTitle =
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {defaultValues}{Normal}{TITLE}
- if (
- defined(
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {defaultValues}{Normal}{TITLE}
- )
- && $priorityCat eq ""
- );
- Log3 $logDevice, 5,
- "msg $device: "
- . "Determined default title: $defTitle"
- unless ( defined($testMode) && $testMode eq "1" );
- # use title from device, global or internal default
- my $loopTitle = $title;
- $loopTitle = MSG_FindAttrVal(
- $device,
- "msgTitle$typeUc$priorityCat",
- $typeUc,
- MSG_FindAttrVal(
- $device,
- "msgTitle$typeUc",
- $typeUc,
- MSG_FindAttrVal(
- $device, "msgTitle",
- $typeUc, $defTitle
- )
- )
- ) if ( $title eq "-" );
- $loopTitle = ""
- if ( $loopTitle eq "none"
- || $loopTitle eq "-" );
- my $loopMsg = $msg;
- if ( $catchall == 1 && $type[$i] ne "queue" ) {
- $loopTitle = "Fw: $loopTitle"
- if ( $loopTitle ne ""
- && $type[$i] !~ /^(audio|screen)$/ );
- $loopMsg = "Forwarded Message: $loopMsg"
- if ( $loopTitle eq "" );
- if ( $type[$i] eq "mail" ) {
- $loopMsg .=
- "\n\n-- \nMail catched "
- . "from device $device";
- }
- elsif ( $type[$i] !~ /^(audio|screen)$/ ) {
- $loopMsg .=
- " ### (Catched from device $device)";
- }
- }
- my $loopMsgShrt =
- defined( $params->{msgTextShrt} )
- ? $params->{msgTextShrt}
- : $msg;
- # correct message format
- #
- # Remove Sonos Speak commands
- $loopMsg =~ s/(\s*\|\w+\|\s*)/\\n\\n/gi
- if ( $type[$i] ne "audio" );
- $loopMsgShrt =~ s/(\s*\|\w+\|\s*)/\\n\\n/gi
- if ( $type[$i] ne "audio" );
- # Replace new line with HTML break
- # for e-mails
- $loopMsg =~ s/\n/<br \/>\n/gi
- if ( $type[$i] eq "mail" );
- $loopMsgShrt =~ s/\n/<br \/>\n/gi
- if ( $type[$i] eq "mail" );
- # use command from device, global or internal default
- my $defCmd = "";
- $defCmd =
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {$priorityCat}
- if (
- defined(
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {$priorityCat}
- )
- && $priorityCat ne ""
- );
- $defCmd =
- $cmdSchema->{ $type[$i] }{$gatewayType}{Normal}
- if (
- defined(
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {Normal}
- )
- && $priorityCat eq ""
- );
- my $cmd =
- # gateway device
- AttrVal(
- $gatewayDev, "msgCmd$typeUc$priorityCat",
- MSG_FindAttrVal(
- $device, "msgCmd$typeUc$priorityCat",
- $typeUc, $defCmd
- )
- );
- if ( $cmd eq "" && $type[$i] ne "queue" ) {
- Log3 $logDevice, 4,
- "$gatewayDev: Unknown command schema "
- . "for gateway device type $gatewayType. Use manual definition by userattr msgCmd*"
- unless ( defined($testMode)
- && $testMode eq "1" );
- $loopReturn3 .=
- "$gatewayDev: Unknown command schema "
- . "for gateway device type $gatewayType. Use manual definition by userattr msgCmd*\n";
- next;
- }
- # ReplaceSetMagic
- #
- my $replaceError;
- if ( $featurelevel >= 5.7 ) {
- my %dummy;
- my ( $err, @a );
- # TITLE
- ( $err, @a ) =
- ReplaceSetMagic( \%dummy, 0, ($loopTitle) );
- $replaceError .=
- "ReplaceSetMagic failed for TITLE: $err\n"
- if ($err);
- $loopTitle = join( " ", @a )
- unless ($err);
- # RECIPIENT
- if ( $subRecipient ne "" ) {
- ( $err, @a ) =
- ReplaceSetMagic( \%dummy, 0,
- ($subRecipient) );
- $replaceError .=
- "ReplaceSetMagic failed "
- . "for RECIPIENT: $err\n"
- if ($err);
- $subRecipient = join( " ", @a )
- unless ($err);
- }
- # TERMINAL
- if ( $termRecipient ne "" ) {
- ( $err, @a ) =
- ReplaceSetMagic( \%dummy, 0,
- ($termRecipient) );
- $replaceError .=
- "ReplaceSetMagic failed "
- . "for TERMINAL: $err\n"
- if ($err);
- $termRecipient = join( " ", @a )
- unless ($err);
- }
- }
- $cmd =~ s/%PRIORITY%/$loopPriority/gi;
- $cmd =~ s/%PRIOCAT%/$priorityCat/gi;
- $cmd =~ s/%MSG%/$loopMsg/gi;
- $cmd =~ s/%MSGSHRT%/$loopMsgShrt/gi;
- $cmd =~ s/%MSGID%/$msgID.$sentCounter/gi;
- $cmd =~ s/%TITLE%/$loopTitle/gi;
- my $loopTitleShrt =
- defined( $params->{msgTitleShrt} )
- ? $params->{msgTitleShrt}
- : MSG_FindAttrVal(
- $device,
- "msgTitleShrt$typeUc$priorityCat",
- $typeUc,
- MSG_FindAttrVal(
- $device,
- "msgTitleShrt$typeUc",
- $typeUc,
- MSG_FindAttrVal(
- $device, "msgTitleShrt",
- $typeUc, $loopTitle
- )
- )
- );
- $loopTitleShrt =
- substr( $loopTitleShrt, 0, 37 ) . "..."
- if ( length($loopTitleShrt) > 40 );
- $cmd =~ s/%TITLESHRT%/$loopTitleShrt/gi;
- $loopTitleShrt =~ s/ /_/;
- $cmd =~ s/%TITLESHRT2%/$loopTitleShrt/gi;
- $loopTitleShrt =~ s/^([\s\t ]*\w+).*/$1/g;
- $loopTitleShrt =
- substr( $loopTitleShrt, 0, 17 ) . "..."
- if ( length($loopTitleShrt) > 20 );
- $cmd =~ s/%TITLESHRT3%/$loopTitleShrt/gi;
- my $deviceName = AttrVal(
- $device,
- AttrVal(
- $device,
- "rg_realname",
- AttrVal( $device, "rr_realname", "group" )
- ),
- AttrVal( $device, "alias", $device )
- );
- my $deviceName2 = $deviceName;
- $deviceName2 =~ s/ /_/;
- $cmd =~ s/%SOURCE%/$device/gi;
- $cmd =~ s/%SRCALIAS%/$deviceName/gi;
- $cmd =~ s/%SRCALIAS2%/$deviceName2/gi;
- my $gatewayDevName = AttrVal(
- $gatewayDev,
- AttrVal(
- $gatewayDev,
- "rg_realname",
- AttrVal(
- $gatewayDev, "rr_realname", "group"
- )
- ),
- AttrVal( $gatewayDev, "alias", $gatewayDev )
- );
- my $gatewayDevName2 = $gatewayDevName;
- $gatewayDevName2 =~ s/ /_/;
- $cmd =~ s/%DEVICE%/$gatewayDev/gi;
- $cmd =~ s/%DEVALIAS%/$gatewayDevName/gi;
- $cmd =~ s/%DEVALIAS2%/$gatewayDevName2/gi;
- my $loopMsgDateTime = $msgDateTime;
- $loopMsgDateTime .= ".$sentCounter"
- if ($sentCounter);
- my $loopMsgDateTime2 = $loopMsgDateTime;
- $loopMsgDateTime2 =~ s/ /_/;
- $cmd =~ s/%MSGDATETIME%/$loopMsgDateTime/gi;
- $cmd =~ s/%MSGDATETIME2%/$loopMsgDateTime2/gi;
- my $subRecipientName =
- $subRecipient eq ""
- ? ""
- : AttrVal(
- $subRecipient,
- AttrVal(
- $subRecipient,
- "rg_realname",
- AttrVal(
- $subRecipient, "rr_realname",
- "group"
- )
- ),
- AttrVal(
- $subRecipient, "alias", $subRecipient
- )
- );
- my $subRecipientName2 = $subRecipientName;
- $subRecipientName2 =~ s/ /_/;
- $cmd =~ s/%RECIPIENT%/$subRecipient/gi
- if ( $subRecipient ne "" );
- $cmd =~ s/%RCPTNAME%/$subRecipientName/gi
- if ( $subRecipientName ne "" );
- $cmd =~ s/%RCPTNAME2%/$subRecipientName2/gi
- if ( $subRecipientName2 ne "" );
- $cmd =~ s/%TERMINAL%/$termRecipient/gi
- if ( $termRecipient ne "" );
- my $paramsA;
- unless ( defined($testMode) && $testMode eq "1" ) {
- # user parameters from message
- if ( ref($params) eq "HASH" ) {
- for my $key ( keys %$params ) {
- next if ( ref( $params->{$key} ) );
- my $val = $params->{$key};
- $cmd =~ s/%$key%/$val/gi;
- $cmd =~ s/\$$key/$val/g;
- Log3 $logDevice, 5,
- "msg $device: User parameters: "
- . "replacing %$key% and \$$key by '$val'";
- }
- }
- # user parameters from attributes
- my $paramsAttr1 =
- AttrVal( $gatewayDev,
- "msgParams$typeUc$priorityCat", undef );
- my $paramsAttr2 =
- AttrVal( $gatewayDev, "msgParams$typeUc",
- undef );
- my $paramsAttr3 =
- AttrVal( $gatewayDev, "msgParams", undef );
- my $paramsAttr4 =
- MSG_FindAttrVal( $device,
- "msgParams$typeUc$priorityCat",
- $typeUc, undef );
- my $paramsAttr5 =
- MSG_FindAttrVal( $device, "msgParams$typeUc",
- $typeUc, undef );
- my $paramsAttr6 =
- MSG_FindAttrVal( $device, "msgParams",
- $typeUc, undef );
- foreach (
- $paramsAttr1, $paramsAttr2, $paramsAttr3,
- $paramsAttr4, $paramsAttr5, $paramsAttr6
- )
- {
- next unless ($_);
- if ( $_ =~ m/^{.*}$/s
- && $_ =~ m/=>/
- && $_ !~ m/\$/ )
- {
- my $av = eval $_;
- if ($@) {
- Log3 $logDevice, 3,
- "msg $device: "
- . "ERROR while reading attribute msgParams";
- }
- else {
- $paramsA = $av;
- }
- }
- else {
- my ( $a, $h ) = parseParams($_);
- $paramsA = $h;
- }
- next unless ref($paramsA) eq "HASH";
- if ( ref($paramsA) eq "HASH" ) {
- for my $key ( keys %$paramsA ) {
- next if ( ref( $params->{$key} ) );
- my $val = $paramsA->{$key};
- $cmd =~ s/%$key%/$val/gi;
- $cmd =~ s/\$$key/$val/g;
- Log3 $logDevice, 5,
- "msg $device: "
- . "msgParams: replacing %$key% and \$$key by '$val'";
- }
- }
- }
- # user parameters from command schema hash
- if (
- $priorityCat ne ""
- && defined(
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {defaultValues}{$priorityCat}
- )
- )
- {
- for my $item (
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {defaultValues}{$priorityCat} )
- {
- for my $key ( keys(%$item) ) {
- my $val = $item->{$key};
- $cmd =~ s/%$key%/$val/gi;
- $cmd =~ s/\$$key/$val/g;
- Log3 $logDevice, 5,
- "msg $device: "
- . "msgSchema: replacing %$key% and \$$key by '$val'";
- }
- }
- }
- elsif (
- $priorityCat eq ""
- && defined(
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {defaultValues}{Normal}
- )
- )
- {
- for my $item (
- $cmdSchema->{ $type[$i] }{$gatewayType}
- {defaultValues}{Normal} )
- {
- for my $key ( keys(%$item) ) {
- my $val = $item->{$key};
- $cmd =~ s/%$key%/$val/gi;
- $cmd =~ s/\$$key/$val/g;
- Log3 $logDevice, 5,
- "msg $device: "
- . "msgSchema: replacing %$key% and \$$key by '$val'";
- }
- }
- }
- }
- $sentCounter++;
- if ( $routeStatus =~ /^OK\w*/ ) {
- my $error = 0;
- unless ( defined($testMode)
- && $testMode eq "1" )
- {
- # ReplaceSetMagic
- #
- if ( $featurelevel >= 5.7
- && !$replaceError )
- {
- my %dummy;
- my ( $err, @a ) =
- ReplaceSetMagic( \%dummy, 0, ($cmd) );
- $replaceError .=
- "ReplaceSetMagic failed for CMD: "
- . "$err\n"
- if ($err);
- $cmd = join( " ", @a )
- unless ($err);
- }
- # add user parameters
- # if gateway supports parseParams
- my $gatewayDevType = GetType($gatewayDev);
- if (
- $gatewayDevType
- && ref($params) eq "HASH"
- && ( $modules{$gatewayDevType}
- ->{parseParams}
- || $modules{$gatewayDevType}
- ->{msgParams}{parseParams}
- || $modules{$gatewayDevType}
- ->{'.msgParams'}{parseParams} )
- )
- {
- Log3 $logDevice, 5,
- "msg $device: "
- . "parseParams support: Handing over user parameters to other device";
- my ( $a, $h ) = parseParams($cmd);
- keys %$params;
- while ( ( my $key, my $value ) =
- each %$params )
- {
- # Compatibility to legacy schema:
- # lowercase after _
- my $s = $gatewayDevType
- . "[\_\/-]([A-Z0-9_-]+)";
- $key =~ s/^$s$/\L$1/;
- # remove gateway TYPE when
- # used as prefix
- $s = $gatewayDevType . "[_\/-]";
- $key =~ s/^$s//;
- $cmd .= " $key='$value'"
- if ( !defined( $h->{$key} )
- || $h->{$key} =~
- m/^[\s\t\n ]*$/ );
- }
- keys %$paramsA;
- while ( ( my $key, my $value ) =
- each %$paramsA )
- {
- # Compatibility to legacy schema:
- # lowercase after _
- my $s = $gatewayDevType
- . "[\_\/-]([A-Z0-9_-]+)";
- $key =~ s/^$s$/\L$1/;
- # remove gateway TYPE when
- # used as prefix
- $s = $gatewayDevType . "[_\/-]";
- $key =~ s/^$s//;
- $cmd .= " $key='$value'"
- if ( !defined( $h->{$key} )
- || $h->{$key} =~
- m/^[\s\t\n ]*$/ );
- }
- }
- # excplicitly queue message
- if ( $routeStatus eq "OK_QUEUE" ) {
- $queued = msgConfig_QueueAdd(
- $msgA, $params,
- $msgDateTime, $msgID,
- $sentCounter, $type[$i],
- $device, $subRecipient,
- $termRecipient, $priority,
- $loopTitle, $loopMsg
- ) ? 1 : 0;
- }
- # run command
- elsif ($replaceError) {
- $error = 2;
- $loopReturn3 .= $replaceError;
- }
- elsif ( $cmd =~ /^\s*\{.*\}\s*$/ ) {
- Log3 $logDevice, 5,
- "msg $device: "
- . "$type[$i] route command (Perl): $cmd";
- eval $cmd;
- unless ( !$@ || $@ =~ m/^[\s\t\n ]*$/ )
- {
- $error = 1;
- $loopReturn3 .= "$gatewayDev: $@\n";
- }
- }
- else {
- Log3 $logDevice, 5,
- "msg $device: "
- . "$type[$i] route command (fhem): $cmd";
- my $ret = fhem $cmd, 1;
- unless ( !$ret
- || $ret =~ m/^[\s\t\n ]*$/ )
- {
- $error = 1;
- $loopReturn3 .=
- "$gatewayDev: $ret\n";
- }
- }
- $routeStatus = "ERROR"
- if ( $error == 1 );
- $routeStatus = "ERROR_EVAL"
- if ( $error == 2 );
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "RECIPIENT=$subRecipient "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority($priorityCat) "
- . "TITLE='$loopTitle' "
- . "MSG='$loopMsg'"
- if ( $priorityCat ne ""
- && $subRecipient ne "" );
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "RECIPIENT=$subRecipient "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority "
- . "TITLE='$loopTitle' "
- . "MSG='$loopMsg'"
- if ( $priorityCat eq ""
- && $subRecipient ne "" );
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority($priorityCat) "
- . "TITLE='$loopTitle' "
- . "MSG='$loopMsg'"
- if ( $priorityCat ne ""
- && $subRecipient eq "" );
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority "
- . "TITLE='$loopTitle' "
- . "MSG='$loopMsg'"
- if ( $priorityCat eq ""
- && $subRecipient eq "" );
- }
- $msgSent = 1 if ( $error == 0 );
- $msgSentDev = 1 if ( $error == 0 );
- if ( $subRecipient ne "" ) {
- $gatewaysStatus{"$gatewayDev:$subRecipient"}
- = $routeStatus
- if ( $globalDevName ne $gatewayDev );
- $gatewaysStatus{"$device:$subRecipient"} =
- $routeStatus
- if ( $globalDevName eq $gatewayDev );
- }
- else {
- $gatewaysStatus{$gatewayDev} = $routeStatus
- if ( $globalDevName ne $gatewayDev );
- $gatewaysStatus{$device} = $routeStatus
- if ( $globalDevName eq $gatewayDev );
- }
- }
- elsif ( $routeStatus =~ /\+QUEUE/ || $forceQueue ) {
- unless ( defined($testMode)
- && $testMode eq "1" )
- {
- if ( !( grep { "queue" eq $_ } @type ) ) {
- $queued = msgConfig_QueueAdd(
- $msgA, $params,
- $msgDateTime, $msgID,
- $sentCounter, $type[$i],
- $device, $subRecipient,
- $termRecipient, $priority,
- $loopTitle, $loopMsg
- ) ? 1 : 0;
- }
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "RECIPIENT=$subRecipient "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority "
- . "TITLE='$loopTitle' '$loopMsg'"
- if ( $subRecipient ne "" );
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority "
- . "TITLE='$loopTitle' '$loopMsg'"
- if ( $subRecipient eq "" );
- }
- $msgSent = 3 if ( $msgSent != 1 );
- $msgSentDev = 3 if ( $msgSentDev != 1 );
- $gatewaysStatus{$gatewayDev} = $routeStatus
- if ( $globalDevName ne $gatewayDev );
- $gatewaysStatus{$device} = $routeStatus
- if ( $globalDevName eq $gatewayDev );
- }
- elsif ($routeStatus eq "UNAVAILABLE"
- || $routeStatus eq "UNDEFINED" )
- {
- unless ( defined($testMode)
- && $testMode eq "1" )
- {
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "RECIPIENT=$subRecipient "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority "
- . "TITLE='$loopTitle' '$loopMsg'"
- if ( $subRecipient ne "" );
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority "
- . "TITLE='$loopTitle' '$loopMsg'"
- if ( $subRecipient eq "" );
- }
- $gatewaysStatus{$gatewayDev} = $routeStatus
- if ( $globalDevName ne $gatewayDev );
- $gatewaysStatus{$device} = $routeStatus
- if ( $globalDevName eq $gatewayDev );
- }
- else {
- unless ( defined($testMode)
- && $testMode eq "1" )
- {
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "RECIPIENT=$subRecipient "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority "
- . "TITLE='$loopTitle' '$loopMsg'"
- if ( $subRecipient ne "" );
- Log3 $logDevice, 3,
- "msg $device: "
- . "ID=$msgID.$sentCounter "
- . "TYPE=$type[$i] "
- . "ROUTE=$gatewayDev "
- . "STATUS=$routeStatus "
- . "PRIORITY=$loopPriority "
- . "TITLE='$loopTitle' '$loopMsg'"
- if ( $subRecipient eq "" );
- }
- $msgSent = 2 if ( $msgSent != 1 );
- $msgSentDev = 2 if ( $msgSentDev != 1 );
- $gatewaysStatus{$gatewayDev} = $routeStatus
- if ( $globalDevName ne $gatewayDev );
- $gatewaysStatus{$device} = $routeStatus
- if ( $globalDevName eq $gatewayDev );
- }
- }
- last if ( $msgSentDev == 1 || $msgSentDev == 3 );
- }
- #####################
- # return if we are in routing target test mode
- #
- if ( defined($testMode) && $testMode eq "1" ) {
- Log3 $logDevice, 5,
- "msg $device: "
- . "$type[$i] route check result: ROUTE_AVAILABLE"
- if ( $loopReturn3 eq "" );
- Log3 $logDevice, 5,
- "msg $device: "
- . "$type[$i] route check result: ROUTE_UNAVAILABLE"
- if ( $loopReturn3 ne "" );
- return "ROUTE_AVAILABLE" if ( $loopReturn3 eq "" );
- return "ROUTE_UNAVAILABLE" if ( $loopReturn3 ne "" );
- }
- if ( $catchall == 0 ) {
- if ( !defined( $sentTypesPerDevice{$device} ) ) {
- $sentTypesPerDevice{$device} = "";
- }
- else {
- $sentTypesPerDevice{$device} .= " ";
- }
- $sentTypesPerDevice{$device} .=
- $type[$i] . ":" . $msgSentDev;
- }
- else {
- if ( !defined( $sentTypesPerDevice{$device} ) ) {
- $sentTypesPerDevice{$globalDevName} = "";
- }
- else {
- $sentTypesPerDevice{$globalDevName} .= " ";
- }
- $sentTypesPerDevice{$globalDevName} .=
- $type[$i] . ":" . $msgSentDev;
- }
- # update device readings
- my $readingsDev = $defs{$device};
- $readingsDev = $defs{$globalDevName}
- if ( $catchall == 1 || $deviceType eq "email" );
- readingsBeginUpdate($readingsDev);
- readingsBulkUpdate( $readingsDev, "fhemMsg" . $typeUc,
- $msg );
- readingsBulkUpdate( $readingsDev,
- "fhemMsg" . $typeUc . "Title", $title );
- readingsBulkUpdate( $readingsDev,
- "fhemMsg" . $typeUc . "Prio",
- $loopPriority );
- my $gwStates = "-";
- keys %gatewaysStatus;
- while ( ( my $gwName, my $gwState ) = each %gatewaysStatus )
- {
- $gwStates = "" if $gwStates eq "-";
- $gwStates .= " " if $gwStates ne "-";
- $gwStates .= "$gwName:$gwState";
- }
- readingsBulkUpdate( $readingsDev,
- "fhemMsg" . $typeUc . "Gw", $gwStates );
- readingsBulkUpdate( $readingsDev,
- "fhemMsg" . $typeUc . "State", $msgSentDev );
- # suppress errors when there are still alternatives
- if ( $hasTypeOr == 1
- && $isTypeOr < scalar( grep { defined $_ } @typesOr ) )
- {
- $loopReturn3 = "";
- }
- ################################################################
- ### Implicit forwards based on priority or presence
- ###
- # Skip if typeOr is defined
- # and this is not the last type entry
- if ( $msgSentDev != 3
- && $msgSentDev != 1
- && $hasTypeOr == 1
- && $isTypeOr < scalar( grep { defined $_ } @typesOr ) )
- {
- Log3 $logDevice, 4,
- "msg $device: "
- . "Skipping implicit forward due to typesOr definition";
- # remove recipient from list to avoid
- # other interaction when using recipientOr in parallel
- if ( $hasRecipientOr == 1
- && $isRecipientOr <
- scalar( grep { defined $_ } @recipientsOr ) )
- {
- my $regex1 =
- "\\s*!?@?" . $device . "[,|]"; # at the beginning
- my $regex2 =
- "[,|]!?@?" . $device . "\\s*"; # at the end
- my $regex3 =
- ",!?@?"
- . $device
- . ","; # in the middle with comma
- my $regex4 =
- "[\|,]!?@?"
- . $device
- . "[\|,]"; # in the middle with pipe and/or comma
- $recipients =~ s/^$regex1//;
- $recipients =~ s/$regex2$/|/gi;
- $recipients =~ s/$regex3/,/gi;
- $recipients =~ s/$regex4/|/gi;
- }
- }
- # Skip if recipientOr is defined
- # and this is not the last device entry
- if ( $msgSentDev != 3
- && $msgSentDev != 1
- && $hasRecipientOr == 1
- && $isRecipientOr <
- scalar( grep { defined $_ } @recipientsOr ) )
- {
- Log3 $logDevice, 4,
- "msg $device: "
- . "Skipping implicit forward due to recipientOr definition";
- }
- # Skip if softFail
- elsif ( $msgSentDev != 3 && $msgSentDev != 1 && $softFail )
- {
- Log3 $logDevice, 4,
- "msg $device: Skipping implicit forward";
- $loopReturn3 = "";
- }
- # priority forward thresholds
- #
- ### emergency
- my $msgFwPrioEmergency =
- MSG_FindAttrVal( $device, "msgFwPrioEmergency$typeUc",
- $typeUc, 2 );
- ### absent
- my $msgFwPrioAbsent =
- MSG_FindAttrVal( $device, "msgFwPrioAbsent$typeUc",
- $typeUc, 0 );
- ### gone
- my $msgFwPrioGone =
- MSG_FindAttrVal( $device, "msgFwPrioGone$typeUc",
- $typeUc, 1 );
- my $fw_gwUnavailable =
- defined(
- $settings->{ $type[$i] }{typeEscalation}{gwUnavailable}
- )
- ? $settings->{ $type[$i] }{typeEscalation}{gwUnavailable}
- : "";
- my $fw_emergency =
- defined(
- $settings->{ $type[$i] }{typeEscalation}{emergency} )
- ? $settings->{ $type[$i] }{typeEscalation}{emergency}
- : "";
- my $fw_residentAbsent =
- defined(
- $settings->{ $type[$i] }{typeEscalation}{residentAbsent}
- )
- ? $settings->{ $type[$i] }{typeEscalation}{residentAbsent}
- : "";
- my $fw_residentGone =
- defined(
- $settings->{ $type[$i] }{typeEscalation}{residentGone} )
- ? $settings->{ $type[$i] }{typeEscalation}{residentGone}
- : "";
- # Forward message
- # if no gateway device for this type was available
- if ( $msgSentDev == 0
- && $fw_gwUnavailable ne ""
- && !( grep { $fw_gwUnavailable eq $_ } @type )
- && $routes{$fw_gwUnavailable} == 1 )
- {
- Log3 $logDevice, 4,
- "msg $device: "
- . "Implicit forwards: No $type[$i] gateway device available for recipient $device ($gatewayDevs). Trying alternative message type "
- . $fw_gwUnavailable;
- push @type, $fw_gwUnavailable;
- $forwarded .= "," if ( $forwarded ne "" );
- $forwarded .= $type[$i] . ">" . $fw_gwUnavailable;
- }
- # Forward message
- # if emergency priority
- if ( $loopPriority >= $msgFwPrioEmergency
- && $fw_emergency ne ""
- && !( grep { $fw_emergency eq $_ } @type )
- && $routes{$fw_emergency} == 1 )
- {
- Log3 $logDevice, 4,
- "msg $device: "
- . "Implicit forwards: Escalating high priority $type[$i] message via "
- . $fw_emergency;
- push @type, $fw_emergency;
- $forwarded .= "," if ( $forwarded ne "" );
- $forwarded .= $type[$i] . ">" . $fw_emergency;
- }
- # Forward message
- # if high priority and residents are
- # constantly not at home
- if ( $residentDevPresence eq "absent"
- && $loopPriority >= $msgFwPrioGone
- && $fw_residentGone ne ""
- && !( grep { $fw_residentGone eq $_ } @type )
- && $routes{$fw_residentGone} == 1 )
- {
- Log3 $logDevice, 4,
- "msg $device: "
- . "Implicit forwards: Escalating high priority $type[$i] message via "
- . $fw_residentGone;
- push @type, $fw_residentGone;
- $forwarded .= "," if ( $forwarded ne "" );
- $forwarded .= $type[$i] . ">" . $fw_residentGone;
- }
- # Forward message
- # if priority is normal or higher and residents
- # are not at home but nearby
- if ( !$forceQueue
- && $residentDevState eq "absent"
- && $loopPriority >= $msgFwPrioAbsent
- && $fw_residentAbsent ne ""
- && !( grep { $fw_residentAbsent eq $_ } @type )
- && $routes{$fw_residentAbsent} == 1 )
- {
- Log3 $logDevice, 4,
- "msg $device: "
- . "Implicit forwards: Escalating $type[$i] message via "
- . $fw_residentAbsent
- . " due to absence";
- push @type, $fw_residentAbsent;
- $forwarded .= "," if ( $forwarded ne "" );
- $forwarded .= $type[$i] . ">" . $fw_residentAbsent;
- }
- }
- $loopReturn2 .= $loopReturn3 unless ($softFail);
- last if ( $msgSent == 1 );
- $isTypeOr++;
- }
- $loopReturn1 .= $loopReturn2;
- }
- $return .= $loopReturn1;
- last if ( $msgSent == 1 );
- $isRecipientOr++;
- }
- # finalize device readings
- keys %sentTypesPerDevice;
- while ( ( my $device, my $types ) = each %sentTypesPerDevice ) {
- $device = $globalDevName
- if ( $device =~ /^(([A-Za-z0-9%+._-])+@+([%+a-z0-9A-Z.-]*))$/ );
- readingsBulkUpdate( $defs{$device}, "fhemMsgStateTypes", $types )
- if ( $forwarded eq "" );
- readingsBulkUpdate( $defs{$device}, "fhemMsgStateTypes",
- $types . " forwards:" . $forwarded )
- if ( $forwarded ne "" );
- readingsBulkUpdate( $defs{$device}, "fhemMsgState", $msgSent );
- readingsEndUpdate( $defs{$device}, 1 );
- }
- $return .= "However, message was still sent to some recipients!"
- if ( $msgSent == 1 && $return ne "" );
- $return .=
- "FATAL ERROR: Message NOT sent. No gateway device was available."
- if ( !$softFail && $msgSent == 2 );
- return $return;
- }
- 1;
- =pod
- =item command
- =item summary dynamic routing of messages to FHEM devices and modules
- =item summary_DE dynamisches Routing für Nachrichten an FHEM Geräte und Module
- =begin html
- <a name="MSG"></a>
- <h3>msg</h3>
- <ul>
- <code>msg [<type>] [<@device>|<e-mail address>] [<priority>] [|<title>|] <message></code>
- <br>
- <br>
- No documentation here yet, sorry.<br>
- <a href="http://forum.fhem.de/index.php/topic,39983.0.html">FHEM Forum</a>
- </ul>
- =end html
- =begin html_DE
- <a name="MSG"></a>
- <h3>msg</h3>
- <ul>
- <code>msg [<type>] [<@device>|<e-mail address>] [<priority>] [|<title>|] <message></code>
- <br>
- <br>
- Bisher keine Dokumentation hier, sorry.<br>
- <a href="http://forum.fhem.de/index.php/topic,39983.0.html">FHEM Forum</a>
- </ul>
- =end html_DE
- =cut
|