95_PostMe.pm 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674
  1. ########################################################################################
  2. #
  3. # PostMe.pm
  4. #
  5. # FHEM module to set up a system of sticky notes, similar to Post-Its
  6. #
  7. # Prof. Dr. Peter A. Henning
  8. #
  9. # $Id: 95_PostMe.pm 16217 2018-02-18 16:25:30Z phenning $
  10. #
  11. # Not named Post-It, which is a trademark of 3M
  12. #
  13. ########################################################################################
  14. #
  15. # This programm is free software; you can redistribute it and/or modify
  16. # it under the terms of the GNU General Public License as published by
  17. # the Free Software Foundation; either version 2 of the License, or
  18. # (at your option) any later version.
  19. #
  20. # The GNU General Public License can be found at
  21. # http://www.gnu.org/copyleft/gpl.html.
  22. # A copy is found in the textfile GPL.txt and important notices to the license
  23. # from the author is found in LICENSE.txt distributed with these scripts.
  24. #
  25. # This script is distributed in the hope that it will be useful,
  26. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  28. # GNU General Public License for more details.
  29. #
  30. ########################################################################################
  31. package main;
  32. use strict;
  33. use warnings;
  34. use vars qw(%defs); # FHEM device/button definitions
  35. use vars qw($FW_RET); # Returned data (html)
  36. use vars qw($FW_RETTYPE); # image/png or the like
  37. use vars qw($FW_wname); # Web instance
  38. use Time::Local;
  39. #########################
  40. # Global variables
  41. my $postmeversion = "2.07";
  42. my $FW_encoding = "UTF-8";
  43. #########################################################################################
  44. #
  45. # PostMe_Initialize
  46. #
  47. # Parameter hash = hash of device addressed
  48. #
  49. #########################################################################################
  50. sub PostMe_Initialize ($) {
  51. my ($hash) = @_;
  52. my $devname = $hash->{NAME};
  53. $hash->{DefFn} = "PostMe_Define";
  54. $hash->{SetFn} = "PostMe_Set";
  55. $hash->{GetFn} = "PostMe_Get";
  56. $hash->{UndefFn} = "PostMe_Undef";
  57. $hash->{InitFn} = "PostMe_Init";
  58. $hash->{AttrFn} = "PostMe_Attr";
  59. $hash->{AttrList} = "postmeTTSFun postmeTTSDev postmeMsgFun postme[0-9]+MsgRec postmeMailFun postme[0-9]+MailRec ".
  60. "postmeStd postmeIcon postmeStyle:test,jQuery,HTML,SVG postmeClick:0,1 listseparator ".$readingFnAttributes;
  61. $hash->{FW_detailFn} = "PostMe_detailFn";
  62. $data{FWEXT}{"/PostMe_widget"}{FUNC} = "PostMe_widget";
  63. $data{FWEXT}{"/PostMe_widget"}{FORKABLE} = 1;
  64. return undef;
  65. }
  66. #########################################################################################
  67. #
  68. # PostMe_Define - Implements DefFn function
  69. #
  70. # Parameter hash = hash of device addressed, def = definition string
  71. #
  72. #########################################################################################
  73. sub PostMe_Define ($$) {
  74. my ($hash, $def) = @_;
  75. my @a = split("[ \t][ \t]*", $def);
  76. my $now = time();
  77. my $devname = $hash->{NAME};
  78. $modules{PostMe}{defptr}{$a[0]} = $hash;
  79. readingsBeginUpdate($hash);
  80. readingsBulkUpdate($hash,"state","Initialized");
  81. readingsEndUpdate($hash,1);
  82. InternalTimer(gettimeofday()+2, "PostMe_Init", $hash,0);
  83. return undef;
  84. }
  85. #########################################################################################
  86. #
  87. # PostMe_Undef - Implements Undef function
  88. #
  89. # Parameter hash = hash of device addressed, def = definition string
  90. #
  91. #########################################################################################
  92. sub PostMe_Undef ($$) {
  93. my ($hash,$arg) = @_;
  94. RemoveInternalTimer($hash);
  95. return undef;
  96. }
  97. #########################################################################################
  98. #
  99. # PostMe_Attr - Implements Attr function
  100. #
  101. # Parameter hash = hash of device addressed, ???
  102. #
  103. #########################################################################################
  104. sub PostMe_Attr($$$) {
  105. my ($cmd, $listname, $attrName, $attrVal) = @_;
  106. return;
  107. }
  108. #########################################################################################
  109. #
  110. # PostMe_Init - Check, if default PostMes have been defined
  111. #
  112. # Parameter hash = hash of device addressed
  113. #
  114. #########################################################################################
  115. sub PostMe_Init($) {
  116. my ($hash) = @_;
  117. my $devname = $hash->{NAME};
  118. my $now = time();
  119. my $err = 0;
  120. #-- current number of PostMes
  121. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  122. my @std = split(',',AttrVal("$devname","postmeStd",""));
  123. for( my $i=0;$i<int(@std);$i++ ){
  124. my $pmn = PostMe_Check($hash,$std[$i]);
  125. if( !$pmn || ($pmn-1)!=$i ){
  126. $err = 1;
  127. Log 1,"[PostMe_Init] PostMe ".$std[$i]." not properly defined";
  128. }
  129. }
  130. #-- no write operation if everything is ok
  131. return undef
  132. if( $err==0 );
  133. #-- must be improved: Enforce first PostMes to be the standard ones
  134. for( my $i=0;$i<int(@std);$i++ ){
  135. PostMe_Create($hash,$std[$i]);
  136. }
  137. readingsSingleUpdate($hash,"state","OK",1);
  138. }
  139. #########################################################################################
  140. #
  141. # PostMe_Check - Check, if a PostMe exists with this name and return its number
  142. #
  143. # Parameter hash = ash of device addressed
  144. # listname = name of PostMe
  145. #
  146. #########################################################################################
  147. sub PostMe_Check($$) {
  148. my ($hash,$listname) = @_;
  149. my $devname = $hash->{NAME};
  150. my ($loop,$res);
  151. #-- current number of PostMes
  152. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  153. for( $loop=1;$loop<=$cnop;$loop++){
  154. $res = ReadingsVal($devname, sprintf("postme%02dName",$loop), undef);
  155. last
  156. if(lc($res) eq lc($listname));
  157. }
  158. #-- no PostMe with this name
  159. if( lc($res) ne lc($listname) ){
  160. return undef;
  161. }else{
  162. return $loop;
  163. }
  164. }
  165. #########################################################################################
  166. #
  167. # PostMe_Create - Create a new PostMe
  168. #
  169. # Parameter hash = hash of device addressed
  170. # listname = name of PostMe
  171. #
  172. #########################################################################################
  173. sub PostMe_Create($$) {
  174. my ($hash,$listname) = @_;
  175. my $devname = $hash->{NAME};
  176. if( PostMe_Check($hash,$listname) ){
  177. my $mga = "Error, a PostMe named $listname does already exist";
  178. Log 1,"[PostMe_Create] $mga";
  179. return "$mga";
  180. }
  181. #-- current number of PostMes
  182. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  183. $cnop++;
  184. readingsBeginUpdate($hash);
  185. readingsBulkUpdate($hash, sprintf("postme%02dName",$cnop),$listname);
  186. readingsBulkUpdate($hash, sprintf("postme%02dCont",$cnop),"");
  187. readingsBulkUpdate($hash, "postmeCnt",$cnop);
  188. readingsEndUpdate($hash,1);
  189. Log3 $devname,3,"[PostMe] Added a new PostMe named $listname";
  190. return undef;
  191. }
  192. #########################################################################################
  193. #
  194. # PostMe_Delete - Delete an existing PostMe
  195. #
  196. # Parameter hash = hash of device addressed
  197. # listname = name of PostMe
  198. #
  199. #########################################################################################
  200. sub PostMe_Delete($$) {
  201. my ($hash,$listname) = @_;
  202. my $devname = $hash->{NAME};
  203. my $loop;
  204. if( index(AttrVal("$devname","postmeStd",""),$listname) != -1){
  205. my $mga = "Error, the PostMe named $listname is a standard PostMe and cannot be deleted";
  206. Log 1,"[PostMe_Delete] $mga";
  207. return "$mga";
  208. }
  209. my $pmn=PostMe_Check($hash,$listname);
  210. if( !$pmn ){
  211. my $mga = "Error, a PostMe named $listname does not exist";
  212. Log 1,"[PostMe_Delete] $mga";
  213. return "$mga";
  214. }
  215. #-- current number of PostMes
  216. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  217. readingsBeginUpdate($hash);
  218. #-- re-ordering
  219. for( $loop=$pmn;$loop<$cnop;$loop++){
  220. readingsBulkUpdate($hash, sprintf("postme%02dName",$loop),
  221. ReadingsVal($devname, sprintf("postme%02dName",$loop+1),""));
  222. readingsBulkUpdate($hash, sprintf("postme%02dCont",$loop),
  223. ReadingsVal($devname, sprintf("postme%02dCont",$loop+1),""));
  224. }
  225. $cnop--;
  226. readingsBulkUpdate($hash, "postmeCnt",$cnop);
  227. readingsEndUpdate($hash,1);
  228. fhem("deletereading $devname ".sprintf("postme%02dName",$cnop+1));
  229. fhem("deletereading $devname ".sprintf("postme%02dCont",$cnop+1));
  230. Log3 $devname,3,"[PostMe] Deleted PostMe named $listname";
  231. return undef;
  232. }
  233. #########################################################################################
  234. #
  235. # PostMe_Rename - Renames an existing PostMe
  236. #
  237. # Parameter hash = hash of device addressed
  238. # listname = name of PostMe
  239. # newname = newname of PostMe
  240. #
  241. #########################################################################################
  242. sub PostMe_Rename($$$) {
  243. my ($hash,$listname,$newname) = @_;
  244. my $devname = $hash->{NAME};
  245. my $loop;
  246. if( index(AttrVal("$devname","postmeStd",""),$listname) != -1){
  247. my $mga = "Error, the PostMe named $listname is a standard PostMe and cannot be renamed";
  248. Log 1,"[PostMe_Rename] $mga";
  249. return "$mga";
  250. }
  251. my $pmn=PostMe_Check($hash,$listname);
  252. if( !$pmn ){
  253. my $mga = "Error, a PostMe named $listname does not exist";
  254. Log 1,"[PostMe_Rename] $mga";
  255. return "$mga";
  256. }
  257. my $pnn=PostMe_Check($hash,$newname);
  258. if( $pnn ){
  259. my $mga = "Error, a PostMe named $newname does already exist and is not empty";
  260. Log 1,"[PostMe_Rename] $mga";
  261. return "$mga";
  262. }
  263. readingsSingleUpdate($hash,sprintf("postme%02dName",$pmn),$newname,1);
  264. Log3 $devname,3,"[PostMe] Renamed PostMe named $listname into $newname";
  265. return undef;
  266. }
  267. #########################################################################################
  268. #
  269. # PostMe_Add - Add something to a PostMe
  270. #
  271. # Parameter hash = hash of device addressed
  272. #
  273. #########################################################################################
  274. sub PostMe_Add($$@) {
  275. my ($hash,$listname,@args) = @_;
  276. my $devname = $hash->{NAME};
  277. my $pmn=PostMe_Check($hash,$listname);
  278. if( !$pmn ){
  279. my $mga = "Error, a PostMe named $listname does not exist";
  280. Log 1,"[PostMe_Add] $mga";
  281. return "$mga";
  282. }
  283. my $raw = join(' ',@args);
  284. #-- remove meta data
  285. my $item = $raw;
  286. $item =~ s/\[.*\]//g;
  287. $item =~ s/\]//g;
  288. $item =~ s/\[//g;
  289. #-- safety catch: No action when item empty
  290. if( $item eq "" ){
  291. my $mga = "Error, empty item given";
  292. Log 1,"[PostMe_Add] $mga";
  293. return "$mga";
  294. }
  295. #-- check old content
  296. my $old = ReadingsVal($devname, sprintf("postme%02dCont",$pmn),"");
  297. my $ind = index($old,$item);
  298. if( $ind >= 0 ){
  299. my $mga = "Error, item $item is already present in PostMe $listname";
  300. Log 1,"[PostMe_Add] $mga";
  301. return "$mga";
  302. }
  303. $old .= AttrVal($devname,"listseparator",',')
  304. if($old ne "");
  305. #-- TODO: META DATA MISSING
  306. readingsSingleUpdate($hash, sprintf("postme%02dCont",$pmn),$old.$item,1);
  307. Log3 $devname,3,"[Postme] Added item $item to PostMe named $listname";
  308. return undef;
  309. }
  310. #########################################################################################
  311. #
  312. # PostMe_Remove - Remove something from a PostMe
  313. #
  314. # Parameter hash = hash of device addressed
  315. #
  316. #########################################################################################
  317. sub PostMe_Remove($$@) {
  318. my ($hash,$listname,@args) = @_;
  319. my $devname = $hash->{NAME};
  320. my $pmn=PostMe_Check($hash,$listname);
  321. if( !$pmn ){
  322. my $mga = "Error, a PostMe named $listname does not exist";
  323. Log 1,"[PostMe_Remove] $mga";
  324. return "$mga";
  325. }
  326. my $raw = join(' ',@args);
  327. my $listsep = AttrVal($devname,"listseparator",',');
  328. #-- remove meta data
  329. my $item = $raw;
  330. $item =~ s/\[.*\]//g;
  331. #-- safety catch: No action when item empty
  332. if( $item eq "" ){
  333. my $mga = "Error, empty item given";
  334. Log 1,"[PostMe_Remove] $mga";
  335. return "$mga";
  336. }
  337. #-- get old content
  338. my $new = "";
  339. my $old = ReadingsVal($devname, sprintf("postme%02dCont",$pmn),"");
  340. my @lines= split($listsep,$old);
  341. #-- item may be of type item\d\d
  342. if( $item =~ /item(\d+)/ ){
  343. $item = $lines[$1];
  344. }
  345. #-- check old content
  346. my $ind = index($old,$item);
  347. if( $ind < 0 ){
  348. my $mga = "Error, item $item is not present in PostMe $listname";
  349. Log 1,"[PostMe_Remove] $mga";
  350. return "$mga";
  351. }
  352. #-- item may be a short version of the real entry
  353. for( my $loop=0;$loop<int(@lines);$loop++){
  354. $ind = index($lines[$loop],$item);
  355. #-- cleanup reminders
  356. if( $ind >= 0 ){
  357. my $line = $lines[$loop];
  358. my $itex = $line;
  359. my $meta = $line;
  360. $itex =~ s/\s*\[.*//;
  361. #-- only if attributes present
  362. if( $line =~ /.*\[.*\].*/){
  363. $meta =~ s/.*\[//;
  364. $meta =~ s/\]//;
  365. my @lines2 = split('" ',$meta);
  366. for( my $loop2=0;$loop2<int(@lines2);$loop2++){
  367. my $attr = $lines2[$loop2];
  368. $attr =~ /(.*)="(.*)/;
  369. $attr = $1;
  370. my $val = $2;
  371. PostMe_cleanSpecial($hash,$listname,$itex,$attr);
  372. }
  373. }
  374. #-- different item
  375. }else{
  376. $new .= $lines[$loop].$listsep;
  377. }
  378. }
  379. $new =~ s/$listsep$listsep/$listsep/;
  380. $new =~ s/^$listsep//;
  381. $new =~ s/$listsep$//;
  382. readingsSingleUpdate($hash, sprintf("postme%02dCont",$pmn),$new,1);
  383. Log3 $devname,3,"[Postme] Removed item $item from PostMe named $listname";
  384. return undef;
  385. }
  386. #########################################################################################
  387. #
  388. # PostMe_Clear - clear a PostMe
  389. #
  390. # Parameter hash = hash of device addressed
  391. # name = name of PostMe
  392. #
  393. #########################################################################################
  394. sub PostMe_Clear($$) {
  395. my ($hash,$listname) = @_;
  396. my $devname = $hash->{NAME};
  397. my $pmn=PostMe_Check($hash,$listname);
  398. if( !$pmn ){
  399. my $mga = "Error, a PostMe named $listname does not exist";
  400. Log 1,"[PostMe_Clear] $mga";
  401. return "$mga";
  402. }
  403. PostMe_Special($hash,$listname,1);
  404. readingsSingleUpdate($hash, sprintf("postme%02dCont",$pmn),"",1 );
  405. Log3 $devname,3,"[PostMe_Clear] Cleared PostMe named $listname";
  406. return undef;
  407. }
  408. #########################################################################################
  409. #
  410. # PostMe_Modify - Annotate an item from a PostMe with meta data
  411. #
  412. # Parameter hash = hash of device addressed
  413. #
  414. #########################################################################################
  415. sub PostMe_Modify($$@) {
  416. my ($hash,$listname,@args) = @_;
  417. my $devname = $hash->{NAME};
  418. my $pmn=PostMe_Check($hash,$listname);
  419. if( !$pmn ){
  420. my $mga = "Error, a PostMe named $listname does not exist";
  421. Log 1,"[PostMe_Remove] $mga";
  422. return "$mga";
  423. }
  424. my $listsep = AttrVal($devname,"listseparator",',');
  425. #-- difficult to separate item from new meta data. For now, first term is the item,
  426. # second term is the attribute and remaining terms are the value
  427. my $item = $args[0];
  428. my $attr = $args[1];
  429. splice(@args,0,2);
  430. my $val = join(' ',@args);
  431. #-- safety catch: No action when item empty
  432. if( $item eq "" ){
  433. my $mga = "Error, empty item given";
  434. Log 1,"[PostMe_Modify] $mga";
  435. return "$mga";
  436. }
  437. #-- check old content
  438. my $old = ReadingsVal($devname, sprintf("postme%02dCont",$pmn),"");
  439. my $ind = index($old,$item);
  440. if( $ind < 0 ){
  441. my $mga = "Error, item $item is not present in PostMe $listname";
  442. Log 1,"[PostMe_Remove] $mga";
  443. return "$mga";
  444. }
  445. #-- item
  446. my @lines = split($listsep,$old);
  447. my $new = "";
  448. for( my $loop=0;$loop<int(@lines);$loop++){
  449. $old = $lines[$loop];
  450. $ind = index($old,$item);
  451. #-- different item
  452. if( $ind < 0 ){
  453. $new .= $old.$listsep;
  454. #-- correct item
  455. }elsif( $ind == 0 ){
  456. #-- item may be a short version of the real entry, or may consist of several words
  457. my $fullitem = $old;
  458. $fullitem =~ s/\s*\[.*//;
  459. $item = $fullitem
  460. if( $fullitem ne $item );
  461. $new .= $item.' [';
  462. #-- no attributes present so far
  463. if( ($old !~ /.*\[.*\].*/) && ($val) ){
  464. #PostMe_cleanSpecial($hash,$listname,$item,$attr);
  465. PostMe_procSpecial($hash,$listname,$item,$attr,$val);
  466. $new .= $attr.'="'.$val.'"';
  467. #-- attributes present already
  468. }else{
  469. $old =~ s/.*\[//;
  470. $old =~ s/\]//;
  471. #-- particular attribute not yet present
  472. if( index($old,$attr) < 0){
  473. if( $val ){
  474. #PostMe_cleanSpecial($hash,$listname,$item,$attr);
  475. PostMe_procSpecial($hash,$listname,$item,$attr,$val);
  476. $new .= $old.' '.$attr.'="'.$val.'"'
  477. }
  478. #-- particular attribute already present
  479. }else{
  480. my @lines2 = split('" ',$old);
  481. for( my $loop2=0;$loop2<int(@lines2);$loop2++){
  482. my $ind2 = index($lines2[$loop2],$attr);
  483. #-- different attribute
  484. if( $ind2 < 0){
  485. $new .= $lines2[$loop2].'" ';
  486. #-- correct attribute
  487. }else{
  488. #-- overwrite, if val ist given
  489. if( $val ){
  490. PostMe_cleanSpecial($hash,$listname,$item,$attr);
  491. PostMe_procSpecial($hash,$listname,$item,$attr,$val);
  492. $new .= $attr.'="'.$val.'" ';
  493. #-- remove, if no val is given
  494. }
  495. }
  496. }
  497. }
  498. }
  499. $new .= ']'.$listsep;
  500. }
  501. }
  502. #-- correction of sloppy formatting above
  503. $new =~ s/\s\[\]//g;
  504. $new =~ s/\s\]/\]/g;
  505. $new =~ s/\[\s/\[/g;
  506. $new =~ s/""/"/g;
  507. $new =~ s/$listsep$//g;
  508. readingsSingleUpdate($hash, sprintf("postme%02dCont",$pmn),$new,1);
  509. Log3 $devname,3,"[Postme] Modified item $item in PostMe named $listname";
  510. return undef;
  511. }
  512. ########################################################################################
  513. #
  514. # PostMe_Special - process all special annotations of a PostMe
  515. #
  516. # Parameter hash = hash of device addressed
  517. # listanem = name of the PostMe
  518. # clean = 0 normal processing, = 1 clean all reminders
  519. #
  520. #########################################################################################
  521. sub PostMe_Special($$$) {
  522. my ($hash,$listname,$clean) = @_;
  523. my $devname = $hash->{NAME};
  524. my $pmn=PostMe_Check($hash,$listname);
  525. if( !$pmn ){
  526. my $mga = "Error, a PostMe named $listname does not exist";
  527. Log 1,"[PostMe_Special] $mga";
  528. return "$mga";
  529. }
  530. my $listsep = AttrVal($devname,"listseparator",',');
  531. #-- check content
  532. my $cont = ReadingsVal($devname, sprintf("postme%02dCont",$pmn),"");
  533. #-- item
  534. my @lines = split($listsep,$cont);
  535. for( my $loop=0;$loop<int(@lines);$loop++){
  536. my $line = $lines[$loop];
  537. my $item = $line;
  538. my $meta = $line;
  539. $item =~ s/\s*\[.*//;
  540. #-- only if attributes present
  541. if( $line =~ /.*\[.*\].*/){
  542. $meta =~ s/.*\[//;
  543. $meta =~ s/\]//;
  544. my @lines2 = split('" ',$meta);
  545. for( my $loop2=0;$loop2<int(@lines2);$loop2++){
  546. my $attr = $lines2[$loop2];
  547. $attr =~ /(.*)="(.*)/;
  548. $attr = $1;
  549. my $val = $2;
  550. PostMe_cleanSpecial($hash,$listname,$item,$attr);
  551. PostMe_procSpecial($hash,$listname,$item,$attr,$val)
  552. if( $clean==0 );
  553. }
  554. }
  555. }
  556. }
  557. #########################################################################################
  558. #
  559. # PostMe_procSpecial - process special annotations
  560. # Parameter hash = hash of device addressed
  561. # name = name of the PostMe
  562. # item = item content
  563. # attr = attribute name
  564. # val = attribute value
  565. #
  566. #########################################################################################
  567. sub PostMe_procSpecial($$$$$){
  568. my($hash,$listname,$item,$attr,$val) =@_;
  569. my $devname=$hash->{NAME};
  570. #-- get the number of this list
  571. my $pmn = PostMe_Check($hash,$listname);
  572. if( !$pmn ){
  573. my $mga = "Error, a PostMe named $listname does not exist";
  574. Log 1,"[PostMe_procSpecial] $mga";
  575. return "$mga";
  576. }
  577. if( $attr eq "at" ){
  578. my ($timeraw,$year,$mon,$day,$hour,$min,$sec,$delta,$deltah,$deltam,$repeat);
  579. my ($secn,$minn,$hourn,$dayn,$monn,$yearn) = localtime(time);
  580. my $str = "{";
  581. if( $val =~ /((\d\d\:\d\d)|(\d\d\:\d\d\:\d\d)|(\d\d\d\d-\d\d-\d\dT\d\d\:\d\d\:\d\d))(\-(\d\d:\d\d)(P(\d+))?)/ ){
  582. $timeraw = $1;
  583. $delta = $6;
  584. $repeat = ($8)?$8:1;
  585. $timeraw =~ /((\d\d\d\d)-(\d\d)-(\d\d)T)?(\d\d)\:(\d\d)\:?(\d\d)?/;
  586. #($year,$mon,$day,$hour,$min,$sec) = ($2,$3-1,$4,$5,$6,$7);
  587. $year =($2)?$2 : $yearn+1900;
  588. $mon =($3)?$3-1: $monn;
  589. $mon = ( ($mon>=0)&&($mon<=11) )? $mon:0;
  590. $day =($4)?$4 : $dayn;
  591. $day = ( ($day>=1)&&($day<=31) )? $day:0;
  592. $hour =($5)?$5 : $hourn;
  593. $hour = ( ($hour>=0)&&($hour<=23) )? $hour:0;
  594. $min =($6)?$6 : $minn;
  595. $min = ( ($min>=0)&&($min<=59) )? $min:0;
  596. $sec =($7)?$7 : "00";
  597. $sec = ( ($sec>=0)&&($sec<=59) )? $sec:0;
  598. $delta =~ /(\d\d):(\d\d)/;
  599. ($deltah,$deltam)=($1,$2);
  600. my $deltas = min(3600*$deltah+60*$deltam,86400);
  601. $repeat = ( ($repeat>=0)&&($repeat<=10) )? $repeat:0;
  602. my $ftime = timelocal($sec,$min,$hour,$day,$mon,$year);
  603. my $ftimel= localtime($ftime);
  604. #-- determine send strings
  605. my $mrcpt = AttrVal($devname,sprintf("postme%02dMailRec",$pmn),undef);
  606. my $mfun = AttrVal($devname,"postmeMailFun",undef);
  607. if( $mrcpt && $mfun ){
  608. $str .= "$mfun('$mrcpt','$listname','$item => $ftimel');;";
  609. }
  610. my $trcpt = AttrVal($devname,sprintf("postme%02dMsgRec",$pmn),undef);
  611. my $tfun = AttrVal($devname,"postmeMsgFun",undef);
  612. if( $trcpt && $tfun ){
  613. $str .= "$tfun('$trcpt','$listname','$item => $ftimel');;";
  614. }
  615. $str .="}";
  616. #-- define name for timer
  617. my $safename = PostMe_safeItem($hash,$listname,$item,"at");
  618. fhem("define ".$safename."_00 at $ftime $str");
  619. fhem("attr ".$safename."_00 room hidden");
  620. if( $delta ){
  621. for(my $i=1;$i<=$repeat;$i++){
  622. my $stime = $ftime-$i*$deltas;
  623. my $sname = $safename.sprintf("_%02d",$i);
  624. fhem("define ".$sname." at $stime $str");
  625. fhem("attr ".$sname." room hidden");
  626. }
  627. }
  628. }
  629. }elsif( $attr eq "notify" ){
  630. return
  631. if( !$val);
  632. my $str = "{";
  633. #-- determine send strings
  634. my $mrcpt = AttrVal($devname,sprintf("postme%02dMailRec",$pmn),undef);
  635. my $mfun = AttrVal($devname,"postmeMailFun",undef);
  636. if( $mrcpt && $mfun ){
  637. $str .= "$mfun('$mrcpt','$listname','$item');;";
  638. }
  639. my $trcpt = AttrVal($devname,sprintf("postme%02dMsgRec",$pmn),undef);
  640. my $tfun = AttrVal($devname,"postmeMsgFun",undef);
  641. if( $trcpt && $tfun ){
  642. $str .= "$tfun('$trcpt','$listname','$item');;";
  643. }
  644. $str .="}";
  645. #-- define name for notify
  646. my $safename = PostMe_safeItem($hash,$listname,$item,"notify");
  647. fhem("define ".$safename." notify $val $str");
  648. fhem("attr ".$safename." room hidden");
  649. }
  650. }
  651. #########################################################################################
  652. #
  653. # PostMe_cleanSpecial - process special annotations by cleaning leftover procedures
  654. # Parameter hash = hash of device addressed
  655. # name = name of the PostMe
  656. # item = item content
  657. # attr = attribute name
  658. #
  659. #########################################################################################
  660. sub PostMe_cleanSpecial($$$$){
  661. my($hash,$listname,$item,$attr) =@_;
  662. my $devname=$hash->{NAME};
  663. if( $attr eq "at" ){
  664. #-- define name for timer
  665. my $safename = PostMe_safeItem($hash,$listname,$item,"at");
  666. fhem("delete ".$safename.".*");
  667. }elsif( $attr eq "notify" ){
  668. #-- define name for notify
  669. my $safename = PostMe_safeItem($hash,$listname,$item,"notify");
  670. fhem("delete ".$safename.".*");
  671. }
  672. }
  673. #########################################################################################
  674. #
  675. # PostMe_safeItem - transform an item content into a FHEM name
  676. # Parameter hash = hash of device addressed
  677. # name = name of the PostMe
  678. # item = item content
  679. # attr = attribute name
  680. #
  681. #########################################################################################
  682. sub PostMe_safeItem($$$$){
  683. my($hash,$listname,$item,$attr) =@_;
  684. my $devname=$hash->{NAME};
  685. my $safeitem=join('_',split(' ',$item));
  686. $safeitem = substr($safeitem,0,4);
  687. $safeitem =~ tr/äöüÄÖÜß'/a_o_u_A_O_U_S__/;
  688. my $safelist=join('_',split(' ',$listname));
  689. $safelist = substr($safelist,0,4);
  690. $safelist =~ tr/äöüÄÖÜß'/a_o_u_A_O_U_S__/;
  691. my $safeattr = substr($attr,0,2);
  692. return $devname."rem_".$safelist."_".$safeitem."_".$safeattr;
  693. }
  694. #########################################################################################
  695. #
  696. # PostMe_LineIn - format a single PostMe line from input
  697. #
  698. # Parameter hash = hash of device addressed
  699. # line = raw data in the form item [att1="val1" att2="val2"]
  700. #
  701. #########################################################################################
  702. sub PostMe_LineIn($$) {
  703. my ($hash,$line) = @_;
  704. my $devname = $hash->{NAME};
  705. }
  706. #########################################################################################
  707. #
  708. # PostMe_LineOut - format a single PostMe line for output
  709. #
  710. # Parameter line = raw data in the form item [att1="val1" att2="val2"]
  711. # (multiple items separated by comma)
  712. # format = 0 - item only
  713. #
  714. #########################################################################################
  715. sub PostMe_LineOut($$$$) {
  716. my ($hash,$listname,$line,$format) = @_;
  717. my $devname = $hash->{NAME};
  718. my ($i,$line2,$item,$meat,$new,@lines,%meta);
  719. #Log 1,"LINEOUT format = $format, line=$line";
  720. #-- format == 0 - single item line
  721. if( $format < 10){
  722. $item = $line;
  723. $item =~ s/\s+\[.*//;
  724. $line =~ s/.*\[//;
  725. $line =~ s/\]//;
  726. my @list1 = split(/ /,$line);
  727. foreach my $item2(@list1) {
  728. my ($i,$j)= split(/=/, $item2);
  729. $meta{$i} = $j;
  730. }
  731. #Log 1,"line=$line, item=$item";
  732. return $item;
  733. #-- formats >= 10 for all items in a PostMe
  734. }elsif( $format >= 10){
  735. my $listsep = AttrVal($devname,"listseparator",',');
  736. my @lines = split($listsep,$line);
  737. #-- format 13, return array
  738. return \@lines
  739. if( $format==14 );
  740. my $new = "";
  741. my $item;
  742. my $meat;
  743. for( my $loop=0;$loop<int(@lines);$loop++){
  744. $line2 = $lines[$loop];
  745. $i = index($line2,'[');
  746. if( $i >=0 ){
  747. $item = substr($line2,0,$i);
  748. $meat = substr($line2,$i);
  749. $item =~ s/\s*$//;
  750. $meat =~ s/.*\[//;
  751. $meat =~ s/\]//;
  752. my @list1 = split('" ',$meat);
  753. foreach my $item2(@list1) {
  754. my ($i,$j)= split(/=/, $item2);
  755. $j =~ s/^"//;
  756. $meta{$i} = $j;
  757. #Log 1,"Setting META $i to VALUE $j";
  758. }
  759. }else{
  760. $item = $line2;
  761. $meat = "";
  762. $item =~ s/\s*$//;
  763. }
  764. #-- format 10: plain format, item only
  765. $new .= $item.','
  766. if( $format == 10);
  767. #-- format 11: meta data in brackets
  768. if( $format == 11){
  769. if( $meat ne "" ){
  770. $new .= $item.'('.$meat.'),';
  771. }else{
  772. $new .= $item.',';
  773. }
  774. }
  775. #-- format 13: Telegram format item w indexing
  776. $new .= '('.$item.sprintf(':%sitem%02d) ',$listname,$loop)
  777. if( $format == 13);
  778. #-- json format by hand
  779. if( $format == 15 ){
  780. $new .= '{"item": "'.$item.'"';
  781. if( $meat ne "" ){
  782. $new .= ',"meta": {';
  783. foreach my $k (keys %meta){
  784. $new .= '"'.$k.'": "'.$meta{$k}.'",';
  785. }
  786. $new .= '}';
  787. }
  788. $new .= '},';
  789. }
  790. }
  791. $new =~ s/""/"/g;
  792. $new =~ s/,}/}/g;
  793. $new =~ s/,$//;
  794. return $new;
  795. }
  796. }
  797. #########################################################################################
  798. #
  799. # PostMe_tgi - format a single PostMe as inline keyboard for telegram (items w. indexing)
  800. #
  801. # Parameter devname = device name
  802. # listname = list name
  803. #
  804. #########################################################################################
  805. sub PostMe_tgi($$) {
  806. my ($devname,$listname) = @_;
  807. my $pmn;
  808. my $res = "";
  809. my $hash = $defs{$devname};
  810. if( !$hash ){
  811. my $mga = "Error, a PostMe device named $devname does not exist";
  812. Log 1,"[PostMe_tgi] $mga";
  813. return "$mga";
  814. }
  815. #Log 1,"[PostMe_Get] with name=$listname key=$key args=@args";
  816. $pmn = PostMe_Check($hash,$listname);
  817. if( !$pmn ){
  818. my $mga = "Error, a PostMe named $listname does not exist";
  819. Log 1,"[PostMe_tgi] $mga";
  820. return "$mga";
  821. }
  822. $res = PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""),13);
  823. $res.= " ".$listname;
  824. return $res;
  825. }
  826. #########################################################################################
  827. #
  828. # PostMe_tgj - format a single PostMe as simple array
  829. #
  830. # Parameter devname = device name
  831. # listname = list name
  832. #
  833. ###########################################################################k##############
  834. sub PostMe_tgj($$) {
  835. my ($devname,$listname) = @_;
  836. my $pmn;
  837. my $hash = $defs{$devname};
  838. if( !$hash ){
  839. my $mga = "Error, a PostMe device named $devname does not exist";
  840. Log 1,"[PostMe_tgk] $mga";
  841. return "$mga";
  842. }
  843. #Log 1,"[PostMe_Get] with name=$listname key=$key args=@args";
  844. $pmn = PostMe_Check($hash,$listname);
  845. if( !$pmn ){
  846. my $mga = "Error, a PostMe named $listname does not exist";
  847. Log 1,"[PostMe_tgk] $mga";
  848. return "$mga";
  849. }
  850. my @ret=PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""),14);
  851. return \@ret;
  852. }
  853. #########################################################################################
  854. #
  855. # PostMe_Set - Implements the Set function
  856. #
  857. # Parameter hash = hash of device addressed
  858. #
  859. #########################################################################################
  860. sub PostMe_Set($@) {
  861. my ( $hash, $devname, $key, @args ) = @_;
  862. #-- for the selector: which values are possible
  863. if ($key eq "?"){
  864. #--prevent any default set
  865. return undef;
  866. #-- obsolete
  867. my @cmds = ("create","delete","rename","add","modify","remove","clear");
  868. return "Unknown argument $key, choose one of " .join(" ",@cmds);
  869. }
  870. my $listname = shift @args;
  871. if( $key eq "create"){
  872. PostMe_Create($hash,$listname);
  873. }elsif( $key eq "delete"){
  874. PostMe_Delete($hash,$listname);
  875. }elsif( $key eq "rename"){
  876. PostMe_Rename($hash,$listname,@args[0]);
  877. }elsif( $key eq "add"){
  878. PostMe_Add($hash,$listname,@args);
  879. }elsif( $key eq "modify"){
  880. PostMe_Modify($hash,$listname,@args);
  881. }elsif( $key eq "remove"){
  882. PostMe_Remove($hash,$listname,@args);
  883. }elsif( $key eq "clear"){
  884. PostMe_Clear($hash,$listname);
  885. }
  886. }
  887. #########################################################################################
  888. #
  889. # PostMe_Get - Implements the Get function
  890. #
  891. # Parameter hash = hash of device addressed
  892. #
  893. #########################################################################################
  894. sub PostMe_Get($$$@) {
  895. my ($hash, $devname, $key, @args) = @_;
  896. my $pmn;
  897. my $res = "";
  898. my $hasMail = defined(AttrVal($devname,"postmeMailFun",undef)) ? 1 : 0;
  899. my $hasMsgr = defined(AttrVal($devname,"postmeMsgFun",undef)) ? 1 : 0;
  900. my $hasTTS = defined(AttrVal($devname,"postmeTTSFun",undef)) ? 1 : 0;
  901. #-- for the selector: which values are possible
  902. if ($key eq "?"){
  903. #-- prevent any default get
  904. return undef;
  905. #-- obsolete
  906. #-- current number of PostMes
  907. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  908. my $pml = "";
  909. for( my $i=1;$i<=$cnop;$i++){
  910. $pml .= ","
  911. if( $i >1);
  912. $pml .= ReadingsVal($devname, sprintf("postme%02dName",$i),"");
  913. }
  914. my @cmds = ("version:noArg","all:noArg","allspecial","list:".$pml,"special:".$pml);
  915. $res = "Unknown argument $key choose one of ".join(" ",@cmds);
  916. $res.= " mail:".$pml
  917. if($hasMail);
  918. $res.= " message:".$pml
  919. if($hasMsgr);
  920. $res.= " TTS:".$pml
  921. if($hasTTS);
  922. $res.= " JSON:".$pml;
  923. return $res;
  924. }
  925. my $listname = @args[0];
  926. if ($key eq "version") {
  927. return "PostMe.version => $postmeversion";
  928. #-- list one PostMe
  929. } elsif( ($key eq "list")||($key eq "special")||($key eq "JSON")||($key eq "mail")||($key eq "message")||($key eq "TTS") ){
  930. $pmn = PostMe_Check($hash,$listname);
  931. if( !$pmn ){
  932. my $mga = "Error, a PostMe named $listname does not exist";
  933. Log 1,"[PostMe_Get] $mga";
  934. return "$mga";
  935. }
  936. ##-- list
  937. if( $key eq "list" ){
  938. $res = ReadingsVal($devname, sprintf("postme%02dName",$pmn),"");
  939. $res .= ": ";
  940. $res .= PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),"")."\n",10);
  941. return $res;
  942. ##-- list
  943. }elsif( $key eq "special" ){
  944. PostMe_Special($hash,$listname,0);
  945. ##-- JSON
  946. }elsif( $key eq "JSON" ){
  947. $res = PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""),15);
  948. return '{"'.$listname.'": ['.$res.']}';
  949. ##-- send by mail
  950. }elsif( $key eq "mail" ){
  951. my $rcpt = AttrVal($devname,sprintf("postme%02dMailRec",$pmn),undef);
  952. my $text = PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),undef),11);
  953. my $fun = AttrVal($devname,"postmeMailFun",undef);
  954. if( $rcpt && $text && $fun ){
  955. my $ref = \&$fun;
  956. &$ref($rcpt,$listname,$text);
  957. }
  958. my $mga = "$listname sent by mail";
  959. readingsSingleUpdate($hash,"state",$mga,1 );
  960. Log3 $devname,3,"[PostMe] ".$mga;
  961. return undef;
  962. ##-- send by instant messenger
  963. }elsif( $key eq "message" ){
  964. my $rcpt = AttrVal($devname,sprintf("postme%02dMsgRec",$pmn),undef);
  965. my $text = PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),undef),11);
  966. $text =~ s/,/,\n/g;
  967. my $fun = AttrVal($devname,"postmeMsgFun",undef);
  968. if( $rcpt && $text && $fun ){
  969. my $ref = \&$fun;
  970. &$ref($rcpt,$listname,$text);
  971. }
  972. my $mga = "$listname sent by messenger";
  973. readingsSingleUpdate($hash,"state",$mga,1 );
  974. Log3 $devname,3,"[PostMe] ".$mga;
  975. return undef;
  976. ##-- speak as TTS
  977. }elsif( $key eq "TTS" ){
  978. my $dev = AttrVal($devname,"postmeTTSDev",undef);
  979. my $text = $listname.": ".PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),undef),10);
  980. my $fun = AttrVal($devname,"postmeTTSFun",undef);
  981. if( $text && $fun ){
  982. my $ref = \&$fun;
  983. &$ref($dev,$text);
  984. }
  985. my $mga = "$listname spoken by TTS";
  986. readingsSingleUpdate($hash,"state",$mga,1 );
  987. Log3 $devname,3,"[PostMe] ".$mga;
  988. return undef;
  989. }
  990. #-- list all PostMe
  991. } elsif ($key eq "all") {
  992. #-- current number of PostMes
  993. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  994. for( my $loop=1;$loop<=$cnop;$loop++){
  995. $res .= ReadingsVal($devname, sprintf("postme%02dName",$loop),"");
  996. $res .= ": ".PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$loop),"")."\n",10);
  997. $res .= "\n";
  998. }
  999. return $res;
  1000. #-- process all PostMe special annotations
  1001. } elsif ($key eq "allspecial") {
  1002. #-- current number of PostMes
  1003. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  1004. for( my $loop=1;$loop<=$cnop;$loop++){
  1005. $listname = ReadingsVal($devname, sprintf("postme%02dName",$loop),"");
  1006. PostMe_Special($hash,$listname,0);
  1007. }
  1008. return $res;
  1009. }
  1010. }
  1011. #########################################################################################
  1012. #
  1013. # PostMe_detailFn - Displays PostMes in detailed view of FHEM
  1014. #
  1015. # Parameter = web argument list
  1016. #
  1017. #########################################################################################
  1018. sub PostMe_detailFn(){
  1019. my ($FW_wname, $devname, $room, $pageHash) = @_; # pageHash is set for summaryFn.
  1020. my $hash = $defs{$devname};
  1021. $hash->{mayBeVisible} = 1;
  1022. my $pmname=$hash->{NAME};
  1023. my $pmfirst = ReadingsVal($devname, "postme01Name","");
  1024. my $pmlist="";
  1025. my $pmoption="";
  1026. #-- current number of PostMes
  1027. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  1028. for( my $loop=1;$loop<=$cnop;$loop++){
  1029. my $n = ReadingsVal($devname, sprintf("postme%02dName",$loop),"");
  1030. $pmlist .= $n;
  1031. $pmlist .= ","
  1032. if( $loop != $cnop);
  1033. if( $loop == 1){
  1034. $pmoption .= '<option selected="selected" value="'.$n.'">'.$n.'</option>';
  1035. }else{
  1036. $pmoption .= '<option value="'.$n.'">'.$n.'</option>';
  1037. }
  1038. }
  1039. my $icon = AttrVal($devname, "icon", "");
  1040. $icon = FW_makeImage($icon,$icon,"icon") . "&nbsp;" if($icon);
  1041. my $html = '<div id="ddtable" class="makeTable wide"><table class="block wide"><tr class="odd">'.
  1042. '<td width="300px"><div>'.$icon.'</div></td>'.
  1043. '<td informId="'.$pmname.'"><div id="'.$pmname.'" title="Initialized" class="col2">'.ReadingsVal($devname,"state","").'</div></td>'.
  1044. '</tr></table></div>';
  1045. $html .= '<script type="text/javascript">function oc(){var p1=document.getElementById("val1_set'.$pmname.'").value;var p2=document.getElementById("val2_set'.$pmname.'").value;'.
  1046. 'var p3;if(document.getElementById("sel_set'.$pmname.'").selectedIndex == 3) p3=p2; else p3=p1+" "+p2;document.getElementById("val_set'.$pmname.'").value=p3;}'.
  1047. 'function dc1(i){if(i == 3)document.getElementById("val1_set'.$pmname.'").style.visibility = "hidden";'.
  1048. 'else document.getElementById("val1_set'.$pmname.'").style.visibility = "visible";'.
  1049. 'if(i > 4)document.getElementById("val2_set'.$pmname.'").style.visibility = "hidden"; else document.getElementById("val2_set'.$pmname.'").style.visibility = "visible";}'.
  1050. 'function dc2(i){if(i > 4)document.getElementById("val_get'.$pmname.'").style.visibility = "hidden";'.
  1051. 'else document.getElementById("val_get'.$pmname.'").style.visibility = "visible";};</script>';
  1052. $html .= '<table><tr><td>'.
  1053. '<form method="post" action="/fhem" autocomplete="off"><input id="pm.setter" type="hidden" name="fwcsrf" value="none"/>'.
  1054. '<input type="hidden" name="detail" value="'.$pmname.'"/><input type="hidden" name="dev.set'.$pmname.'" value="'.$pmname.'"/>'.
  1055. '<input type="submit" name="cmd.set'.$pmname.'" value="set" class="set"/><div class="set downText">&nbsp;'.$pmname.'&nbsp;</div>'.
  1056. '<select id="sel_set'.$pmname.'" informId="sel_set'.$pmname.'" name="arg.set'.$pmname.'" class="set" style="width:100px;" '.
  1057. 'onchange="dc1(this.selectedIndex)">'.
  1058. '<option selected="selected" value="add">add</option><option value="modify">modify</option><option value="remove">remove</option><option value="create">create</option>'.
  1059. '<option value="rename">rename</option><option value="clear">clear</option><option value="delete">delete</option>'.
  1060. '</select>'.
  1061. '<select id="val1_set'.$pmname.'" informId="val1_set'.$pmname.'" name="val1.set'.$pmname.'" class="set" onchange="oc()">'.$pmoption.'</select>'.
  1062. '<input type="text" id="val2_set'.$pmname.'" informId="val2_set'.$pmname.'" name="val2.set'.$pmname.'" class="set" size="30" value="" onchange="oc()"/>'.
  1063. '<input type="hidden" id="val_set'.$pmname.'" informId="val_set'.$pmname.'" name="val.set'.$pmname.'" class="set" size="30" value="'.$pmfirst.'"/></form></td></tr>';
  1064. $html .= '<tr><td>'.
  1065. '<form method="post" action="/fhem" autocomplete="off"><input id="pm.getter" type="hidden" name="fwcsrf" value="none"/>'.
  1066. '<input type="hidden" name="detail" value="'.$pmname.'"/><input type="hidden" name="dev.get'.$pmname.'" value="'.$pmname.'"/>'.
  1067. '<input type="submit" name="cmd.get'.$pmname.'" value="get" class="get"/><div class="get downText">&nbsp;'.$pmname.'&nbsp;</div>'.
  1068. '<select id="sel_get'.$pmname.'" informId="sel_get'.$pmname.'" name="arg.get'.$pmname.'" class="get" style="width:100px;" '.
  1069. 'onchange="dc2(this.selectedIndex)">'.
  1070. '<option selected="selected" value="list">list</option><option value="special">special</option><option value="mail">mail</option><option value="message">message</option><option value="TTS">TTS</option>'.
  1071. '<option value="JSON">JSON</option><option value="all">all</option><option value="allspecial">allspecial</option><<option value="version">version</option>'.
  1072. '</select>'.
  1073. '<select type="hidden" id="val_get'.$pmname.'" informId="val_get'.$pmname.'" name="val.get'.$pmname.'" class="get">'.$pmoption.'</select>'.
  1074. '</form></td></tr></table>';
  1075. $html .= '<script type="text/javascript">var req = new XMLHttpRequest();req.open(\'GET\', document.location.href, false);req.send(null);'.
  1076. 'var csrfToken = req.getResponseHeader(\'X-FHEM-csrfToken\');if( csrfToken == null ){csrfToken = "null";}'.
  1077. 'document.getElementById("pm.setter").value=csrfToken;document.getElementById("pm.getter").value=csrfToken;</script>';
  1078. return $html;
  1079. }
  1080. #########################################################################################
  1081. #
  1082. # PostMe_widget - Displays PostMes as widgets
  1083. #
  1084. # Parameter = web argument list
  1085. #
  1086. #########################################################################################
  1087. sub PostMe_widget($) {
  1088. my ($arg) = @_;
  1089. my $type = $FW_webArgs{type};
  1090. $type = "show"
  1091. if( !$type);
  1092. my $devname = $FW_webArgs{postit};
  1093. my $listname = $FW_webArgs{name};
  1094. my $pmn;
  1095. my $res = "";
  1096. #-- device name
  1097. if( !$devname ){
  1098. Log 1,"[PostMe_widget] Error, web argument postit=... is missing";
  1099. return undef;
  1100. }
  1101. my $hash = $defs{$devname};
  1102. my $style = AttrVal($devname,"postmeStyle","jQuery");
  1103. my $icon = AttrVal($devname,"postmeIcon","images/default/pin_red_32.png");
  1104. my $click = AttrVal($devname,"postmeClick","0");
  1105. my $css = '<link href="www/pgm2/'.AttrVal($FW_wname, "stylesheetPrefix", "").'style.css" rel="stylesheet"/>';
  1106. ##################################################-- type=pins => list with pins
  1107. if( $type eq "pins"){
  1108. #-- current number of Postmes
  1109. my $cnop = ReadingsVal($devname,"postmeCnt",0);
  1110. #-- jQuery rendering
  1111. if( $style eq "jQuery" ){
  1112. $FW_RETTYPE = "text/html";
  1113. $FW_RET="";
  1114. $res .= $css;
  1115. #-- we need our own jQuery object
  1116. $res .= '<script type="text/javascript" src="/fhem/pgm2/jquery.min.js"></script>';
  1117. $res .= '<script type="text/javascript" src="/fhem/pgm2/jquery-ui.min.js"></script>';
  1118. #-- this is for the selector
  1119. $res .= '<div id="postme" class="postmeclass">';
  1120. for( my $loop=1;$loop<=$cnop;$loop++){
  1121. my $name2 = ReadingsVal($devname, sprintf("postme%02dName",$loop),"");
  1122. my $sel = sprintf("sel%02d",$loop);
  1123. $res .= '<div id="'.$sel.'"><img src="'.$icon.'"/>'.$name2.'</div><br/>';
  1124. };
  1125. $res .= '</div>';
  1126. #-- this is the scripting for the dialog box
  1127. $res .= '<script type="text/javascript">';
  1128. $res .= 'var $jParent = window.parent.jQuery;';
  1129. $res .= '$jParent( ".roomBlock1" ).prepend( "<div id=\'postmedia\' style=\'width:200px\'></div>" );';
  1130. $res .= 'var dlg1 = $jParent("#postmedia");';
  1131. $res .= 'dlg1 = dlg1.dialog({width:300,autoOpen:false';
  1132. $res .= ',open:function(event, ui){$(".ui-dialog-titlebar-close").hide();}';
  1133. #-- button only when needed
  1134. $res .= ',buttons:[{text: "OK",click:function(){dlg1.dialog("close");}}]'
  1135. if ($click == 1);
  1136. $res .= '});';
  1137. #-- this is the scripting for the connection selector-dialog
  1138. for( my $loop=1;$loop<=$cnop;$loop++){
  1139. my $name2 = ReadingsVal($devname, sprintf("postme%02dName",$loop),"");
  1140. my $sel = sprintf("sel%02d",$loop);
  1141. if( $click == 0){
  1142. $res .= '$("#'.$sel.'").mouseover(function(){dlg1.load("/fhem/PostMe_widget?postit='.$devname.'&name='.$name2.'",';
  1143. $res .= 'function(){dlg1.dialog("open")})});';
  1144. $res .= '$("#'.$sel.'").mouseout(function(){dlg1.dialog("close")});';
  1145. }else{
  1146. $res .= '$("#'.$sel.'").click(function(){dlg1.load("/fhem/PostMe_widget?postit='.$devname.'&name='.$name2.'",';
  1147. $res .= 'function(){dlg1.dialog("open")})});';
  1148. }
  1149. }
  1150. $res .= '</script>';
  1151. FW_pO $res;
  1152. #-- HTML rendering
  1153. }elsif( $style eq "HTML"){
  1154. $FW_RETTYPE = "text/html; charset=$FW_encoding";
  1155. $FW_RET="";
  1156. $res .= $css;
  1157. $res .= '<div class="postmeclass">';
  1158. for( my $loop=1;$loop<=$cnop;$loop++){
  1159. my $name2 = ReadingsVal($devname, sprintf("postme%02dName",$loop),"");
  1160. if( $click == 0){
  1161. $res .= '<div onmouseover="postit=window.open(\'PostMe_widget?postit='.$devname.'&amp;name='.$name2.'\',\'postit\',\'height=200,width=200,top=400,left=400,menubar=no,toolbar=no,titlebar=no\');" ';
  1162. $res .= 'onmouseout="postit.close()"><img src="'.$icon.'"/>'.$name2.'</div><br/>';
  1163. }else{
  1164. $res .= '<div onclick="postit=window.open(\'PostMe_widget?postit='.$devname.'&amp;name='.$name2.'\',\'postit\',\'height=200,width=200,top=400,left=400,menubar=no,toolbar=no,titlebar=no\');">';
  1165. $res .= '<img src="'.$icon.'"/>'.$name2.'</div><br/>';
  1166. }
  1167. }
  1168. FW_pO $res.'</div>';
  1169. #-- SVG rendering
  1170. }else{
  1171. $FW_RETTYPE = "image/svg+xml";
  1172. $FW_RET="";
  1173. FW_pO '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100px" height="100px">';
  1174. for( my $loop=1;$loop<=$cnop;$loop++){
  1175. my $name2 = ReadingsVal($devname, sprintf("postme%02dName",$loop),"");
  1176. $res.= sprintf('<text x="10" y="%02d" fill="blue" style="font-family:Helvetica;font-size:12px;font-weight:bold" ',10+15*$loop);
  1177. $res.= 'onmouseover="postit=window.open(\'PostMe_widget?postit='.$devname.'&amp;name='.$name2.'\',\'postit\',\'height=200,width=200,top=400,left=400,menubar=no,toolbar=no,titlebar=no\');" ';
  1178. $res.= 'onmouseout="postit.close()">'.$name2.'</text>';
  1179. $res.= <g>
  1180. }
  1181. FW_pO $res.'</svg>';
  1182. }
  1183. return ($FW_RETTYPE, $FW_RET);
  1184. }
  1185. #-- PostMe name
  1186. if( !$listname ){
  1187. Log 1,"[PostMe_widget] Error, web argument name=... is missing";
  1188. return undef;
  1189. }
  1190. $pmn = PostMe_Check($hash,$listname);
  1191. if( !$pmn ){
  1192. Log 1,"[PostMe_widget] Error, a PostMe named $listname does not exist";
  1193. return undef;
  1194. }
  1195. ##################################################-- type=pin => single pin
  1196. if( $type eq "pin"){
  1197. #-- jQuery rendering
  1198. if( $style eq "jQuery"){
  1199. my $sel = sprintf("sel%02d",$pmn);
  1200. $FW_RETTYPE = "text/html";
  1201. $FW_RET="";
  1202. $res .= $css;
  1203. #-- we need our own jQuery object
  1204. $res .= '<script type="text/javascript" src="/fhem/pgm2/jquery.min.js"></script>';
  1205. $res .= '<script type="text/javascript" src="/fhem/pgm2/jquery-ui.min.js"></script>';
  1206. #-- this is for the selector
  1207. $res .= '<div id="postme" class="postmeclass">';
  1208. $res .= '<div id="'.$sel.'"><img src="'.$icon.'"/>'.$listname.'</div><br/>';
  1209. $res .= '</div>';
  1210. #-- this is the scripting for the dialog box
  1211. $res .= '<script type="text/javascript">';
  1212. $res .= 'var $jParent = window.parent.jQuery;';
  1213. $res .= '$jParent( ".roomBlock1" ).prepend( "<div id=\'postmedia\' style=\'width:200px\'></div>" );';
  1214. $res .= 'var dlg1 = $jParent("#postmedia");';
  1215. $res .= 'dlg1 = dlg1.dialog({width:300,autoOpen:false';
  1216. $res .= ',open:function(event, ui){$(".ui-dialog-titlebar-close").hide();}';
  1217. #-- button only when needed
  1218. $res .= ',buttons:[{text: "OK",click:function(){dlg1.dialog("close");}}]'
  1219. if ($click == 1);
  1220. $res .= '});';
  1221. #-- this is the scripting for the connection selector-dialog
  1222. if( $click == 0){
  1223. $res .= '$("#'.$sel.'").mouseover(function(){dlg1.load("/fhem/PostMe_widget?postit='.$devname.'&name='.$listname.'",';
  1224. $res .= 'function(){dlg1.dialog("open")})});';
  1225. $res .= '$("#'.$sel.'").mouseout(function(){dlg1.dialog("close")});';
  1226. }else{
  1227. $res .= '$("#'.$sel.'").click(function(){dlg1.load("/fhem/PostMe_widget?postit='.$devname.'&name='.$listname.'",';
  1228. $res .= 'function(){dlg1.dialog("open")})});';
  1229. }
  1230. $res .= '</script>';
  1231. FW_pO $res;
  1232. #-- HTML rendering
  1233. }elsif( $style eq "HTML"){
  1234. $FW_RETTYPE = "text/html";
  1235. $FW_RET="";
  1236. $res .= $css;
  1237. $res .= '<div class="postmeclass">';
  1238. if( $click == 0){
  1239. $res.= '<div onmouseover="postit=window.open(\'PostMe_widget?postit='.$devname.'&amp;name='.$listname.'\',\'postit\',\'height=200,width=200,top=400,left=400,menubar=no,toolbar=no,titlebar=no\');" ';
  1240. $res.= 'onmouseout="postit.close()">';
  1241. }else{
  1242. $res.= '<div onclick="postit=window.open(\'PostMe_widget?postit='.$devname.'&amp;name='.$listname.'\',\'postit\',\'height=200,width=200,top=400,left=400,menubar=no,toolbar=no,titlebar=no\');">';
  1243. }
  1244. FW_pO $res.'<img src="'.$icon.'"/>'.$listname.'</div>';
  1245. #-- SVG rendering
  1246. }else{
  1247. $FW_RETTYPE = "image/svg+xml";
  1248. $FW_RET="";
  1249. FW_pO '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100px" height="100px">';
  1250. $res.= '<text x="10" y="10" fill="blue" style="font-family:Helvetica;font-size:12px;font-weight:bold" ';
  1251. $res.= 'onmouseover="postit=window.open(\'PostMe_widget?postit='.$devname.'&amp;name='.$listname.'\',\'postit\',\'height=200,width=200,top=400,left=400,menubar=no,toolbar=no,titlebar=no\');" ';
  1252. $res.= 'onmouseout="postit.close()">'.$listname.'</text>';
  1253. FW_pO $res.'</svg>';
  1254. }
  1255. return ($FW_RETTYPE, $FW_RET);
  1256. }
  1257. ################################################## default (type missing) => content of a single postme
  1258. my @lines=split(AttrVal($devname,"listseparator",','),ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""));
  1259. if( !(int(@lines)>0) ){
  1260. #Log 1,"[PostMe_widget] Asking to display empty PostMe $listname";
  1261. return undef;
  1262. }
  1263. #-- HTML rendering
  1264. if( $style ne "SVG"){
  1265. $FW_RETTYPE = "text/html; charset=$FW_encoding";
  1266. $FW_RET="";
  1267. $res .= $css;
  1268. $res .= '<div class="postmeclass2" style="width:200px">';
  1269. $res .= '<b>'.$listname.'</b><br/>';
  1270. for (my $i=0;$i<int(@lines);$i++){
  1271. #--special for meta data
  1272. my $line=PostMe_LineOut($hash,$listname,$lines[$i],0);
  1273. $res.= $line.'<br/>';
  1274. }
  1275. FW_pO $res.'</div>';
  1276. #--- SVG rendering
  1277. }else{
  1278. $FW_RETTYPE = "image/svg+xml";
  1279. $FW_RET="";
  1280. FW_pO '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100px" height="100px">';
  1281. $res = '<text x="10" y="10" fill="blue" style="font-family:Helvetica;font-size:12px;font-weight:bold">';
  1282. $res.= $listname.'</text>';
  1283. for (my $i=0;$i<int(@lines);$i++){
  1284. $res.= sprintf('<text x="10" y="%02d" fill="blue" style="font-family:Helvetica;font-size:10px">',25+$i*12);
  1285. $res.= PostMe_LineOut($hash,$listname,$lines[$i],0);
  1286. $res.= '</text>';
  1287. }
  1288. FW_pO $res.'</svg>';
  1289. }
  1290. return ($FW_RETTYPE, $FW_RET);
  1291. }
  1292. 1;
  1293. =pod
  1294. =item helper
  1295. =item summary to set up a system of sticky notes, similar to Post-Its&trade;
  1296. =item summary_DE zur Definition eines Systems von Klebezetteln ähnlich des Post-Its&trade;
  1297. =begin html
  1298. <a name="PostMe"></a>
  1299. <h3>PostMe</h3>
  1300. <ul>
  1301. <p> FHEM module to set up a system of sticky notes, similar to Post-Its&trade;</p>
  1302. <a name="PostMedefine"></a>
  1303. <h4>Define</h4>
  1304. <p>
  1305. <code>define &lt;postit&gt; PostMe</code>
  1306. <br />Defines the PostMe system, &lt;postit&gt; is an arbitrary name for the system. </p>
  1307. <a name="PostMeusage"></a>
  1308. <h4>Usage</h4>
  1309. See <a href="http://www.fhemwiki.de/wiki/Modul_PostMe">German Wiki page</a>
  1310. <br/>
  1311. An arbitrary number of lists may be added to the system with the <i>create</i> command.<br/>
  1312. List items may consist of one or more words, and are added/removed by the <i>add</i> and
  1313. <i>remove</i> command, but no separator characters are allowed in one item<br/>
  1314. Attention: A comma "," is the <i>default</i> separator for list items, see attributes below.</br/>
  1315. <p/>
  1316. Meta data for items (=annotations)may be included in the items by using "[" and "]"; characters, e.g.<br/>
  1317. <code>set &lt;postit&gt; add &lt;name&gt; &lt;item&gt; [&lt;attribute1&gt;="&lt;data1&gt;" ...</code><br/>
  1318. These attribute-value pairs may be added, modified and removed with the <i>modify</i> command.
  1319. <p/>
  1320. <b>Special annotations</b> will be evaluated further, either on creation or manually by executing the commands<br/>
  1321. <code>get &lt;postit&gt; special &lt;name&gt;</code> resp. <code>get &lt;postit&gt; allspecial</code>
  1322. <ul>
  1323. <li>The attribute <i>at="&lt;timespec/datespec&gt;"</i>, when given a timespec/datespec value, will result in a single or multiple
  1324. reminding messages for this item. The syntax for this timespec/datespec value is<br/>
  1325. <code>(&lt;HH:MM&gt;|&lt;HH:MM:SS&gt;|&lt;YYYY-MM-DD&gt;T&lt;HH:MM:SS&gt;)[-&lt;HH:MM&gt;[P&lt;number&gt;]]</code>
  1326. <br/>
  1327. The first part is the time/date specification when the item is <i>due</i>.
  1328. <br/>The second optional part beginning with a "-"-sign
  1329. denotes how much time befor this date you want to be alerted.
  1330. <br/>The third optional part beginning with a "P" character
  1331. allows to specify a &lt;number&gt; of periodic reminders, the period given by the second part.<br/>
  1332. Processing this attribute means, that several <i>at</i> devices will be set up in the room <i>hidden</i>
  1333. that are triggered when at the specified times.
  1334. See documentation in Wiki for examples.
  1335. </li>
  1336. <li>The attribute <i>notify="&lt;eventspec&gt;"</i>, when given an eventspec value, will result in a single or multiple
  1337. reminding messages for this item.<br/>
  1338. Processing this attribute means, that a <i>notify</i> device will be set up in the room <i>hidden</i>
  1339. that is triggered when the event is detected.</li>
  1340. </ul>
  1341. The sticky notes may be integrated into any Web page by simply embedding the following tags
  1342. <ul>
  1343. <li> <code>&lt;embed src="/fhem/PostMe_widget?type=pins&amp;postit=&lt;postit&gt;"/&gt;</code> <br/>
  1344. to produce an interactive list of all PostMe names with pins from system &lt;postit&gt;.</li>
  1345. <li> <code>&lt;embed src="/fhem/PostMe_widget?type=pin&amp;postit=&lt;postit&gt;&amp;name=&lt;name&gt;"/&gt;</code> <br/>
  1346. to produce an interactive entry for PostMe &lt;name&gt;from system &lt;postit&gt;</li>
  1347. </ul>
  1348. <br/>
  1349. The module provides interface routines that may be called from your own Perl programs, see documentation in the Wiki.
  1350. <br/>
  1351. <a name="PostMeset"></a>
  1352. <h4>Set</h4>
  1353. <ul>
  1354. <li><code>set &lt;postit&gt; create &lt;name&gt;</code>
  1355. <br />creates a sticky note named &lt;name&gt;</li>
  1356. <li><code>set &lt;postit&gt; rename &lt;name&gt; &lt;newname&gt;</code>
  1357. <br />renames the sticky note named &lt;name&gt; as &lt;newname&gt;</li>
  1358. <li><code>set &lt;postit&gt; delete &lt;name&gt;</code>
  1359. <br />deletes the sticky note named &lt;name&gt;</li>
  1360. <li><code>set &lt;postit&gt; add &lt;name&gt; &lt;item&gt;</code>
  1361. <br />adds to the sticky note named &lt;name&gt; an item &lt;item&gt;</li>
  1362. <li><code>set &lt;postit&gt; modify &lt;name&gt; &lt;item&gt; &lt;attribute&gt; &lt;data&gt;</code>
  1363. <br />adds/modifies/removes and attribute-value-pair &lt;attribute&gt;="&lt;data&gt;" to the item &lt;item&gt; on the sticky note named &lt;name&gt;<br/>
  1364. adding, if this attribute is not yet present; modification, if it is present - &lt;data&gt; will then be overwritten; removal, if no &lt;data&gt; is given</li>
  1365. <li><code>set &lt;postit&gt; remove &lt;name&gt; &lt;item&gt;</code><br />
  1366. <code>set &lt;postit&gt; remove &lt;name&gt; item&lt;number&gt;</code>
  1367. <br />removes from the sticky note named &lt;name&gt; an item &lt;item&gt; or the one numbered &lt;number&gt; (starting at 0)</li>
  1368. <li><code>set &lt;postit&gt; clear &lt;name&gt;</code>
  1369. <br />clears the sticky note named &lt;name&gt; from all items </li>
  1370. </ul>
  1371. <a name="PostMeget"></a>
  1372. <h4>Get</h4>
  1373. <ul>
  1374. <li><code>get &lt;postit&gt; list &lt;name&gt;</code>
  1375. <br />Show the sticky note named &lt;name&gt; and its content</li>
  1376. <li><code>get &lt;postit&gt; special &lt;name&gt;</code>
  1377. <br />Process the special annotations (see above) of the sticky note named &lt;name&gt;</li>
  1378. <li><code>get &lt;postit&gt; mail &lt;name&gt;</code>
  1379. <br />Send the sticky note named &lt;name&gt; and its content via eMail to a predefined
  1380. recipient (e.g. sticky note &lt;postme01Name&gt; is sent to &lt;postme01MailRec&gt;).<br/> The mailing
  1381. subroutine <postmeMsgFun> is called with three parameters for recipient, subject
  1382. and text. </li>
  1383. <li><code>get &lt;postit&gt; message &lt;name&gt;</code>
  1384. <br />Send the sticky note named &lt;name&gt; and its content via instant messenger to a predefined
  1385. recipient (e.g. sticky note &lt;postme01Name&gt; is sent to &lt;postme01MsgRec&gt;).<br/> The messenger
  1386. subroutine <postmeMsgFun> is called with three parameters for recipient, subject
  1387. and text. </li>
  1388. <li><code>get &lt;postit&gt; TTS &lt;name&gt;</code>
  1389. <br />Speak the sticky note named &lt;name&gt; and its content. The TTS
  1390. subroutine <postmeTTSFun> is called with one parameter text. </li>
  1391. <li><code>get &lt;postit&gt; JSON &lt;name&gt;</code>
  1392. <br />Return the sticky note named &lt;name&gt; in JSON format</li>
  1393. <li><code>get &lt;postit&gt; all</code>
  1394. <br />Show all sticky notes and their content</li>
  1395. <li><code>get &lt;postit&gt; allspecial</code>
  1396. <br />Process the special annotations (see above) of all sticky notes</li>
  1397. <li><code>get &lt;postit&gt; version</code>
  1398. <br />Display the version of the module</li>
  1399. </ul>
  1400. <a name="PostMeattr"></a>
  1401. <h4>Attributes</h4>
  1402. <ul>
  1403. <li><code>attr &lt;postit&gt; postmeStd &lt;name1,name2,...&gt;</code>
  1404. <br />Comma separated list of standard sticky notes that will be created on device start.</li>
  1405. <li><code>attr &lt;postit&gt; postmeClick 1|0 (default)</code>
  1406. <br />If 0, embedded sticky notes will pop up on mouseover-events and vanish on mouseout-events (default).<br/>
  1407. If 1, embedded sticky notes will pop up on click events and vanish after closing the note</li>
  1408. <li><code>attr &lt;postit&gt; postmeIcon &lt;string&gt;</code>
  1409. <br />Icon for display of a sticky note</li>
  1410. <li><code>attr &lt;postit&gt; postmeStyle SVG|HTML|jQuery (default)</code>
  1411. <br />If jQuery, embedded sticky notes will produce jQuery code (default) <br/>
  1412. If HTML, embedded sticky notes will produce HTML code <br/>
  1413. If SVG, embedded sticky notes will produce SVG code</li>
  1414. <li><code>attr &lt;postit&gt; listseparator &lt;character&gt;</code>
  1415. <br />Character used to separate list items (default ',')</li>
  1416. </ul>
  1417. Note, that in the parameters sent to the following functions, ":" serves as separator between list name and items,
  1418. and "," serves as separator between items. They may be exchanged with simple regular expression operations.
  1419. <ul>
  1420. <li><code>attr &lt;postit&gt; postmeMailFun &lt;string&gt;</code>
  1421. <br />Function name for the eMail function. This subroutine
  1422. is called with three parameters for recipient, subject
  1423. and text.</li>
  1424. <li><code>attr &lt;postit&gt; postmeMailRec(01|02|...) &lt;string&gt;</code>
  1425. recipient addresses for the above eMail function (per PostMe).</li>
  1426. <li><code>attr &lt;postit&gt; postmeMsgFun &lt;string&gt;</code>
  1427. <br />Function name for the instant messenger function. This subroutine
  1428. is called with three parameters for recipient, subject
  1429. and text.</li>
  1430. <li><code>attr &lt;postit&gt; postmeMsgRec(01|02|...) &lt;string&gt;</code>
  1431. recipient addresses for the above instant messenger function (per PostMe).</li>
  1432. <li><code>attr &lt;postit&gt; postmeTTSFun &lt;string&gt;</code>
  1433. <br />Function name for the text-to-speech function. This subroutine
  1434. is called with two parameters, the device name and the composite text.
  1435. </li>
  1436. <li><code>attr &lt;postit&gt; postmeTTSDev(01|02|...) &lt;string&gt;</code>
  1437. device name for the above TTS function.</li>
  1438. <li>Standard attributes <a href="#alias">alias</a>, <a href="#comment">comment</a>, <a
  1439. href="#event-on-update-reading">event-on-update-reading</a>, <a
  1440. href="#event-on-change-reading">event-on-change-reading</a>, <a href="#room"
  1441. >room</a>, <a href="#eventMap">eventMap</a>, <a href="#loglevel">loglevel</a>,
  1442. <a href="#webCmd">webCmd</a></li>
  1443. </ul>
  1444. </ul>
  1445. =end html
  1446. =begin html_DE
  1447. <a name="PostMe"></a>
  1448. <h3>PostMe</h3>
  1449. <ul>
  1450. <a href="https://wiki.fhem.de/wiki/Modul_PostMe">Deutsche Dokumentation im Wiki</a> vorhanden, die englische Version gibt es hier: <a href="/fhem/docs/commandref.html#PostMe">PostMe</a>
  1451. </ul>
  1452. =end html_DE
  1453. =cut