diff --git a/fhem/FHEM/36_KeyValueProtocol.pm b/fhem/FHEM/36_KeyValueProtocol.pm new file mode 100644 index 000000000..7a0227b9b --- /dev/null +++ b/fhem/FHEM/36_KeyValueProtocol.pm @@ -0,0 +1,252 @@ +# $Id$ + +# ToDo-List +# --------- +# - option to restrict the readings to the defined Mapping + +# MatchList: add "8:KeyValueProtocol" => "^OK\\sVALUES\\s" +# Clients: add KeyValueProtocol + +# Test data +# --------- +# set myJeeLink parse OK VALUES LGW 12345 UpTime=2345678, SSID=MyCoolNetwork,LastReceiveTime=2015-11-17 13:39:14,Mode=OK,Connected,Cool,OTA=Ready +# set myJeeLink parse OK VALUES DAVIS 0 Channel=3, RSSI=-81, Battery=ok, WindSpeed=0, WindDirection=-36, TemperatureOutside=55.90 +# 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 +# set myJeeLink parse OK VALUES LGW 12345 U=2345678, S=MyCoolNetwork,T=2015-11-17 13:39:14,M=OK,Connected,Cool,O=Ready +# attr KeyValueProtocol_LGW_12345 Mapping U=UpTime,S=SSID,T=LastReceptionDate,M=Mode,O=OTA-State +# set myJeeLink parse INIT DICTIONARY U=UpTime,M=MessagesPerMinute,S=SSID + +package main; + +use strict; +use warnings; +use SetExtensions; + +#======================================================================================= +sub KeyValueProtocol_Initialize($) { + my ($hash) = @_; + + $hash->{Match} = "^OK\\sVALUES\\s"; + $hash->{DefFn} = "KeyValueProtocol_Define"; + $hash->{UndefFn} = "KeyValueProtocol_Undef"; + $hash->{FingerprintFn} = "KeyValueProtocol_Fingerprint"; + $hash->{ParseFn} = "KeyValueProtocol_Parse"; + $hash->{SetFn} = "KeyValueProtocol_Set"; + $hash->{GetFn} = "KeyValueProtocol_Get"; + $hash->{AttrFn} = "KeyValueProtocol_Attr"; + $hash->{AttrList} = "IODev " . + "Mapping " . + "$readingFnAttributes "; + +} + + +#======================================================================================= +sub KeyValueProtocol_Define($$) { + my ( $hash, $def ) = @_; + my @a = split( "[ \t][ \t]*", $def ); + + return "Usage: define KeyValueProtocol " if(@a < 4); + + my $name = $a[0]; + my $type = $a[2]; + my $id = $a[2] . "_" . $a[3]; + + $hash->{STATE} = 'Initialized'; + $hash->{NAME} = $name; + $hash->{model} = $type; + $hash->{ID} = $id; + + $modules{KeyValueProtocol}{defptr}{$id} = $hash; + + AssignIoPort($hash); + if(defined($hash->{IODev}->{NAME})) { + Log3 $name, 4, "$name: I/O device is " . $hash->{IODev}->{NAME}; + } + else { + Log3 $name, 1, "$name: no I/O device"; + } + + return undef; +} + + +#======================================================================================= +sub KeyValueProtocol_Undef($$) { + my ($hash, $arg) = @_; + my $id = $hash->{ID}; + + delete($modules{KeyValueProtocol}{defptr}{$id}); + + return undef; +} + + +#======================================================================================= +sub KeyValueProtocol_Get($@) { + my ($hash, $name, $cmd, @args) = @_; + + + return undef; +} + + +#======================================================================================= +sub KeyValueProtocol_Set($@) { + my ($hash, $name, $cmd, @args) = @_; + + return undef; +} + + +#======================================================================================= +sub KeyValueProtocol_Fingerprint($$) { + my ($name, $msg) = @_; + return ("", $msg); +} + + +#======================================================================================= +sub KeyValueProtocol_Attr(@) { + my ($cmd, $name, $attrName, $attrVal) = @_; + + return undef; +} + + +#======================================================================================= +sub KeyValueProtocol_Parse($$) { + my ($hash, $msg) = @_; + my $name = $hash->{NAME}; + my $buffer = $msg; + + if( $msg =~ m/^OK VALUES/) { + my @parts = split(' ', substr($msg, 10)); + my $sensorType = $parts[0]; + my $id = $parts[0] . "_" . $parts[1]; + + if($modules{KeyValueProtocol}{defptr}{$id}) { + my $rhash = $modules{KeyValueProtocol}{defptr}{$id}; + my $rname = $rhash->{NAME}; + + my %mappings; + # our "Mapping" attribute has priority + my $mappingsString = AttrVal($rname, "Mapping", ""); + if ($mappingsString) { + %mappings = split (/[,=]/, AttrVal($rname, "Mapping", "")); + } + else { + # Do we have initMessages in the IODevice? + if ($rhash->{IODev}->{initMessages}) { + my @ima = split('\n', $rhash->{IODev}->{initMessages}); + for my $i (0 .. $#ima) { + my @im = split("INIT DICTIONARY ", $ima[$i]); + if ($im[1]) { + %mappings = split (/[,=]/, $im[1]); + last; + } + } + } + } + + readingsBeginUpdate($rhash); + + my @kvPairs; + my @data = split(',', substr($msg, 12 + length($parts[0]) + length($parts[1]))); + for my $i (0 .. $#data) { + if(@kvPairs && index($data[$i], "=") == -1) { + splice(@kvPairs, @kvPairs -1, 1, $kvPairs[@kvPairs -1] . "," . $data[$i]); + } + else { + push(@kvPairs, $data[$i]); + } + } + + while (@kvPairs) { + my $kvPairString = shift(@kvPairs); + my @kvPair = split('=', $kvPairString, 2); + + my $value = $kvPair[1]; + + my $key = $kvPair[0]; + $key =~ s/^\s+|\s+$//g; + if (%mappings) { + my $newKey = $mappings{$key}; + $key = $newKey if ($newKey); + } + + readingsBulkUpdate($rhash, $key, $value); + } + + readingsEndUpdate($rhash, 1); + + my @list; + push(@list, $rname); + return @list; + } + else { + return "UNDEFINED KeyValueProtocol_$id KeyValueProtocol $parts[0] $parts[1]"; + } + } +} + +1; + +=pod +=begin html + + +

KeyValueProtocol

+ +
    + A generic module to receive key-value-pairs from an IODevice like JeeLink.
    + The data source can send any key/value pairs, which will get converted into readings.
    + The protocol that the sketch must send is: OK VALUES Key1=Value1,Key2=Value2, ...
    +
    + + + Define +
      + define <name> KeyValueProtocol <Type> <ID>
      +
      +
    + + + Set +
      + +
    +
    + + + Get +
      + +
    +
    + + + Attributes +
      +
    • Dictionary
      + The Dictionary attribute can optionally be used to translate the Keys.
      + The format is: ReceivedKey1=NewKey1,ReceivedKey2=NewKey2, ...
      + The Sketch can then send short Keys, which will get translated to long names.
      + Example: attr myKVP Dictionary T=Temperature,H=Humidity
      + If the sketch then sends: OK VALUES T=12,H=70
      + you will get the readings Temperature and Humidity with the Values 12 and 70
      +
    • +
    +
    + + + Readings
    +
      + Depending on the received data +
    +
    + +
+ +=end html +=cut diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index f39202a98..d1b7f04b3 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -145,6 +145,7 @@ FHEM/36_EC3000.pm justme1968 http://forum.fhem.de Sonstige FHEM/36_EleroDrive.pm HCS http://forum.fhem.de Sonstige Systeme FHEM/36_EleroStick.pm HCS http://forum.fhem.de Sonstige Systeme FHEM/36_JeeLink.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/36_KeyValueProtocol.pm HCS http://forum.fhem.de Sonstige Systeme FHEM/36_PCA301.pm justme1968 http://forum.fhem.de Sonstige Systeme FHEM/36_LaCrosse.pm HCS http://forum.fhem.de Sonstige Systeme FHEM/36_EMT7110.pm HCS http://forum.fhem.de Sonstige Systeme