75_msgConfig.pm 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. ###############################################################################
  2. # $Id: 75_msgConfig.pm 15167 2017-10-01 18:46:23Z loredo $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use Data::Dumper;
  7. # initialize ##################################################################
  8. sub msgConfig_Initialize($) {
  9. my ($hash) = @_;
  10. my $TYPE = "msgConfig";
  11. require "$attr{global}{modpath}/FHEM/msgSchema.pm";
  12. $hash->{DefFn} = $TYPE . "_Define";
  13. $hash->{SetFn} = $TYPE . "_Set";
  14. $hash->{GetFn} = $TYPE . "_Get";
  15. $hash->{UndefFn} = $TYPE . "_Undefine";
  16. $hash->{NotifyFn} = $TYPE . "_Notify";
  17. # add attributes for configuration
  18. no warnings 'qw';
  19. my @attrList = qw(
  20. msgCmdAudio
  21. msgCmdAudioShort
  22. msgCmdAudioShortPrio
  23. msgCmdLight
  24. msgCmdLightHigh
  25. msgCmdLightLow
  26. msgCmdMail
  27. msgCmdMailHigh
  28. msgCmdMailLow
  29. msgCmdPush
  30. msgCmdPushHigh
  31. msgCmdPushLow
  32. msgCmdScreen
  33. msgCmdScreenHigh
  34. msgCmdScreenLow
  35. msgFwPrioAbsentAudio:-2,-1,0,1,2
  36. msgFwPrioAbsentLight:-2,-1,0,1,2
  37. msgFwPrioAbsentScreen:-2,-1,0,1,2
  38. msgFwPrioEmergencyAudio:-2,-1,0,1,2
  39. msgFwPrioEmergencyLight:-2,-1,0,1,2
  40. msgFwPrioEmergencyPush:-2,-1,0,1,2
  41. msgFwPrioEmergencyScreen:-2,-1,0,1,2
  42. msgFwPrioGoneAudio:-2,-1,0,1,2
  43. msgFwPrioGoneLight:-2,-1,0,1,2
  44. msgFwPrioGoneScreen:-2,-1,0,1,2
  45. msgLocationDevs
  46. msgParamsAudio
  47. msgParamsAudioShort
  48. msgParamsAudioShortPrio
  49. msgParamsLight
  50. msgParamsLightHigh
  51. msgParamsLightLow
  52. msgParamsMail
  53. msgParamsMailHigh
  54. msgParamsMailLow
  55. msgParamsPush
  56. msgParamsPushHigh
  57. msgParamsPushLow
  58. msgParamsScreen
  59. msgParamsScreenHigh
  60. msgParamsScreenLow
  61. msgParamsText
  62. msgParamsTextHigh
  63. msgParamsTextLow
  64. msgPriorityAudio:-2,-1,0,1,2
  65. msgPriorityLight:-2,-1,0,1,2
  66. msgPriorityMail:-2,-1,0,1,2
  67. msgPriorityPush:-2,-1,0,1,2
  68. msgPriorityScreen:-2,-1,0,1,2
  69. msgPriorityText:-2,-1,0,1,2
  70. msgRcv:1,0
  71. msgResidentsDev
  72. msgSwitcherDev
  73. msgThPrioHigh:-2,-1,0,1,2
  74. msgThPrioNormal:-2,-1,0,1,2
  75. msgThPrioAudioEmergency:-2,-1,0,1,2
  76. msgThPrioAudioHigh:-2,-1,0,1,2
  77. msgThPrioTextEmergency:-2,-1,0,1,2
  78. msgThPrioTextNormal:-2,-1,0,1,2
  79. msgThPrioGwEmergency:-2,-1,0,1,2
  80. msgTitleAudio
  81. msgTitleAudioShort
  82. msgTitleAudioShortPrio
  83. msgTitleLight
  84. msgTitleLightHigh
  85. msgTitleLightLow
  86. msgTitleMail
  87. msgTitleMailHigh
  88. msgTitleMailLow
  89. msgTitlePush
  90. msgTitlePushHigh
  91. msgTitlePushLow
  92. msgTitleScreen
  93. msgTitleScreenHigh
  94. msgTitleScreenLow
  95. msgTitleText
  96. msgTitleTextHigh
  97. msgTitleTextLow
  98. msgTitleShrtAudio
  99. msgTitleShrtAudioShort
  100. msgTitleShrtAudioShortPrio
  101. msgTitleShrtLight
  102. msgTitleShrtLightHigh
  103. msgTitleShrtLightLow
  104. msgTitleShrtMail
  105. msgTitleShrtMailHigh
  106. msgTitleShrtMailLow
  107. msgTitleShrtPush
  108. msgTitleShrtPushHigh
  109. msgTitleShrtPushLow
  110. msgTitleShrtScreen
  111. msgTitleShrtScreenHigh
  112. msgTitleShrtScreenLow
  113. msgTitleShrtText
  114. msgTitleShrtTextHigh
  115. msgTitleShrtTextLow
  116. );
  117. use warnings 'qw';
  118. $hash->{AttrList} = join( " ", @attrList ) . " " . $readingFnAttributes;
  119. # add global attributes
  120. foreach (
  121. "msgContactAudio",
  122. "msgContactMail",
  123. "msgContactPush",
  124. "msgContactScreen",
  125. "msgContactLight",
  126. "msgParams",
  127. "msgPriority",
  128. "msgRecipient",
  129. "msgRecipientAudio",
  130. "msgRecipientMail",
  131. "msgRecipientPush",
  132. "msgRecipientScreen",
  133. "msgRecipientText",
  134. "msgRecipientLight",
  135. "msgTitle",
  136. "msgTitleShrt",
  137. "msgType:text,push,mail,screen,light,audio,queue",
  138. )
  139. {
  140. addToAttrList($_);
  141. }
  142. }
  143. # regular Fn ##################################################################
  144. sub msgConfig_Define($$) {
  145. my ( $hash, $def ) = @_;
  146. my $TYPE = $hash->{TYPE};
  147. my @a = split( "[ \t]+", $def, 5 );
  148. return "Usage: define <name> $TYPE"
  149. if ( int(@a) < 2 );
  150. my $name = $a[0];
  151. return "Global configuration device already defined: "
  152. . $modules{$TYPE}{defptr}{NAME}
  153. if ( defined( $modules{$TYPE}{defptr} ) );
  154. # create global unique device definition
  155. $modules{$TYPE}{defptr} = $hash;
  156. # set default settings on first define
  157. if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
  158. my $group = AttrVal( "global", "group", "Global" );
  159. my $room = AttrVal( "global", "room", "" );
  160. my $verbose = AttrVal( "global", "verbose", 3 );
  161. $attr{$name}{group} = $group;
  162. $attr{$name}{verbose} = $verbose;
  163. $attr{$name}{room} = $room if ( $room ne "" );
  164. $attr{$name}{comment} = "FHEM Global Configuration for command 'msg'";
  165. $attr{$name}{stateFormat} = "fhemMsgState";
  166. $attr{$name}{msgType} = "text";
  167. readingsBeginUpdate($hash);
  168. readingsBulkUpdate( $hash, "fhemMsgState", "initialized" );
  169. readingsEndUpdate( $hash, 1 );
  170. }
  171. $hash->{NOTIFYDEV} = "TYPE=(Jabber|TelegramBot|yowsup)";
  172. return undef;
  173. }
  174. sub msgConfig_Undefine($$) {
  175. my ( $hash, $name ) = @_;
  176. my $TYPE = $hash->{TYPE};
  177. # release global unique device definition
  178. delete $modules{$TYPE}{defptr};
  179. return undef;
  180. }
  181. sub msgConfig_Set($@) {
  182. my ( $hash, @a ) = @_;
  183. my $name = $hash->{NAME};
  184. my $TYPE = $hash->{TYPE};
  185. shift @a;
  186. my $what = shift @a;
  187. Log3 $name, 5, "$TYPE $name: called function $TYPE" . "_Set()";
  188. my @msgTypes = ( "audio", "light", "mail", "push", "screen", "queue" );
  189. # cleanReadings
  190. if ( lc($what) eq "cleanreadings" ) {
  191. my $device = defined( $a[0] ) ? $a[0] : ".*";
  192. return fhem( "deletereading $device fhemMsg.*", 1 );
  193. }
  194. # addLocation
  195. elsif ( lc($what) eq "addlocation" ) {
  196. my $location = join( " ", @a );
  197. my $group = AttrVal( $name, "group", $TYPE );
  198. my $room = AttrVal( $name, "room", "" );
  199. my $return = "";
  200. return "Missing argument 'location'"
  201. if ( $location eq "" );
  202. my $device = "msgRoom_" . $location;
  203. $device =~ s/[\s\t-]+/_/g;
  204. return "Device $device is already existing but not a dummy device"
  205. if ( IsDevice($device)
  206. && GetType($device) ne "dummy" );
  207. if ( !IsDevice($device) ) {
  208. $return = fhem( "define $device dummy", 1 );
  209. $return .= "Device $device was created"
  210. if ( $return eq "" );
  211. }
  212. else {
  213. $return = "Existing dummy device $device was updated";
  214. }
  215. $attr{$device}{group} = $group if ( !defined( $attr{$device}{group} ) );
  216. $attr{$device}{room} = $room
  217. if ( !defined( $attr{$device}{room} ) && $room ne "" );
  218. $attr{$device}{comment} = "Auto-created by $name"
  219. if ( !defined( $attr{$device}{comment} ) );
  220. $attr{$device}{userattr} .= " msgLocationName"
  221. if ( defined( $attr{$device}{userattr} )
  222. && $attr{$device}{userattr} !~
  223. m/^msgLocationName$|^msgLocationName\s|\smsgLocationName\s|\smsgLocationName$/
  224. );
  225. $attr{$device}{userattr} = "msgLocationName"
  226. if ( !defined( $attr{$device}{userattr} ) );
  227. $attr{$device}{msgLocationName} = $location;
  228. fhem("set $device $location");
  229. $attr{$name}{msgLocationDevs} .= "," . $device
  230. if ( defined( $attr{$name}{msgLocationDevs} )
  231. && $attr{$name}{msgLocationDevs} !~
  232. /^$device\$|^$device,|,$device,|,$device$/ );
  233. $attr{$name}{msgLocationDevs} = $device
  234. if ( !defined( $attr{$name}{msgLocationDevs} ) );
  235. return $return;
  236. }
  237. # createSwitcherDev
  238. elsif ( lc($what) eq "createswitcherdev" ) {
  239. my $device = AttrVal( $name, "msgSwitcherDev", "HouseAnn" );
  240. my $state = AttrVal( $device, "state", "???" );
  241. my $return = "";
  242. my $lang = "en";
  243. $lang = $a[0]
  244. if ( defined( $a[0] ) && $a[0] eq "de" );
  245. return "Device $device is already existing but not a dummy device"
  246. if ( IsDevice($device)
  247. && GetType($device) ne "dummy" );
  248. if ( !IsDevice($device) ) {
  249. $return = fhem( "define $device dummy", 1 );
  250. $return .= "Device $device was created"
  251. if ( $return eq "" );
  252. }
  253. else {
  254. $return = "Existing dummy device $device was updated";
  255. }
  256. if ( $lang eq "de" ) {
  257. $attr{$device}{alias} = "Durchsagen";
  258. $attr{$device}{eventMap} =
  259. "active:aktiv long:lang short:kurz visual:visuell off:aus";
  260. $attr{$device}{room} = "Haus"
  261. if ( !defined( $attr{$device}{room} ) );
  262. $attr{$device}{setList} = "state:lang,kurz,visuell,aus";
  263. }
  264. else {
  265. $attr{$device}{alias} = "Announcements";
  266. $attr{$device}{room} = "House"
  267. if ( !defined( $attr{$device}{room} ) );
  268. $attr{$device}{setList} = "state:long,short,visual,off";
  269. delete $attr{$device}{eventMap}
  270. if ( defined( $attr{$device}{eventMap} ) );
  271. }
  272. $attr{$device}{comment} = "Auto-created by $name"
  273. if ( !defined( $attr{$device}{comment} )
  274. || $attr{$device}{comment} ne "Auto-created by $name" );
  275. $attr{$device}{devStateIcon} =
  276. 'aktiv:general_an@90EE90 active:general_an@90EE90 lang:general_an@green:off long:general_an@green:off aus:general_aus@red:long off:general_aus@red:long kurz:general_an@orange:long short:general_an@orange:long visuell:general_an@orange:long visual:general_an@orange:long';
  277. $attr{$device}{"event-on-change-reading"} = "state"
  278. if ( !defined( $attr{$device}{"event-on-change-reading"} ) );
  279. $attr{$device}{group} = "Automation"
  280. if ( !defined( $attr{$device}{group} ) );
  281. $attr{$device}{icon} = "audio_volume_mid";
  282. $attr{$device}{webCmd} = "state";
  283. fhem("set $device long") if ( $state eq "???" );
  284. $return .=
  285. "\nAttribute msgSwitcherDev at device $name was changed to $device"
  286. if ( defined( $attr{$name}{msgSwitcherDev} ) );
  287. $return .= "\nAdded attribute msgSwitcherDev to device $name"
  288. if ( !defined( $attr{$name}{msgSwitcherDev} ) );
  289. $attr{$name}{msgSwitcherDev} = $device;
  290. return $return;
  291. }
  292. # createResidentsDev
  293. elsif ( lc($what) eq "createresidentsdev" ) {
  294. my $device = AttrVal( $name, "msgResidentsDev", "rgr_Residents" );
  295. my $return = "";
  296. my $lang = defined( $a[0] ) ? uc( $a[0] ) : "EN";
  297. return
  298. "Device $device is already existing but not a RESIDENTS or ROOMMATE device"
  299. if ( IsDevice($device)
  300. && !IsDevice( $device, "RESIDENTS|ROOMMATE" ) );
  301. if ( !IsDevice($device) ) {
  302. $return = fhem( "define $device RESIDENTS", 1 );
  303. $return .= "RESIDENTS device $device was created."
  304. if ( $return eq "" );
  305. }
  306. else {
  307. $return =
  308. "Existing " . GetType($device) . " device $device was updated.";
  309. }
  310. my $txt = fhem("attr $device rgr_lang $lang")
  311. unless ( $lang eq "EN" );
  312. $return .= $txt if ($txt);
  313. $attr{$device}{comment} = "Auto-created by $name"
  314. if ( !defined( $attr{$device}{comment} )
  315. || $attr{$device}{comment} ne "Auto-created by $name" );
  316. $return .=
  317. "\nIf you would like this device to act as an overall presence device for ALL msg commands, please adjust attribute msgResidentsDev at device $name to $device."
  318. if ( defined( $attr{$name}{msgResidentsDev} )
  319. && $attr{$name}{msgResidentsDev} ne $device );
  320. $return .=
  321. "\nNext, set a device's msgResidentsDev attribute to '$device' (think of using 'userattr' to add 'msgResidentsDev' to the list of available attributes). \nIf you would like '$device' to act as an overall presence device for ALL msg commands, sett attribute msgResidentsDev at device $name to $device."
  322. if ( !defined( $attr{$name}{msgResidentsDev} ) );
  323. return $return;
  324. }
  325. else {
  326. return
  327. "Unknown argument $what, choose one of cleanReadings addLocation createSwitcherDev:de,en createResidentsDev:de,en";
  328. }
  329. return undef;
  330. }
  331. sub msgConfig_Get($@) {
  332. my ( $hash, @a ) = @_;
  333. my $name = $hash->{NAME};
  334. my $TYPE = $hash->{TYPE};
  335. shift @a;
  336. my $what = shift @a;
  337. Log3 $name, 5, "$TYPE $name: called function $TYPE" . "_Get()";
  338. my @msgTypes = ( "audio", "light", "mail", "push", "screen" );
  339. # routeCmd
  340. if ( lc($what) eq "routecmd" ) {
  341. my $return = "";
  342. my $msgTypesReq =
  343. defined( $a[0] ) ? lc( $a[0] ) : join( ',', @msgTypes );
  344. my $devicesReq = defined( $a[1] ) ? $a[1] : $name;
  345. my $cmdSchema = msgSchema::get();
  346. my $UserDeviceTypes = "";
  347. foreach my $msgType ( split( /,/, $msgTypesReq ) ) {
  348. # Check device
  349. if ( $devicesReq ne "" ) {
  350. foreach my $device ( split( /,/, $devicesReq ) ) {
  351. if ( IsDevice($device) ) {
  352. $UserDeviceTypes .= "," . GetType($device)
  353. if ( $UserDeviceTypes ne ""
  354. && $msgType ne "mail"
  355. && $device ne $name );
  356. $UserDeviceTypes = GetType($device)
  357. if ( $UserDeviceTypes eq ""
  358. && $msgType ne "mail"
  359. && $device ne $name );
  360. $UserDeviceTypes .= ",fhemMsgMail"
  361. if ( $UserDeviceTypes ne ""
  362. && $msgType eq "mail"
  363. && $device ne $name );
  364. $UserDeviceTypes = "fhemMsgMail"
  365. if ( $UserDeviceTypes eq ""
  366. && $msgType eq "mail"
  367. && $device ne $name );
  368. my $typeUc = ucfirst($msgType);
  369. my @priorities;
  370. @priorities = ( "Normal", "ShortPrio", "Short" )
  371. if ( $msgType eq "audio" );
  372. @priorities = ( "Normal", "High", "Low" )
  373. if ( $msgType ne "audio" );
  374. my $output = 0;
  375. foreach my $prio (@priorities) {
  376. my $priorityCat = "";
  377. $priorityCat = $prio if ( $prio ne "Normal" );
  378. my $cmd = MSG_FindAttrVal( $device,
  379. "msgCmd$typeUc$priorityCat", $typeUc, "" );
  380. next
  381. if ( $cmd eq ""
  382. && $device eq $name
  383. && $output == 0 );
  384. $return .=
  385. uc($msgType)
  386. . ": USER DEFINED COMMANDS WITH PRECEDENCE\n-------------------------------------------------------------------------------\n\n"
  387. if ( $output == 0 );
  388. $return .=
  389. " $device (DEVICE TYPE: "
  390. . GetType($device) . ")\n"
  391. if ( $output == 0 );
  392. $output = 1 if ( $output == 0 );
  393. $return .= " Priority $prio:\n $cmd\n"
  394. if ( $cmd ne "" );
  395. $return .=
  396. " Priority $prio:\n [DEFAULT COMMAND]\n"
  397. if ( $cmd eq "" );
  398. }
  399. $return .= "\n" if ( $return ne "" );
  400. }
  401. }
  402. $return .= "\n" if ( $return ne "" );
  403. }
  404. # Default commands
  405. if ( defined( $cmdSchema->{$msgType} ) ) {
  406. my $deviceTypes = $devicesReq;
  407. $deviceTypes = join( ',', keys %{ $cmdSchema->{$msgType} } )
  408. if ( $deviceTypes eq "" || $devicesReq eq $name );
  409. $deviceTypes = $UserDeviceTypes
  410. if ( $UserDeviceTypes ne "" );
  411. my $outout = 0;
  412. foreach my $deviceType ( split( /,/, $deviceTypes ) ) {
  413. if ( defined( $cmdSchema->{$msgType}{$deviceType} ) ) {
  414. $return .=
  415. uc($msgType)
  416. . ": DEFAULT COMMANDS\n-------------------------------------------------------------------------------\n\n"
  417. if ( $outout == 0 );
  418. $outout = 1;
  419. $return .= " $deviceType\n";
  420. my @priorities;
  421. @priorities = ( "Normal", "ShortPrio", "Short" )
  422. if ( $msgType eq "audio" );
  423. @priorities = ( "Normal", "High", "Low" )
  424. if ( $msgType ne "audio" );
  425. foreach my $prio (@priorities) {
  426. $return .=
  427. " Priority $prio:\n "
  428. . $cmdSchema->{$msgType}{$deviceType}{$prio}
  429. . "\n";
  430. if (
  431. defined(
  432. $cmdSchema->{$msgType}{$deviceType}
  433. {defaultValues}{$prio}
  434. )
  435. )
  436. {
  437. $return .= " Default Values:\n";
  438. foreach my $key (
  439. keys %{
  440. $cmdSchema->{$msgType}{$deviceType}
  441. {defaultValues}{$prio}
  442. }
  443. )
  444. {
  445. if ( $cmdSchema->{$msgType}{$deviceType}
  446. {defaultValues}{$prio}{$key} ne "" )
  447. {
  448. $return .=
  449. " $key = "
  450. . $cmdSchema->{$msgType}{$deviceType}
  451. {defaultValues}{$prio}{$key} . "\n";
  452. }
  453. else {
  454. $return .= " $key = [EMPTY]\n";
  455. }
  456. }
  457. }
  458. }
  459. $return .= "\n" if ( $return ne "" );
  460. }
  461. }
  462. }
  463. else {
  464. $return .= "Unknown messaging type '$msgType'\n"
  465. if ( $msgType ne "text" );
  466. $return .=
  467. "Messaging type 'text' does not have dedicated routing commands. This is a wrapper type to dynamically distinguish between push and mail.\n"
  468. if ( $msgType eq "text" );
  469. }
  470. $return .= "\n" if ( $return ne "" );
  471. }
  472. $return =
  473. "Non-existing device or unknown module messaging schema definition: $devicesReq"
  474. if ( $return eq "" );
  475. return $return;
  476. }
  477. else {
  478. return
  479. "Unknown argument $what, choose one of routeCmd:,audio,light,mail,push,screen,queue";
  480. }
  481. return undef;
  482. }
  483. sub msgConfig_Notify($$) {
  484. my ( $hash, $dev ) = @_;
  485. my $name = $hash->{NAME};
  486. my $TYPE = GetType($name);
  487. my $devName = $dev->{NAME};
  488. my $devType = GetType($devName);
  489. return ""
  490. if ( IsDisabled($name)
  491. or IsDisabled($devName)
  492. or !AttrVal( $devName, "msgRcv", AttrVal( $name, "msgRcv", "1" ) ) );
  493. Log3 $name, 5, "$TYPE $name: called function $TYPE" . "_Notify()";
  494. my @events = @{ deviceEvents( $dev, 1 ) };
  495. return "" unless (@events);
  496. foreach my $event (@events) {
  497. next
  498. unless (
  499. $event =~ m/^(msgText|queryData|((?:OTR)?Last)Message|message)/ );
  500. my ( $sender, $msg );
  501. # TelegramBot
  502. if ( $devType eq "TelegramBot" ) {
  503. if ( $1 eq "msgText" ) {
  504. $sender = ReadingsVal( $devName, "msgPeerId", undef );
  505. $msg = ReadingsVal( $devName, "msgText", undef );
  506. }
  507. elsif ( $1 eq "queryData" ) {
  508. $sender = ReadingsVal( $devName, "queryPeerId", undef );
  509. $msg = ReadingsVal( $devName, "queryData", undef );
  510. }
  511. }
  512. # Jabber
  513. elsif ( $devType eq "Jabber" ) {
  514. ($sender) =
  515. ( ReadingsVal( $devName, $2 . "SenderJID", undef ) =~ m/[^\/]/g );
  516. $msg = ReadingsVal( $devName, $2 . "Message", undef );
  517. }
  518. # yowsup
  519. elsif ( $devType eq "yowsup" ) {
  520. $sender = $devName;
  521. $devName = $modules{yowsup}{defptr}{yowsup}->{NAME};
  522. $msg = ReadingsVal( $devName, "message", undef );
  523. }
  524. next unless ( $msg && $msg ne "" );
  525. unless ( $sender && $sender ne "" ) {
  526. Log3 $name, 5,
  527. "msg: ERROR RCV $devName: "
  528. . "Unable to retrieve sender reference";
  529. next;
  530. }
  531. my $delivered = 0;
  532. foreach my $t ( "push", "screen" ) {
  533. my @contacts = devspec2array(
  534. "msgContact" . ucfirst($t) . "=.*$devName:[@#]*$sender.*" );
  535. if (@contacts) {
  536. foreach (@contacts) {
  537. next unless ( IsDevice($_) );
  538. Log3 $_, 4,
  539. "msg $_: " . "Received $t message from $devName: $msg";
  540. $delivered = 1;
  541. my $recipient = $defs{$_};
  542. readingsBeginUpdate($recipient);
  543. readingsBulkUpdate( $recipient,
  544. "fhemMsgRcv" . ucfirst($t), $msg );
  545. readingsBulkUpdate( $recipient,
  546. "fhemMsgRcv" . ucfirst($t) . "Gw", $devName );
  547. readingsEndUpdate( $recipient, 1 );
  548. }
  549. }
  550. last if ($delivered);
  551. }
  552. unless ($delivered) {
  553. Log3 $name, 4,
  554. "msg: ERROR RCV $devName $sender: "
  555. . "Missing reference in msgContact attribute of any device";
  556. DoTrigger( $name,
  557. "ERROR RCV $devName $sender: "
  558. . "Missing reference in msgContact attribute of any device" );
  559. }
  560. }
  561. return "";
  562. }
  563. # module Fn ####################################################################
  564. sub MSG_FindAttrVal($$$$) {
  565. my ( $d, $n, $msgType, $default ) = @_;
  566. $msgType = "" unless ($msgType);
  567. $msgType = ucfirst($msgType);
  568. $n .= $msgType if ( $n =~ /^msg(Contact)$/ );
  569. my $g = (
  570. (
  571. defined( $modules{msgConfig}{defptr} )
  572. && $n !~ /^(verbose|msgContact.*)$/
  573. )
  574. ? $modules{msgConfig}{defptr}{NAME}
  575. : ""
  576. );
  577. return
  578. # look for direct
  579. AttrVal(
  580. $d, $n,
  581. # look for indirect
  582. AttrVal(
  583. AttrVal( $d, "msgRecipient$msgType", "" ),
  584. $n,
  585. # look for indirect, type-independent
  586. AttrVal(
  587. AttrVal( $d, "msgRecipient", "" ),
  588. $n,
  589. # look for global direct
  590. AttrVal(
  591. $g, $n,
  592. # look for global indirect
  593. AttrVal(
  594. AttrVal( $g, "msgRecipient$msgType", "" ),
  595. $n,
  596. # look for global indirect, type-independent
  597. AttrVal(
  598. AttrVal( $g, "msgRecipient", "" ),
  599. $n,
  600. # default
  601. $default
  602. )
  603. )
  604. )
  605. )
  606. )
  607. );
  608. }
  609. sub msgConfig_FindReadingsVal($$$$) {
  610. my ( $d, $n, $msgType, $default ) = @_;
  611. $msgType = ucfirst($msgType) if ($msgType);
  612. return
  613. # look for direct
  614. ReadingsVal(
  615. $d, $n,
  616. # look for indirect
  617. ReadingsVal(
  618. AttrVal( $d, "msgRecipient$msgType", "" ),
  619. $n,
  620. # look for indirect, type-independent
  621. ReadingsVal(
  622. AttrVal( $d, "msgRecipient", "" ),
  623. $n,
  624. # default
  625. $default
  626. )
  627. )
  628. );
  629. }
  630. sub msgConfig_QueueAdd(@) {
  631. my (
  632. $msgA, $params, $datetime, $msgID,
  633. $minorID, $type, $recipient, $subRecipient,
  634. $termRecipient, $priority, $title, $msg
  635. ) = @_;
  636. my $name = $modules{msgConfig}{defptr}{NAME};
  637. return 0 if ( $defs{$name}{queue}{$recipient}{"$msgID.$minorID"} );
  638. $defs{$name}{queue}{$recipient}{"$msgID.$minorID"} = {
  639. msgOrig => $msgA,
  640. msgOrigParams => $params,
  641. datetime => $datetime,
  642. majorId => $msgID,
  643. minorId => $minorID,
  644. type => $type,
  645. recipient => $recipient,
  646. subRecipient => $subRecipient,
  647. terminalRecipient => $termRecipient,
  648. priority => $priority,
  649. title => $title,
  650. message => $msg,
  651. };
  652. delete $defs{$name}{queue}{$recipient}{"$msgID.$minorID"}{msgOrigParams}
  653. {msgQID};
  654. readingsSingleUpdate(
  655. $defs{$name},
  656. "Q_" . $recipient,
  657. scalar keys %{ $defs{$name}{queue}{$recipient} }, 1
  658. );
  659. return 1;
  660. }
  661. sub msgConfig_QueueReleaseMsgId($$) {
  662. my ( $recipient, $msgID ) = @_;
  663. my $name = $modules{msgConfig}{defptr}{NAME};
  664. return 0
  665. unless ( $defs{$name}{queue}
  666. && $defs{$name}{queue}{$recipient}
  667. && $defs{$name}{queue}{$recipient}{$msgID} );
  668. delete $defs{$name}{queue}{$recipient}{$msgID};
  669. my $c = scalar keys %{ $defs{$name}{queue}{$recipient} };
  670. delete $defs{$name}{queue}{$recipient} unless ($c);
  671. readingsSingleUpdate( $defs{$name}, "Q_" . $recipient, $c, 1 );
  672. return 1;
  673. }
  674. 1;
  675. =pod
  676. =item helper
  677. =item summary global settings and tools for FHEM command <a href="#MSG">msg</a>
  678. =item summary_DE globale Einstellungen und Tools f&uml;r das FHEM Kommando <a href="#MSG">msg</a>
  679. =begin html
  680. <p>
  681. <a name="msgConfig" id="msgConfig"></a>
  682. </p>
  683. <h3>
  684. msgConfig
  685. </h3>
  686. <ul>
  687. Provides global settings and tools for FHEM command <a href="#MSG">msg</a>.<br>
  688. A device named globalMsg will be created automatically when using msg-command for the first time and no msgConfig device could be found.<br>
  689. The device name can be renamed and reconfigured afterwards if desired.<br>
  690. <br>
  691. <a name="msgConfigdefine" id="msgConfigdefine"></a> <b>Define</b>
  692. <ul>
  693. <code>define &lt;name&gt; msgConfig</code><br>
  694. </ul><br>
  695. <br>
  696. <a name="msgConfigset" id="msgConfigset"></a> <b>Set</b>
  697. <ul>
  698. <ul>
  699. <li>
  700. <b>addLocation</b> &nbsp;&nbsp;<Location Name>&nbsp;&nbsp;<br>
  701. Conveniently creates a Dummy device based on the given location name. It will be pre-configured to be used together with location-based routing when using the msg-command. The dummy device will be added to attribute msgLocationDevs automatically. Afterwards additional configuration is required by adding msgContact* or msgRecipient* attributes for gateway devices placed at this specific location.
  702. </li>
  703. <li>
  704. <b>cleanReadings</b> &nbsp;&nbsp;[<device and/or regex>]&nbsp;&nbsp;<br>
  705. Easy way to cleanup all fhemMsg readings. A parameter is optional and can be a concrete device name or mixed together with regex. This command is an alias for "deletereading <device and/or regex> fhemMsg.*".
  706. </li>
  707. <li>
  708. <b>createResidentsDev</b> &nbsp;&nbsp;<de|en>&nbsp;&nbsp;<br>
  709. Creates a new device named rgr_Residents of type <a href="#RESIDENTS">RESIDENTS</a>. It will be pre-configured based on the given language. In case rgr_Residents exists it will be updated based on the given language (basically only a language change). Afterwards next configuration steps will be displayed to use RESIDENTS together with presence-based routing of the msg-command.<br>
  710. This next step is basically to set attribute msgResidentsDevice to refer to this RESIDENTS device either globally or for any other specific FHEM device (most likely you do NOT want to have this attribute set globally as otherwise this will affect ALL devices and therefore ALL msg-commands in your automations).<br>
  711. Note that use of RESIDENTS only makes sense together with ROOMMATE and or GUEST devices which still need to be created manually. See <a href="#RESIDENTSset">RESIDENTS Set commands</a> addRoommate and addGuest respectively.
  712. </li>
  713. <li>
  714. <b>createSwitcherDev</b> &nbsp;&nbsp;<de|en>&nbsp;&nbsp;<br>
  715. Creates a pre-configured Dummy device named HouseAnn and updates globalMsg attribute msgSwitcherDev to refer to it.
  716. </li>
  717. </ul>
  718. </ul>
  719. </ul>
  720. =end html
  721. =begin html_DE
  722. <p>
  723. <a name="msgConfig" id="msgConfig"></a>
  724. </p>
  725. <h3>
  726. msgConfig
  727. </h3>
  728. <ul>
  729. Stellt globale Einstellungen und Tools f&uuml;r das FHEM Kommando <a href="#MSG">msg</a> bereit.<br>
  730. Ein Device mit dem Namen globalMsg wird automatisch bei der ersten Benutzung des msg Kommandos angelegt, sofern kein msgConfig Device gefunden wurde.<br>
  731. Der Device Name kann anschlie&szlig;end beliebig umbenannt und umkonfiguriert werden.<br>
  732. <br>
  733. <a name="msgConfigdefine" id="msgConfigdefine"></a> <b>Define</b>
  734. <ul>
  735. <code>define &lt;name&gt; msgConfig</code><br>
  736. </ul><br>
  737. <br>
  738. <a name="msgConfigset" id="msgConfigset"></a> <b>Set</b>
  739. <ul>
  740. <ul>
  741. <li>
  742. <b>addLocation</b> &nbsp;&nbsp;<Name der Lokation>&nbsp;&nbsp;<br>
  743. Erstellt auf einfache Weise ein Dummy Device basierend auf dem &uuml;bergebenen Lokationsnamen. Es wird for die lokations-basierte Verwendung mit dem msg-Kommando vorkonfiguriert. Das Dummy Device wird automatisch zum Attribut msgLocationDevs hinzugef&uuml;gt. Anschlie&szlig;end ist eine weitere Konfiguration &uuml;ber die Attribute msgContact* oder msgRecipient* notwendig, die auf entsprechende Gateway Devices verweisen, die an dieser Lokation stehen.
  744. </li>
  745. </ul>
  746. </ul>
  747. </ul>
  748. =end html_DE
  749. =cut