76_MSGFile.pm 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. ########################################################
  2. # $Id: 76_MSGFile.pm 12024 2016-08-21 09:48:42Z gandy92 $
  3. ########################################################
  4. #
  5. # History:
  6. #
  7. # 2015-05-09: Assimilate file related code from 75_MSG
  8. # 2015-05-06: Tidy up code for restructuring
  9. # 2015-05-05: Remove dependency on Switch
  10. # 2012 : Created by rbente
  11. #
  12. package main;
  13. use strict;
  14. use warnings;
  15. my %sets = (
  16. "add" => "MSGFile",
  17. "clear" => "MSGFile",
  18. "list" => "MSGFile",
  19. "write" => "MSGFile"
  20. );
  21. ##############################################
  22. # Initialize Function
  23. # Attributes are:
  24. # filename the name of the file
  25. # filemode new = file will be created from scratch
  26. # append = add the new lines to the end of the existing data
  27. # CR 0 = no CR added to the end of the line
  28. # 1 = CR added to the end of the line
  29. ##############################################
  30. sub MSGFile_Initialize($)
  31. {
  32. my ($hash) = @_;
  33. $hash->{SetFn} = "MSGFile_Set";
  34. $hash->{DefFn} = "MSGFile_Define";
  35. $hash->{UndefFn} = "MSGFile_Undef";
  36. $hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 filename filemode:new,append CR:0,1";
  37. }
  38. ##############################################
  39. # Define Function
  40. # set the counter to 0
  41. # and filemode to "new"
  42. ##############################################
  43. sub MSGFile_Define($$)
  44. {
  45. my ($hash, $def) = @_;
  46. my @a = split("[ \t][ \t]*", $def);
  47. my $errmsg = "wrong syntax: define <name> MSGFile filename";
  48. my $name = $hash->{NAME};
  49. return $errmsg if (@a != 3);
  50. $attr{$name}{filename} = $a[2];
  51. $attr{$name}{filemode} = "new";
  52. $attr{$name}{CR} = "1";
  53. $hash->{STATE} = "ready";
  54. $hash->{TYPE} = "MSGFile";
  55. $hash->{READINGS}{msgcount}{TIME} = TimeNow();
  56. $hash->{READINGS}{msgcount}{VAL} = 0;
  57. return undef;
  58. }
  59. ##############################################
  60. # Undefine Function
  61. # flush all lines of data
  62. ##############################################
  63. sub MSGFile_Undef($$)
  64. {
  65. my ($hash, $name) = @_;
  66. my $i;
  67. # flush the data
  68. for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
  69. {
  70. $data{$name}{$i} = "";
  71. }
  72. delete($modules{MSGFile}{defptr}{ $hash->{CODE} }) if ($hash && $hash->{CODE});
  73. return undef;
  74. }
  75. ##############################################
  76. # Set Function
  77. # all the data are stored in the global array @data
  78. # as counter we use a READING named msgcount
  79. ##############################################
  80. sub MSGFile_Set($@)
  81. {
  82. my ($hash, @a) = @_;
  83. return "Unknown argument $a[1], choose one of -> " . join(" ", sort keys %sets)
  84. if (!defined($sets{ $a[1] }));
  85. my $name = shift @a;
  86. return "no set value specified" if (int(@a) < 1);
  87. return "Unknown argument ?" if ($a[0] eq "?");
  88. my $v = join(" ", @a);
  89. # we like to add another line of data
  90. if ($a[0] eq "add")
  91. {
  92. # split the line in command and data
  93. my $mx = shift @a;
  94. my $my = join(" ", @a);
  95. # check if we like to have and CR at the end of the line
  96. if (AttrVal($name, "CR", "0") eq "1")
  97. {
  98. $my = $my . "\n";
  99. }
  100. # get the highest number of lines, store the line in @data and increase
  101. # the counter, at the end set the status
  102. my $count = $hash->{READINGS}{msgcount}{VAL};
  103. $data{$name}{$count} = $my;
  104. $hash->{READINGS}{msgcount}{TIME} = TimeNow();
  105. $hash->{READINGS}{msgcount}{VAL} = $count + 1;
  106. $hash->{STATE} = "addmsg";
  107. }
  108. # we like to clear our buffer, first clear all lines of @data
  109. # and then set the counter to 0 and the status to clear
  110. elsif ($a[0] eq "clear")
  111. {
  112. my $i;
  113. for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
  114. {
  115. $data{$name}{$i} = "";
  116. }
  117. $hash->{READINGS}{msgcount}{TIME} = TimeNow();
  118. $hash->{READINGS}{msgcount}{VAL} = 0;
  119. $hash->{STATE} = "clear";
  120. }
  121. # we like to see the buffer
  122. elsif ($a[0] eq "list")
  123. {
  124. my $i;
  125. my $mess = "---- Lines of data for $name ----\n";
  126. for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
  127. {
  128. $mess .= $data{$name}{$i};
  129. }
  130. return "$mess---- End of data for $name ----";
  131. }
  132. elsif ($a[0] eq "write")
  133. {
  134. return "No filename specified, use attr <name> filename <filename> $name $defs{$name}{TYPE}"
  135. if (!AttrVal($name, "filename", ""));
  136. # open the file, new = delete file before create it
  137. # append = add lines to the existing file contents
  138. if (AttrVal($name, "filemode", "") eq "new")
  139. {
  140. open(FHEMMSGFILE, ">" . AttrVal($name, "filename", ""))
  141. || return "Can not open the file: $!";
  142. }
  143. else
  144. {
  145. open(FHEMMSGFILE, ">>" . AttrVal($name, "filename", ""))
  146. || return "Can not open the file: $!";
  147. }
  148. # loop thru the stored lines and write them to the file
  149. # number of lines are in the Readings / msgcount
  150. my $i;
  151. if (ReadingsVal($name, "msgcount", 0) > 0)
  152. {
  153. for ($i = 0 ; $i < ReadingsVal($name, "msgcount", 0) ; $i++)
  154. {
  155. print FHEMMSGFILE $data{ $name }{$i}
  156. || return "Can not write to the file: $!";
  157. }
  158. }
  159. # close the file and send a message to the log
  160. close(FHEMMSGFILE);
  161. Log 1, "<MSG> write to File: " . AttrVal($name, "filename", "");
  162. } # END MSGFile
  163. Log GetLogLevel($name, 2), "messenger set $name $v";
  164. # set stats
  165. # $hash->{CHANGED}[0] = $v;
  166. $hash->{READINGS}{state}{TIME} = TimeNow();
  167. $hash->{READINGS}{state}{VAL} = $v;
  168. return undef;
  169. }
  170. 1;
  171. =pod
  172. =item device
  173. =item summary write text to a file on the filesystem
  174. =begin html
  175. <a name="MSGFile"></a>
  176. <h3>MSGFile</h3>
  177. <ul>
  178. The MSGFile device is used to write arbitrary data to a file on disk
  179. or other media accessable through the filesystem. In order to write to a file,
  180. the access rights of the FHEM process to the specified file and path are relevant.
  181. To set the rights for a directory, please use OS related commands.
  182. <br><br>
  183. <a name="MSGFileDefine"></a>
  184. <b>Define</b>
  185. <ul><br>
  186. <code>define &lt;name&gt; MSGFile &lt;filename&gt;</code><br><br>
  187. Specifies the MSGFile device. At definition the message counter is set to 0.
  188. A filename must be specified at definition.
  189. </ul>
  190. <br>
  191. Examples:
  192. <ul>
  193. <code>define myFile MSGFile</code>
  194. </ul><br>
  195. <a name="MSGFileSet"></a>
  196. <b>Set</b><br>
  197. <ul><code>set &lt;name&gt; add|clear|list|write [text]</code><br>
  198. Set is used to manipulate the message buffer of the device. The message
  199. buffer is an array of lines of data, stored serial based on the incoming
  200. time into the buffer. Lines of data inside the buffer could not be deleted
  201. anymore, except of flashing the whole buffer.<br>
  202. <ul><b>add</b><br> to add lines of data to the message buffer. All data behind
  203. "add" will be interpreted as text message. To add a carriage return to the data,
  204. please use the CR attribute.
  205. </ul>
  206. <ul><b>clear</b><br> to flash the message buffer and set the line counter to 0.
  207. All the lines of data are deleted and the buffer is flushed.</ul>
  208. <ul><b>list</b><br> to list the message buffer.</ul><br>
  209. <ul><b>write</b><br> to write the message buffer to the associated file.</ul><br>
  210. </ul><br>
  211. Examples:
  212. <ul>
  213. <code>set myFile add Dies ist Textzeile 1</code><br>
  214. <code>set myFile add Dies ist Textzeile 2</code><br>
  215. <code>set myFile clear</code><br>
  216. <br>
  217. Full working example to write two lines of data to a file:<br>
  218. <code>define myFile MSGFile /tmp/fhemtest.txt</code><br>
  219. <code>attr myFile filemode append</code><br>
  220. <code>set myFile add Textzeile 1</code><br>
  221. <code>set myFile add Textzeile 2</code><br>
  222. <code>set myFile write</code><br>
  223. <code>set myFile clear</code><br>
  224. </ul><br>
  225. <a name="MSGFileVattr"></a>
  226. <b>Attributes</b>
  227. <ul>
  228. <li><a href="MSGFilefilename">filename</a><br>
  229. sets the filename, must be a fully qualified filename.
  230. FHEM must have the rights to write this file to the directory</li>
  231. <li><a href="MSGFilefilemode">filemode</a><br>
  232. sets the filemode, valid are "new" or "append"<br>
  233. new creates a new, empty file and writes the data to this file. Existing files are cleared, the data is lost!<br>
  234. append uses, if available, an existing file and writes the
  235. buffer data to the end of the file. If the file do not exist, it will
  236. be created</li>
  237. <li><a href="MSGFilenameCR">CR</a><br>
  238. set the option to write a carriage return at the end of the line.
  239. CR could be set to 0 or 1, 1 enables this feature</li>
  240. <li><a href="#loglevel">loglevel</a></li>
  241. </ul>
  242. </ul>
  243. =end html
  244. =cut