######################################################################################## # # PostMe.pm # # FHEM module to set up a system of sticky notes, similar to Post-Its # # Prof. Dr. Peter A. Henning # # $Id$ # # Not named Post-It, which is a trademark of 3M # ######################################################################################## # # This programm is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # The GNU General Public License can be found at # http://www.gnu.org/copyleft/gpl.html. # A copy is found in the textfile GPL.txt and important notices to the license # from the author is found in LICENSE.txt distributed with these scripts. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # ######################################################################################## package main; use strict; use warnings; use vars qw(%defs); # FHEM device/button definitions use vars qw($FW_RET); # Returned data (html) use vars qw($FW_RETTYPE); # image/png or the like use vars qw($FW_wname); # Web instance use Time::Local; ######################### # Global variables my $postmeversion = "2.10"; my $FW_encoding = "UTF-8"; ######################################################################################### # # PostMe_Initialize # # Parameter hash = hash of device addressed # ######################################################################################### sub PostMe_Initialize ($) { my ($hash) = @_; my $devname = $hash->{NAME}; $hash->{DefFn} = "PostMe_Define"; $hash->{SetFn} = "PostMe_Set"; $hash->{GetFn} = "PostMe_Get"; $hash->{UndefFn} = "PostMe_Undef"; $hash->{InitFn} = "PostMe_Init"; $hash->{AttrFn} = "PostMe_Attr"; $hash->{AttrList} = "postmeTTSFun postmeTTSDev postmeMsgFun postme[0-9]+MsgRec postmeMailFun postme[0-9]+MailRec ". "postmeStd postmeIcon postmeStyle:jQuery,HTML,SVG postmeClick:0,1 listseparator ".$readingFnAttributes; $hash->{FW_detailFn} = "PostMe_detailFn"; $data{FWEXT}{"/PostMe_widget"}{FUNC} = "PostMe_widget"; $data{FWEXT}{"/PostMe_widget"}{FORKABLE} = 1; return undef; } ######################################################################################### # # PostMe_Define - Implements DefFn function # # Parameter hash = hash of device addressed, def = definition string # ######################################################################################### sub PostMe_Define ($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); my $now = time(); my $devname = $hash->{NAME}; $modules{PostMe}{defptr}{$a[0]} = $hash; readingsBeginUpdate($hash); readingsBulkUpdate($hash,"state","Initialized"); readingsEndUpdate($hash,1); InternalTimer(gettimeofday()+2, "PostMe_Init", $hash,0); return undef; } ######################################################################################### # # PostMe_Undef - Implements Undef function # # Parameter hash = hash of device addressed, def = definition string # ######################################################################################### sub PostMe_Undef ($$) { my ($hash,$arg) = @_; RemoveInternalTimer($hash); return undef; } ######################################################################################### # # PostMe_Attr - Implements Attr function # # Parameter hash = hash of device addressed, ??? # ######################################################################################### sub PostMe_Attr($$$) { my ($cmd, $listname, $attrName, $attrVal) = @_; return; } ######################################################################################### # # PostMe_Init - Check, if default PostMes have been defined # # Parameter hash = hash of device addressed # ######################################################################################### sub PostMe_Init($) { my ($hash) = @_; my $devname = $hash->{NAME}; my $now = time(); my $err = 0; #-- current number of PostMes my $cnop = ReadingsVal($devname,"postmeCnt",0); my @std = split(',',AttrVal("$devname","postmeStd","")); for( my $i=0;$i{NAME}; my ($loop,$res); #-- current number of PostMes my $cnop = ReadingsVal($devname,"postmeCnt",0); for( $loop=1;$loop<=$cnop;$loop++){ $res = ReadingsVal($devname, sprintf("postme%02dName",$loop), undef); last if(lc($res) eq lc($listname)); } #-- no PostMe with this name if( lc($res) ne lc($listname) ){ return undef; }else{ return $loop; } } ######################################################################################### # # PostMe_Create - Create a new PostMe # # Parameter hash = hash of device addressed # listname = name of PostMe # ######################################################################################### sub PostMe_Create($$) { my ($hash,$listname) = @_; my $devname = $hash->{NAME}; if( PostMe_Check($hash,$listname) ){ my $mga = "Error, a PostMe named $listname does already exist"; Log 1,"[PostMe_Create] $mga"; return "$mga"; } #-- current number of PostMes my $cnop = ReadingsVal($devname,"postmeCnt",0); $cnop++; readingsBeginUpdate($hash); readingsBulkUpdate($hash, sprintf("postme%02dName",$cnop),$listname); readingsBulkUpdate($hash, sprintf("postme%02dCont",$cnop),""); readingsBulkUpdate($hash, "postmeCnt",$cnop); readingsEndUpdate($hash,1); Log3 $devname,3,"[PostMe] Added a new PostMe named $listname"; return undef; } ######################################################################################### # # PostMe_Delete - Delete an existing PostMe # # Parameter hash = hash of device addressed # listname = name of PostMe # ######################################################################################### sub PostMe_Delete($$) { my ($hash,$listname) = @_; my $devname = $hash->{NAME}; my $loop; if( index(AttrVal("$devname","postmeStd",""),$listname) != -1){ my $mga = "Error, the PostMe named $listname is a standard PostMe and cannot be deleted"; Log 1,"[PostMe_Delete] $mga"; return "$mga"; } my $pmn=PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_Delete] $mga"; return "$mga"; } #-- current number of PostMes my $cnop = ReadingsVal($devname,"postmeCnt",0); readingsBeginUpdate($hash); #-- re-ordering for( $loop=$pmn;$loop<$cnop;$loop++){ readingsBulkUpdate($hash, sprintf("postme%02dName",$loop), ReadingsVal($devname, sprintf("postme%02dName",$loop+1),"")); readingsBulkUpdate($hash, sprintf("postme%02dCont",$loop), ReadingsVal($devname, sprintf("postme%02dCont",$loop+1),"")); } $cnop--; readingsBulkUpdate($hash, "postmeCnt",$cnop); readingsEndUpdate($hash,1); fhem("deletereading $devname ".sprintf("postme%02dName",$cnop+1)); fhem("deletereading $devname ".sprintf("postme%02dCont",$cnop+1)); Log3 $devname,3,"[PostMe] Deleted PostMe named $listname"; return undef; } ######################################################################################### # # PostMe_Rename - Renames an existing PostMe # # Parameter hash = hash of device addressed # listname = name of PostMe # newname = newname of PostMe # ######################################################################################### sub PostMe_Rename($$$) { my ($hash,$listname,$newname) = @_; my $devname = $hash->{NAME}; my $loop; if( index(AttrVal("$devname","postmeStd",""),$listname) != -1){ my $mga = "Error, the PostMe named $listname is a standard PostMe and cannot be renamed"; Log 1,"[PostMe_Rename] $mga"; return "$mga"; } my $pmn=PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_Rename] $mga"; return "$mga"; } my $pnn=PostMe_Check($hash,$newname); if( $pnn ){ my $mga = "Error, a PostMe named $newname does already exist and is not empty"; Log 1,"[PostMe_Rename] $mga"; return "$mga"; } readingsSingleUpdate($hash,sprintf("postme%02dName",$pmn),$newname,1); Log3 $devname,3,"[PostMe] Renamed PostMe named $listname into $newname"; return undef; } ######################################################################################### # # PostMe_Add - Add something to a PostMe # # Parameter hash = hash of device addressed # ######################################################################################### sub PostMe_Add($$@) { my ($hash,$listname,@args) = @_; my $devname = $hash->{NAME}; my $pmn=PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_Add] $mga"; return "$mga"; } my $raw = join(' ',@args); #-- remove meta data my $item = $raw; $item =~ s/\[.*\]//g; $item =~ s/\]//g; $item =~ s/\[//g; #-- safety catch: No action when item empty if( $item eq "" ){ my $mga = "Error, empty item given"; Log 1,"[PostMe_Add] $mga"; return "$mga"; } #-- check old content my $old = ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""); my $ind = index($old,$item); if( $ind >= 0 ){ my $mga = "Error, item $item is already present in PostMe $listname"; Log 1,"[PostMe_Add] $mga"; return "$mga"; } $old .= AttrVal($devname,"listseparator",',') if($old ne ""); #-- TODO: META DATA MISSING readingsSingleUpdate($hash, sprintf("postme%02dCont",$pmn),$old.$item,1); Log3 $devname,3,"[Postme] Added item $item to PostMe named $listname"; return undef; } ######################################################################################### # # PostMe_Remove - Remove something from a PostMe # # Parameter hash = hash of device addressed # ######################################################################################### sub PostMe_Remove($$@) { my ($hash,$listname,@args) = @_; my $devname = $hash->{NAME}; my $pmn=PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_Remove] $mga"; return "$mga"; } my $raw = join(' ',@args); my $listsep = AttrVal($devname,"listseparator",','); #-- remove meta data my $item = $raw; $item =~ s/\[.*\]//g; #-- safety catch: No action when item empty if( $item eq "" ){ my $mga = "Error, empty item given"; Log 1,"[PostMe_Remove] $mga"; return "$mga"; } #-- get old content my $new = ""; my $old = ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""); my @lines= split($listsep,$old); #-- item may be of type item\d\d if( $item =~ /item(\d+)/ ){ $item = $lines[$1]; } #-- check old content my $ind = index($old,$item); if( $ind < 0 ){ my $mga = "Error, item $item is not present in PostMe $listname"; Log 1,"[PostMe_Remove] $mga"; return "$mga"; } #-- item may be a short version of the real entry for( my $loop=0;$loop= 0 ){ my $line = $lines[$loop]; my $itex = $line; my $meta = $line; $itex =~ s/\s*\[.*//; #-- only if attributes present if( $line =~ /.*\[.*\].*/){ $meta =~ s/.*\[//; $meta =~ s/\]//; my @lines2 = split('" ',$meta); for( my $loop2=0;$loop2{NAME}; my $pmn=PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_Clear] $mga"; return "$mga"; } PostMe_Special($hash,$listname,1); readingsSingleUpdate($hash, sprintf("postme%02dCont",$pmn),"",1 ); Log3 $devname,3,"[PostMe_Clear] Cleared PostMe named $listname"; return undef; } ######################################################################################### # # PostMe_Modify - Annotate an item from a PostMe with meta data # # Parameter hash = hash of device addressed # ######################################################################################### sub PostMe_Modify($$@) { my ($hash,$listname,@args) = @_; my $devname = $hash->{NAME}; my $pmn=PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_Remove] $mga"; return "$mga"; } my $listsep = AttrVal($devname,"listseparator",','); #-- difficult to separate item from new meta data. For now, first term is the item, # second term is the attribute and remaining terms are the value my $item = $args[0]; my $attr = $args[1]; splice(@args,0,2); my $val = join(' ',@args); #-- safety catch: No action when item empty if( $item eq "" ){ my $mga = "Error, empty item given"; Log 1,"[PostMe_Modify] $mga"; return "$mga"; } #-- check old content my $old = ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""); my $ind = index($old,$item); if( $ind < 0 ){ my $mga = "Error, item $item is not present in PostMe $listname"; Log 1,"[PostMe_Remove] $mga"; return "$mga"; } #-- item my @lines = split($listsep,$old); my $new = ""; for( my $loop=0;$loop{NAME}; my $pmn=PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_Special] $mga"; return "$mga"; } my $listsep = AttrVal($devname,"listseparator",','); #-- check content my $cont = ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""); #-- item my @lines = split($listsep,$cont); for( my $loop=0;$loop=0)&&($mon<=11) )? $mon:0; $day =($3)?$3 : $dayn; $day = ( ($day>=1)&&($day<=31) )? $day:0; $timeraw =~ /(\d\d):(\d\d)(\:(\d\d))?/; $hour =($1)?$1 : $hourn; $hour = ( ($hour>=0)&&($hour<=23) )? $hour:0; $min =($2)?$2 : $minn; $min = ( ($min>=0)&&($min<=59) )? $min:0; $sec =($4)?$4 : "00"; $sec = ( ($sec>=0)&&($sec<=59) )? $sec:0; $delta =~ /(\d\d):(\d\d)/; ($deltah,$deltam)=($1,$2); my $deltas = min(3600*$deltah+60*$deltam,86400); $repeat = ( ($repeat>=0)&&($repeat<=10) )? $repeat:0; my $ftime = timelocal($sec,$min,$hour,$day,$mon,$year); my $ftimel= strftime('%Y-%m-%dT%H:%M:%S',localtime($ftime)); #-- determine send strings my $mrcpt = AttrVal($devname,sprintf("postme%02dMailRec",$pmn),undef); my $mfun = AttrVal($devname,"postmeMailFun",undef); if( $mrcpt && $mfun ){ $str .= "$mfun('$mrcpt','$listname','$item => $ftimel');;"; } my $trcpt = AttrVal($devname,sprintf("postme%02dMsgRec",$pmn),undef); my $tfun = AttrVal($devname,"postmeMsgFun",undef); if( $trcpt && $tfun ){ $str .= "$tfun('$trcpt','$listname','$item => $ftimel');;"; } $str .="}"; #-- define name for timer my $safename = PostMe_safeItem($hash,$listname,$item,"at"); fhem("defmod ".$safename."_00 at $ftimel $str"); fhem("attr ".$safename."_00 room hidden"); if( $delta ){ for(my $i=1;$i<=$repeat;$i++){ my $stime = $ftime-$i*$deltas; my $stimel= strftime('%Y-%m-%dT%H:%M:%S',localtime($stime)); my $sname = $safename.sprintf("_%02d",$i); fhem("defmod ".$sname." at $stimel $str"); fhem("attr ".$sname." room hidden"); } } } }elsif( $attr eq "notify" ){ return if( !$val); $val =~ s/\"$//; my $str = "{"; #-- determine send strings my $mrcpt = AttrVal($devname,sprintf("postme%02dMailRec",$pmn),undef); my $mfun = AttrVal($devname,"postmeMailFun",undef); if( $mrcpt && $mfun ){ $str .= "$mfun('$mrcpt','$listname','$item');;"; } my $trcpt = AttrVal($devname,sprintf("postme%02dMsgRec",$pmn),undef); my $tfun = AttrVal($devname,"postmeMsgFun",undef); if( $trcpt && $tfun ){ $str .= "$tfun('$trcpt','$listname','$item');;"; } $str .="}"; #-- define name for notify my $safename = PostMe_safeItem($hash,$listname,$item,"notify"); fhem("defmod ".$safename." notify $val $str"); fhem("attr ".$safename." room hidden"); } } ######################################################################################### # # PostMe_cleanSpecial - process special annotations by cleaning leftover procedures # Parameter hash = hash of device addressed # name = name of the PostMe # item = item content # attr = attribute name # ######################################################################################### sub PostMe_cleanSpecial($$$$){ my($hash,$listname,$item,$attr) =@_; my $devname=$hash->{NAME}; if( $attr eq "at" ){ #-- define name for timer my $safename = PostMe_safeItem($hash,$listname,$item,"at"); fhem("delete ".$safename.".*"); }elsif( $attr eq "notify" ){ #-- define name for notify my $safename = PostMe_safeItem($hash,$listname,$item,"notify"); fhem("delete ".$safename.".*"); } } ######################################################################################### # # PostMe_safeItem - transform an item content into a FHEM name # Parameter hash = hash of device addressed # name = name of the PostMe # item = item content # attr = attribute name # ######################################################################################### sub PostMe_safeItem($$$$){ my($hash,$listname,$item,$attr) =@_; my $devname=$hash->{NAME}; my $safeitem=join('_',split(' ',$item)); $safeitem = substr($safeitem,0,4); $safeitem =~ tr/äöüÄÖÜß'/a_o_u_A_O_U_S__/; my $safelist=join('_',split(' ',$listname)); $safelist = substr($safelist,0,4); $safelist =~ tr/äöüÄÖÜß'/a_o_u_A_O_U_S__/; my $safeattr = substr($attr,0,2); return $devname."_".$safelist."_".$safeitem."_".$safeattr; } ######################################################################################### # # PostMe_LineIn - format a single PostMe line from input # # Parameter hash = hash of device addressed # line = raw data in the form item [att1="val1" att2="val2"] # ######################################################################################### sub PostMe_LineIn($$) { my ($hash,$line) = @_; my $devname = $hash->{NAME}; } ######################################################################################### # # PostMe_LineOut - format a single PostMe line for output # # Parameter line = raw data in the form item [att1="val1" att2="val2"] # (multiple items separated by comma) # format = 0 - item only # ######################################################################################### sub PostMe_LineOut($$$$) { my ($hash,$listname,$line,$format) = @_; my $devname = $hash->{NAME}; my ($i,$line2,$item,$meat,$new,@lines,%meta); #Log 1,"LINEOUT format = $format, line=$line"; #-- format == 0 - single item line if( $format < 10){ $item = $line; $item =~ s/\s+\[.*//; $line =~ s/.*\[//; $line =~ s/\]//; my @list1 = split(/ /,$line); foreach my $item2(@list1) { my ($i,$j)= split(/=/, $item2); $meta{$i} = $j; } #Log 1,"line=$line, item=$item"; return $item; #-- formats >= 10 for all items in a PostMe }elsif( $format >= 10){ my $listsep = AttrVal($devname,"listseparator",','); my @lines = split($listsep,$line); #-- format 13, return array return \@lines if( $format==14 ); my $new = ""; my $item; my $meat; for( my $loop=0;$loop=0 ){ $item = substr($line2,0,$i); $meat = substr($line2,$i); $item =~ s/\s*$//; $meat =~ s/.*\[//; $meat =~ s/\]//; my @list1 = split('" ',$meat); foreach my $item2(@list1) { my ($i,$j)= split(/=/, $item2); $j =~ s/^"//; $meta{$i} = $j; #Log 1,"Setting META $i to VALUE $j"; } }else{ $item = $line2; $meat = ""; $item =~ s/\s*$//; } #-- format 10: plain format, item only $new .= $item.',' if( $format == 10); #-- format 11: meta data in brackets if( $format == 11){ if( $meat ne "" ){ $new .= $item.'('.$meat.'),'; }else{ $new .= $item.','; } } #-- format 13: Telegram format item w indexing $new .= '('.$item.sprintf(':%sitem%02d) ',$listname,$loop) if( $format == 13); #-- json format by hand if( $format == 15 ){ $new .= '{"item": "'.$item.'"'; if( $meat ne "" ){ $new .= ',"meta": {'; foreach my $k (keys %meta){ $new .= '"'.$k.'": "'.$meta{$k}.'",'; } $new .= '}'; } $new .= '},'; } } $new =~ s/""/"/g; $new =~ s/,}/}/g; $new =~ s/,$//; return $new; } } ######################################################################################### # # PostMe_tgi - format a single PostMe as inline keyboard for telegram (items w. indexing) # # Parameter devname = device name # listname = list name # ######################################################################################### sub PostMe_tgi($$) { my ($devname,$listname) = @_; my $pmn; my $res = ""; my $hash = $defs{$devname}; if( !$hash ){ my $mga = "Error, a PostMe device named $devname does not exist"; Log 1,"[PostMe_tgi] $mga"; return "$mga"; } #Log 1,"[PostMe_Get] with name=$listname key=$key args=@args"; $pmn = PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_tgi] $mga"; return "$mga"; } $res = PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""),13); $res.= " ".$listname; return $res; } ######################################################################################### # # PostMe_tgj - format a single PostMe as simple array # # Parameter devname = device name # listname = list name # ###########################################################################k############## sub PostMe_tgj($$) { my ($devname,$listname) = @_; my $pmn; my $hash = $defs{$devname}; if( !$hash ){ my $mga = "Error, a PostMe device named $devname does not exist"; Log 1,"[PostMe_tgk] $mga"; return "$mga"; } #Log 1,"[PostMe_Get] with name=$listname key=$key args=@args"; $pmn = PostMe_Check($hash,$listname); if( !$pmn ){ my $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_tgk] $mga"; return "$mga"; } my @ret=PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""),14); return \@ret; } ######################################################################################### # # PostMe_Set - Implements the Set function # # Parameter hash = hash of device addressed # ######################################################################################### sub PostMe_Set($@) { my ( $hash, $devname, $key, @args ) = @_; #-- for the selector: which values are possible if ($key eq "?"){ #--prevent any default set return undef; #-- obsolete my @cmds = ("create","delete","rename","add","modify","remove","clear"); return "Unknown argument $key, choose one of " .join(" ",@cmds); } my $listname = shift @args; if( $key eq "create"){ PostMe_Create($hash,$listname); }elsif( $key eq "delete"){ PostMe_Delete($hash,$listname); }elsif( $key eq "rename"){ PostMe_Rename($hash,$listname,$args[0]); }elsif( $key eq "add"){ PostMe_Add($hash,$listname,@args); }elsif( $key eq "modify"){ PostMe_Modify($hash,$listname,@args); }elsif( $key eq "remove"){ PostMe_Remove($hash,$listname,@args); }elsif( $key eq "clear"){ PostMe_Clear($hash,$listname); } } ######################################################################################### # # PostMe_Get - Implements the Get function # # Parameter hash = hash of device addressed # ######################################################################################### sub PostMe_Get($$$@) { my ($hash, $devname, $key, @args) = @_; my $pmn; my $res = ""; my $hasMail = defined(AttrVal($devname,"postmeMailFun",undef)) ? 1 : 0; my $hasMsgr = defined(AttrVal($devname,"postmeMsgFun",undef)) ? 1 : 0; my $hasTTS = defined(AttrVal($devname,"postmeTTSFun",undef)) ? 1 : 0; #-- for the selector: which values are possible if ($key eq "?"){ #-- prevent any default get return undef; #-- obsolete #-- current number of PostMes my $cnop = ReadingsVal($devname,"postmeCnt",0); my $pml = ""; for( my $i=1;$i<=$cnop;$i++){ $pml .= "," if( $i >1); $pml .= ReadingsVal($devname, sprintf("postme%02dName",$i),""); } my @cmds = ("version:noArg","all:noArg","allspecial","list:".$pml,"special:".$pml); $res = "Unknown argument $key choose one of ".join(" ",@cmds); $res.= " mail:".$pml if($hasMail); $res.= " message:".$pml if($hasMsgr); $res.= " TTS:".$pml if($hasTTS); $res.= " JSON:".$pml; return $res; } my $listname = $args[0]; if ($key eq "version") { return "PostMe.version => $postmeversion"; #-- list one PostMe } elsif( ($key eq "list")||($key eq "special")||($key eq "JSON")||($key eq "mail")||($key eq "message")||($key eq "TTS") ){ my ($mga,$rcpt,$text,$fun); $pmn = PostMe_Check($hash,$listname); if( !$pmn ){ $mga = "Error, a PostMe named $listname does not exist"; Log 1,"[PostMe_Get] $mga"; return "$mga"; } ##-- list if( $key eq "list" ){ $res = ReadingsVal($devname, sprintf("postme%02dName",$pmn),""); $res .= ": "; $res .= PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),"")."\n",10); return $res; ##-- list }elsif( $key eq "special" ){ PostMe_Special($hash,$listname,0); ##-- JSON }elsif( $key eq "JSON" ){ $res = PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),""),15); return '{"'.$listname.'": ['.$res.']}'; ##-- send by mail }elsif( $key eq "mail" ){ $rcpt = AttrVal($devname,sprintf("postme%02dMailRec",$pmn),undef); $text = PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),undef),11); $fun = AttrVal($devname,"postmeMailFun",undef); $mga = "postmeMailFun not defined"; if( $rcpt && $text && $fun ){ local $@; # protect existing $@ my $ref = \&$fun; eval{&$ref($rcpt,$listname,$text)}; if($@){ $mga = "postmeMailFun failed with rc=$@"; }else{ $mga = "$listname sent by mail"; } } readingsSingleUpdate($hash,"state",$mga,1 ); Log3 $devname,3,"[PostMe] ".$mga; return undef; ##-- send by instant messenger }elsif( $key eq "message" ){ $rcpt = AttrVal($devname,sprintf("postme%02dMsgRec",$pmn),undef); $text = PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),undef),11); $text =~ s/,/,\n/g; $fun = AttrVal($devname,"postmeMsgFun",undef); $mga = "postmeMsgFun not defined"; if( $rcpt && $text && $fun ){ local $@; # protect existing $@ my $ref = \&$fun; eval{&$ref($rcpt,$listname,$text)}; if($@){ $mga = "postmeMsgFun failed with rc=$@"; }else{ $mga = "$listname sent by messenger"; } } readingsSingleUpdate($hash,"state",$mga,1 ); Log3 $devname,3,"[PostMe] ".$mga; return undef; ##-- speak as TTS }elsif( $key eq "TTS" ){ my $dev = AttrVal($devname,"postmeTTSDev",undef); $text = $listname.": ".PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$pmn),undef),10); $fun = AttrVal($devname,"postmeTTSFun",undef); $mga = "postmeTTSFun not defined"; if( $text && $fun ){ local $@; # protect existing $@ my $ref = \&$fun; eval{&$ref($dev,$text)}; if($@){ $mga = "postmeTTSFun failed with rc=$@"; }else{ $mga = "$listname spoken by TTS"; } } readingsSingleUpdate($hash,"state",$mga,1 ); Log3 $devname,3,"[PostMe] ".$mga; return undef; } #-- list all PostMe } elsif ($key eq "all") { #-- current number of PostMes my $cnop = ReadingsVal($devname,"postmeCnt",0); for( my $loop=1;$loop<=$cnop;$loop++){ $res .= ReadingsVal($devname, sprintf("postme%02dName",$loop),""); $res .= ": ".PostMe_LineOut($hash,$listname,ReadingsVal($devname, sprintf("postme%02dCont",$loop),"")."\n",10); $res .= "\n"; } return $res; #-- process all PostMe special annotations } elsif ($key eq "allspecial") { #-- current number of PostMes my $cnop = ReadingsVal($devname,"postmeCnt",0); for( my $loop=1;$loop<=$cnop;$loop++){ $listname = ReadingsVal($devname, sprintf("postme%02dName",$loop),""); PostMe_Special($hash,$listname,0); } return $res; } } ######################################################################################### # # PostMe_detailFn - Displays PostMes in detailed view of FHEM # # Parameter = web argument list # ######################################################################################### sub PostMe_detailFn(){ my ($FW_wname, $devname, $room, $pageHash) = @_; # pageHash is set for summaryFn. my $hash = $defs{$devname}; $hash->{mayBeVisible} = 1; my $pmname=$hash->{NAME}; my $pmfirst = ReadingsVal($devname, "postme01Name",""); my $pmlist=""; my $pmoption=""; #-- current number of PostMes my $cnop = ReadingsVal($devname,"postmeCnt",0); for( my $loop=1;$loop<=$cnop;$loop++){ my $n = ReadingsVal($devname, sprintf("postme%02dName",$loop),""); $pmlist .= $n; $pmlist .= "," if( $loop != $cnop); if( $loop == 1){ $pmoption .= ''; }else{ $pmoption .= ''; } } my $icon = AttrVal($devname, "icon", ""); $icon = FW_makeImage($icon,$icon,"icon") . " " if($icon); my $html = '
'. ''. ''. '
'.$icon.'
'.ReadingsVal($devname,"state","").'
'; $html .= ''; $html .= ''; $html .= '
'. '
'. ''. '
 '.$pmname.' 
'. ''. ''. ''. '
'. '
'. ''. '
 '.$pmname.' 
'. ''. ''. '
'; $html .= ''; return $html; } ######################################################################################### # # PostMe_widget - Displays PostMes as widgets # # Parameter = web argument list # ######################################################################################### sub PostMe_widget($) { my ($arg) = @_; my $type = $FW_webArgs{type}; $type = "show" if( !$type); my $devname = $FW_webArgs{postit}; my $listname = $FW_webArgs{name}; my $pmn; my $res = ""; #-- device name if( !$devname ){ Log 1,"[PostMe_widget] Error, web argument postit=... is missing"; return undef; } my $hash = $defs{$devname}; my $style = AttrVal($devname,"postmeStyle","jQuery"); my $icon = AttrVal($devname,"postmeIcon","images/default/pin_red_32.png"); my $click = AttrVal($devname,"postmeClick","0"); my $css = ''; ##################################################-- type=pins => list with pins, separate boxes for lists if( $type eq "pins"){ #-- current number of Postmes my $cnop = ReadingsVal($devname,"postmeCnt",0); #-- jQuery rendering if( $style eq "jQuery" ){ $FW_RETTYPE = "text/html"; $FW_RET=""; $res .= $css; #-- we need our own jQuery object $res .= ''; $res .= ''; #-- this is for the selector $res .= '
'; for( my $loop=1;$loop<=$cnop;$loop++){ my $name2 = ReadingsVal($devname, sprintf("postme%02dName",$loop),""); my $sel = sprintf("sel%02d",$loop); $res .= '
'.$name2.'

'; }; $res .= '
'; #-- this is the scripting for the dialog box $res .= ''; FW_pO $res; #-- HTML rendering }elsif( $style eq "HTML"){ $FW_RETTYPE = "text/html; charset=$FW_encoding"; $FW_RET=""; $res .= $css; $res .= '
'; for( my $loop=1;$loop<=$cnop;$loop++){ my $name2 = ReadingsVal($devname, sprintf("postme%02dName",$loop),""); if( $click == 0){ $res .= '
'.$name2.'

'; }else{ $res .= '
'; $res .= ''.$name2.'

'; } } FW_pO $res.'
'; #-- SVG rendering }else{ $FW_RETTYPE = "image/svg+xml"; $FW_RET=""; FW_pO ''; for( my $loop=1;$loop<=$cnop;$loop++){ my $name2 = ReadingsVal($devname, sprintf("postme%02dName",$loop),""); $res.= sprintf(''; $res.= } FW_pO $res.''; } return ($FW_RETTYPE, $FW_RET); } #-- PostMe name if( !$listname ){ Log 1,"[PostMe_widget] Error, web argument name=... is missing"; return undef; } $pmn = PostMe_Check($hash,$listname); if( !$pmn ){ Log 1,"[PostMe_widget] Error, a PostMe named $listname does not exist"; return undef; } ##################################################-- type=pin => single pin, only one list if( $type eq "pin"){ #-- jQuery rendering if( $style eq "jQuery"){ my $sel = sprintf("sel%02d",$pmn); $FW_RETTYPE = "text/html"; $FW_RET=""; $res .= $css; #-- we need our own jQuery object $res .= ''; $res .= ''; #-- this is for the selector $res .= '
'; $res .= '
'.$listname.'

'; $res .= '
'; #-- this is the scripting for the dialog box $res .= ''; FW_pO $res; #-- HTML rendering }elsif( $style eq "HTML"){ $FW_RETTYPE = "text/html"; $FW_RET=""; $res .= $css; $res .= '
'; if( $click == 0){ $res.= '
'; } FW_pO $res.''.$listname.'
'; #-- SVG rendering }else{ $FW_RETTYPE = "image/svg+xml"; $FW_RET=""; FW_pO ''; $res.= ''; FW_pO $res.''; } return ($FW_RETTYPE, $FW_RET); } ################################################## default (type missing) => content of a single postme my @lines=split(AttrVal($devname,"listseparator",','),ReadingsVal($devname, sprintf("postme%02dCont",$pmn),"")); if( !(int(@lines)>0) ){ #Log 1,"[PostMe_widget] Asking to display empty PostMe $listname"; return undef; } #-- HTML rendering if( $style ne "SVG"){ $FW_RETTYPE = "text/html; charset=$FW_encoding"; $FW_RET=""; $res .= $css; $res .= '
'; $res .= ''.$listname.'
'; for (my $i=0;$i'; } FW_pO $res.'
'; #--- SVG rendering }else{ $FW_RETTYPE = "image/svg+xml"; $FW_RET=""; FW_pO ''; $res = ''; $res.= $listname.''; for (my $i=0;$i',25+$i*12); $res.= PostMe_LineOut($hash,$listname,$lines[$i],0); $res.= ''; } FW_pO $res.''; } return ($FW_RETTYPE, $FW_RET); } 1; =pod =item helper =item summary to set up a system of sticky notes, similar to Post-Its™ =item summary_DE zur Definition eines Systems von Klebezetteln ähnlich des Post-Its™ =begin html

PostMe

    FHEM module to set up a system of sticky notes, similar to Post-Its™

    Define

    define <postit> PostMe
    Defines the PostMe system, <postit> is an arbitrary name for the system.

    Usage

    See German Wiki page
    An arbitrary number of lists may be added to the system with the create command.
    List items may consist of one or more words, and are added/removed by the add and remove command, but no separator characters are allowed in one item
    Attention: A comma "," is the default separator for list items, see attributes below.

    Meta data for items (=annotations)may be included in the items by using "[" and "]"; characters, e.g.
    set <postit> add <name> <item> [<attribute1>="<data1>" ...
    These attribute-value pairs may be added, modified and removed with the modify command.

    Special annotations will be evaluated further, either on creation or manually by executing the commands
    get <postit> special <name> resp. get <postit> allspecial

    • The attribute at="<timespec/datespec>", when given a timespec/datespec value, will result in a single or multiple reminding messages for this item. The syntax for this timespec/datespec value is
      (<HH:MM>|<HH:MM:SS>|<YYYY-MM-DD>T<HH:MM:SS>)[-<HH:MM>[P<number>]]
      The first part is the time/date specification when the item is due.
      The second optional part beginning with a "-"-sign denotes how much time befor this date you want to be alerted.
      The third optional part beginning with a "P" character allows to specify a <number> of periodic reminders, the period given by the second part.
      Processing this attribute means, that several at devices will be set up in the room hidden that are triggered when at the specified times. See documentation in Wiki for examples.
    • The attribute notify="<eventspec>", when given an eventspec value, will result in a single or multiple reminding messages for this item.
      Processing this attribute means, that a notify device will be set up in the room hidden that is triggered when the event is detected.
    The sticky notes may be integrated into any Web page by simply embedding the following tags
    • <embed src="/fhem/PostMe_widget?type=pins&postit=<postit>"/>
      to produce an interactive list of all PostMe names with pins from system <postit>.
    • <embed src="/fhem/PostMe_widget?type=pin&postit=<postit>&name=<name>"/>
      to produce an interactive entry for PostMe <name>from system <postit>

    The module provides interface routines that may be called from your own Perl programs, see documentation in the Wiki.

    Set

    • set <postit> create <name>
      creates a sticky note named <name>
    • set <postit> rename <name> <newname>
      renames the sticky note named <name> as <newname>
    • set <postit> delete <name>
      deletes the sticky note named <name>
    • set <postit> add <name> <item>
      adds to the sticky note named <name> an item <item>
    • set <postit> modify <name> <item> <attribute> <data>
      adds/modifies/removes and attribute-value-pair <attribute>="<data>" to the item <item> on the sticky note named <name>
      adding, if this attribute is not yet present; modification, if it is present - <data> will then be overwritten; removal, if no <data> is given
    • set <postit> remove <name> <item>
      set <postit> remove <name> item<number>
      removes from the sticky note named <name> an item <item> or the one numbered <number> (starting at 0)
    • set <postit> clear <name>
      clears the sticky note named <name> from all items

    Get

    • get <postit> list <name>
      Show the sticky note named <name> and its content
    • get <postit> special <name>
      Process the special annotations (see above) of the sticky note named <name>
    • get <postit> mail <name>
      Send the sticky note named <name> and its content via eMail to a predefined recipient (e.g. sticky note <postme01Name> is sent to <postme01MailRec>).
      The mailing subroutine is called with three parameters for recipient, subject and text.
    • get <postit> message <name>
      Send the sticky note named <name> and its content via instant messenger to a predefined recipient (e.g. sticky note <postme01Name> is sent to <postme01MsgRec>).
      The messenger subroutine is called with three parameters for recipient, subject and text.
    • get <postit> TTS <name>
      Speak the sticky note named <name> and its content. The TTS subroutine is called with one parameter text.
    • get <postit> JSON <name>
      Return the sticky note named <name> in JSON format
    • get <postit> all
      Show all sticky notes and their content
    • get <postit> allspecial
      Process the special annotations (see above) of all sticky notes
    • get <postit> version
      Display the version of the module

    Attributes

    • attr <postit> postmeStd <name1,name2,...>
      Comma separated list of standard sticky notes that will be created on device start.
    • attr <postit> postmeClick 1|0 (default)
      If 0, embedded sticky notes will pop up on mouseover-events and vanish on mouseout-events (default).
      If 1, embedded sticky notes will pop up on click events and vanish after closing the note
    • attr <postit> postmeIcon <string>
      Icon for display of a sticky note
    • attr <postit> postmeStyle SVG|HTML|jQuery (default)
      If jQuery, embedded sticky notes will produce jQuery code (default)
      If HTML, embedded sticky notes will produce HTML code
      If SVG, embedded sticky notes will produce SVG code
    • attr <postit> listseparator <character>
      Character used to separate list items (default ',')
    Note, that in the parameters sent to the following functions, ":" serves as separator between list name and items, and "," serves as separator between items. They may be exchanged with simple regular expression operations.
    • attr <postit> postmeMailFun <string>
      Function name for the eMail function. This subroutine is called with three parameters for recipient, subject and text.
    • attr <postit> postmeMailRec(01|02|...) <string> recipient addresses for the above eMail function (per PostMe).
    • attr <postit> postmeMsgFun <string>
      Function name for the instant messenger function. This subroutine is called with three parameters for recipient, subject and text.
    • attr <postit> postmeMsgRec(01|02|...) <string> recipient addresses for the above instant messenger function (per PostMe).
    • attr <postit> postmeTTSFun <string>
      Function name for the text-to-speech function. This subroutine is called with two parameters, the device name and the composite text.
    • attr <postit> postmeTTSDev(01|02|...) <string> device name for the above TTS function.
    • Standard attributes alias, comment, event-on-update-reading, event-on-change-reading, room, eventMap, loglevel, webCmd
=end html =begin html_DE

PostMe

=end html_DE =cut