36_KeyValueProtocol.pm 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. # $Id: 36_KeyValueProtocol.pm 13540 2017-02-27 19:31:25Z HCS $
  2. # ToDo-List
  3. # ---------
  4. # - option to restrict the readings to the defined Mapping
  5. # MatchList: add "8:KeyValueProtocol" => "^OK\\sVALUES\\s"
  6. # Clients: add KeyValueProtocol
  7. # Test data
  8. # ---------
  9. # set myJeeLink parse OK VALUES LGW 12345 UpTime=2345678, SSID=MyCoolNetwork,LastReceiveTime=2015-11-17 13:39:14,Mode=OK,Connected,Cool,OTA=Ready
  10. # set myJeeLink parse OK VALUES DAVIS 0 Channel=3, RSSI=-81, Battery=ok, WindSpeed=0, WindDirection=-36, TemperatureOutside=55.90
  11. # set myJeeLink parse OK VALUES LGW 12345 UpTime=2345678, SSID=MyCoolNetwork,LastReceiveTime=2015-11-17 13:39:14,2015-11-18 14:15:16, Mode=OK,Connected,Cool,OTA=Ready
  12. # set myJeeLink parse OK VALUES LGW 12345 U=2345678, S=MyCoolNetwork,T=2015-11-17 13:39:14,M=OK,Connected,Cool,O=Ready
  13. # attr KeyValueProtocol_LGW_12345 Mapping U=UpTime,S=SSID,T=LastReceptionDate,M=Mode,O=OTA-State
  14. # set myJeeLink parse INIT DICTIONARY U=UpTime,M=MessagesPerMinute,S=SSID
  15. package main;
  16. use strict;
  17. use warnings;
  18. use SetExtensions;
  19. #=======================================================================================
  20. sub KeyValueProtocol_Initialize($) {
  21. my ($hash) = @_;
  22. $hash->{Match} = "^OK\\sVALUES\\s";
  23. $hash->{DefFn} = "KeyValueProtocol_Define";
  24. $hash->{UndefFn} = "KeyValueProtocol_Undef";
  25. $hash->{FingerprintFn} = "KeyValueProtocol_Fingerprint";
  26. $hash->{ParseFn} = "KeyValueProtocol_Parse";
  27. $hash->{SetFn} = "KeyValueProtocol_Set";
  28. $hash->{GetFn} = "KeyValueProtocol_Get";
  29. $hash->{AttrFn} = "KeyValueProtocol_Attr";
  30. $hash->{AttrList} = "IODev " .
  31. "Mapping " .
  32. "$readingFnAttributes ";
  33. }
  34. #=======================================================================================
  35. sub KeyValueProtocol_Define($$) {
  36. my ( $hash, $def ) = @_;
  37. my @a = split( "[ \t][ \t]*", $def );
  38. return "Usage: define <name> KeyValueProtocol <Type> <ID>" if(@a < 4);
  39. my $name = $a[0];
  40. my $type = $a[2];
  41. my $id = $a[2] . "_" . $a[3];
  42. $hash->{STATE} = 'Initialized';
  43. $hash->{NAME} = $name;
  44. $hash->{model} = $type;
  45. $hash->{ID} = $id;
  46. $modules{KeyValueProtocol}{defptr}{$id} = $hash;
  47. AssignIoPort($hash);
  48. if(defined($hash->{IODev}->{NAME})) {
  49. Log3 $name, 4, "$name: I/O device is " . $hash->{IODev}->{NAME};
  50. }
  51. else {
  52. Log3 $name, 1, "$name: no I/O device";
  53. }
  54. return undef;
  55. }
  56. #=======================================================================================
  57. sub KeyValueProtocol_Undef($$) {
  58. my ($hash, $arg) = @_;
  59. my $id = $hash->{ID};
  60. delete($modules{KeyValueProtocol}{defptr}{$id});
  61. return undef;
  62. }
  63. #=======================================================================================
  64. sub KeyValueProtocol_Get($@) {
  65. my ($hash, $name, $cmd, @args) = @_;
  66. return undef;
  67. }
  68. #=======================================================================================
  69. sub KeyValueProtocol_Set($@) {
  70. my ($hash, $name, $cmd, @args) = @_;
  71. return undef;
  72. }
  73. #=======================================================================================
  74. sub KeyValueProtocol_Fingerprint($$) {
  75. my ($name, $msg) = @_;
  76. return ("", $msg);
  77. }
  78. #=======================================================================================
  79. sub KeyValueProtocol_Attr(@) {
  80. my ($cmd, $name, $attrName, $attrVal) = @_;
  81. return undef;
  82. }
  83. #=======================================================================================
  84. sub KeyValueProtocol_Parse($$) {
  85. my ($hash, $msg) = @_;
  86. my $name = $hash->{NAME};
  87. my $buffer = $msg;
  88. if( $msg =~ m/^OK VALUES/) {
  89. my @parts = split(' ', substr($msg, 10));
  90. my $sensorType = $parts[0];
  91. my $id = $parts[0] . "_" . $parts[1];
  92. if($modules{KeyValueProtocol}{defptr}{$id}) {
  93. my $rhash = $modules{KeyValueProtocol}{defptr}{$id};
  94. my $rname = $rhash->{NAME};
  95. my %mappings;
  96. # our "Mapping" attribute has priority
  97. my $mappingsString = AttrVal($rname, "Mapping", "");
  98. $mappingsString = InternalVal($rname, AttrVal($rname, "IODev", "") . "_Mapping", "") if (!$mappingsString);
  99. if ($mappingsString) {
  100. %mappings = split (/[,=]/, $mappingsString);
  101. }
  102. else {
  103. # Do we have initMessages in the IODevice?
  104. if ($rhash->{IODev}->{initMessages}) {
  105. my @ima = split('\n', $rhash->{IODev}->{initMessages});
  106. for my $i (0 .. $#ima) {
  107. my @im = split("INIT DICTIONARY ", $ima[$i]);
  108. if ($im[1]) {
  109. %mappings = split (/[,=]/, $im[1]);
  110. last;
  111. }
  112. }
  113. }
  114. }
  115. readingsBeginUpdate($rhash);
  116. my @kvPairs;
  117. my @data = split(',', substr($msg, 12 + length($parts[0]) + length($parts[1])));
  118. for my $i (0 .. $#data) {
  119. if(@kvPairs && index($data[$i], "=") == -1) {
  120. splice(@kvPairs, @kvPairs -1, 1, $kvPairs[@kvPairs -1] . "," . $data[$i]);
  121. }
  122. else {
  123. push(@kvPairs, $data[$i]);
  124. }
  125. }
  126. while (@kvPairs) {
  127. my $kvPairString = shift(@kvPairs);
  128. my @kvPair = split('=', $kvPairString, 2);
  129. my $value = $kvPair[1];
  130. my $key = $kvPair[0];
  131. $key =~ s/^\s+|\s+$//g;
  132. if (%mappings) {
  133. my $newKey = $mappings{$key};
  134. $key = $newKey if ($newKey);
  135. }
  136. readingsBulkUpdate($rhash, $key, $value);
  137. }
  138. readingsEndUpdate($rhash, 1);
  139. my @list;
  140. push(@list, $rname);
  141. return @list;
  142. }
  143. else {
  144. return "UNDEFINED KeyValueProtocol_$id KeyValueProtocol $parts[0] $parts[1]";
  145. }
  146. }
  147. }
  148. 1;
  149. =pod
  150. =item summary A generic module to receive key-value-pairs from an IO-Device like JeeLink.
  151. =item summary_DE Empfängt key-value-pairs von einem IO-Device wie z.B. JeeLink.
  152. =begin html
  153. <a name="KeyValueProtocol"></a>
  154. <h3>KeyValueProtocol</h3>
  155. <ul>
  156. A generic module to receive key-value-pairs from an IODevice like JeeLink.<br>
  157. The data source can send any key/value pairs, which will get converted into readings.<br>
  158. The protocol that the sketch must send is: OK VALUES Key1=Value1,Key2=Value2, ...<br>
  159. <br>
  160. <a name="KeyValueProtocol_Define"></a>
  161. <b>Define</b>
  162. <ul>
  163. <code>define &lt;name&gt; KeyValueProtocol &lt;Type&gt &lt;ID&gt;</code> <br>
  164. <br>
  165. </ul>
  166. <a name="KeyValueProtocol_Set"></a>
  167. <b>Set</b>
  168. <ul>
  169. </ul>
  170. <br>
  171. <a name="KeyValueProtocol_Get"></a>
  172. <b>Get</b>
  173. <ul>
  174. </ul>
  175. <br>
  176. <a name="KeyValueProtocol_Attr"></a>
  177. <b>Attributes</b>
  178. <ul>
  179. <li>Mapping<br>
  180. The Mapping attribute can optionally be used to translate the Keys.<br>
  181. The format is: ReceivedKey1=NewKey1,ReceivedKey2=NewKey2, ...<br>
  182. The Sketch can then send short Keys, which will get translated to long names.<br>
  183. Example: attr myKVP Mapping T=Temperature,H=Humidity<br>
  184. If the sketch then sends: OK VALUES T=12,H=70<br>
  185. you will get the readings Temperature and Humidity with the Values 12 and 70<br>
  186. </li>
  187. </ul>
  188. <br>
  189. <a name="KeyValueProtocol_Readings"></a>
  190. <b>Readings</b><br>
  191. <ul>
  192. Depending on the received data
  193. </ul>
  194. <br>
  195. </ul>
  196. =end html
  197. =cut