2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-14 16:01:53 +00:00

10_EnOcean: Added new EEP: #

F6-01-01 (switch), F6-05-00 (windSpeed.00), F6-05-02 (smokeDetector.02), A5-09-0C (vocSensor.01), A5-14-07, A5-14-08 (doorContact), A5-14-09, A514-0A (windowContact), D2-05-02 (blindsCtrl.00), D2-B0-51 (liquidLeakage.51)
# security function: decrypt messages with R-ORG encapsulation
# commandref: further explanations added


git-svn-id: https://svn.fhem.de/fhem/trunk@12924 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
klaus.schauer 2017-01-01 09:18:17 +00:00
parent 13bb8339fb
commit 9541e45ed9

@ -1,15 +1,5 @@
############################################## ##############################################
# $Id$ # $Id$
# 2016-12-06
# Added new EEP:
# Remote Management:
# EEP changed:
# EnOcean_Notify():
# EnOcean_Attr():
# function SetExtensionsCancel() added
# subType hvac.01: attribute pidCtrl, model added
# commandref: further explanations added
package main; package main;
@ -223,6 +213,7 @@ my %EnO_eepConfig = (
"A5.09.09" => {attr => {subType => "CO2Sensor.01"}, GPLOT => "EnO_CO2:CO2,"}, "A5.09.09" => {attr => {subType => "CO2Sensor.01"}, GPLOT => "EnO_CO2:CO2,"},
"A5.09.0A" => {attr => {subType => "HSensor.01"}, GPLOT => "EnO_A5-09-0A:H/Temp,EnO_voltage4:Voltage,"}, "A5.09.0A" => {attr => {subType => "HSensor.01"}, GPLOT => "EnO_A5-09-0A:H/Temp,EnO_voltage4:Voltage,"},
"A5.09.0B" => {attr => {subType => "radiationSensor.01"}, GPLOT => "EnO_radioactivity4/Radioactivity,EnO_voltage4:Voltage,"}, "A5.09.0B" => {attr => {subType => "radiationSensor.01"}, GPLOT => "EnO_radioactivity4/Radioactivity,EnO_voltage4:Voltage,"},
"A5.09.0C" => {attr => {subType => "vocSensor.01"}, GPLOT => "EnO_A5-09-05:Concentration,"},
"A5.10.01" => {attr => {subType => "roomSensorControl.05"}, GPLOT => "EnO_temp4:Temp,"}, "A5.10.01" => {attr => {subType => "roomSensorControl.05"}, GPLOT => "EnO_temp4:Temp,"},
"A5.10.02" => {attr => {subType => "roomSensorControl.05"}, GPLOT => "EnO_temp4:Temp,"}, "A5.10.02" => {attr => {subType => "roomSensorControl.05"}, GPLOT => "EnO_temp4:Temp,"},
"A5.10.03" => {attr => {subType => "roomSensorControl.05", comMode => "confirm", subDef => "getNextID"}, GPLOT => "EnO_temp4:Temp,"}, "A5.10.03" => {attr => {subType => "roomSensorControl.05", comMode => "confirm", subDef => "getNextID"}, GPLOT => "EnO_temp4:Temp,"},
@ -283,6 +274,10 @@ my %EnO_eepConfig = (
"A5.14.04" => {attr => {subType => "multiFuncSensor"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"}, "A5.14.04" => {attr => {subType => "multiFuncSensor"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"},
"A5.14.05" => {attr => {subType => "multiFuncSensor"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"}, "A5.14.05" => {attr => {subType => "multiFuncSensor"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"},
"A5.14.06" => {attr => {subType => "multiFuncSensor"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"}, "A5.14.06" => {attr => {subType => "multiFuncSensor"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"},
"A5.14.07" => {attr => {subType => "doorContact"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"},
"A5.14.08" => {attr => {subType => "doorContact"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"},
"A5.14.09" => {attr => {subType => "windowContact"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"},
"A5.14.0A" => {attr => {subType => "windowContact"}, GPLOT => "EnO_A5-14-xx:Voltage/Brightness,EnO_A5-14-xx_2:Contact/Vibration,"},
"A5.20.01" => {attr => {subType => "hvac.01", webCmd => "setpointTemp"}, GPLOT => "EnO_A5-20-01:Temp/SetpointTemp/Setpoint,EnO_A5-20-01_2:PID,"}, "A5.20.01" => {attr => {subType => "hvac.01", webCmd => "setpointTemp"}, GPLOT => "EnO_A5-20-01:Temp/SetpointTemp/Setpoint,EnO_A5-20-01_2:PID,"},
#"A5.20.02" => {attr => {subType => "hvac.02"}}, #"A5.20.02" => {attr => {subType => "hvac.02"}},
#"A5.20.03" => {attr => {subType => "hvac.03"}}, #"A5.20.03" => {attr => {subType => "hvac.03"}},
@ -327,6 +322,7 @@ my %EnO_eepConfig = (
"D2.03.10" => {attr => {subType => "windowHandle.10"}, GPLOT => "EnO_windowHandle:WindowHandle,"}, "D2.03.10" => {attr => {subType => "windowHandle.10"}, GPLOT => "EnO_windowHandle:WindowHandle,"},
"D2.05.00" => {attr => {subType => "blindsCtrl.00", webCmd => "opens:stop:closes:position"}, GPLOT => "EnO_position4angle4:Position/AnglePos,"}, "D2.05.00" => {attr => {subType => "blindsCtrl.00", webCmd => "opens:stop:closes:position"}, GPLOT => "EnO_position4angle4:Position/AnglePos,"},
"D2.05.01" => {attr => {subType => "blindsCtrl.01", webCmd => "opens:stop:closes:position"}}, "D2.05.01" => {attr => {subType => "blindsCtrl.01", webCmd => "opens:stop:closes:position"}},
"D2.05.02" => {attr => {subType => "blindsCtrl.00", webCmd => "opens:stop:closes:position"}, GPLOT => "EnO_position4angle4:Position/AnglePos,"},
"D2.06.01" => {attr => {subType => "multisensor.01"}, GPLOT => "EnO_temp4humi4:Temp/Humi,EnO_brightness4:Brightness,"}, "D2.06.01" => {attr => {subType => "multisensor.01"}, GPLOT => "EnO_temp4humi4:Temp/Humi,EnO_brightness4:Brightness,"},
"D2.10.00" => {attr => {subType => "roomCtrlPanel.00", webCmd => "setpointTemp"}, GPLOT => "EnO_D2-10-xx:Temp/SPT/Humi,"}, "D2.10.00" => {attr => {subType => "roomCtrlPanel.00", webCmd => "setpointTemp"}, GPLOT => "EnO_D2-10-xx:Temp/SPT/Humi,"},
"D2.10.01" => {attr => {subType => "roomCtrlPanel.00", webCmd => "setpointTemp"}, GPLOT => "EnO_D2-10-xx:Temp/SPT/Humi,"}, "D2.10.01" => {attr => {subType => "roomCtrlPanel.00", webCmd => "setpointTemp"}, GPLOT => "EnO_D2-10-xx:Temp/SPT/Humi,"},
@ -350,7 +346,9 @@ my %EnO_eepConfig = (
"D2.50.10" => {attr => {subType => "heatRecovery.00", webCmd => "ventilation"}, GPLOT => "EnO_D2-50-xx:Temp/AirQuality,EnO_D2-50-xx_2:AirFlow/FanSpeed,"}, "D2.50.10" => {attr => {subType => "heatRecovery.00", webCmd => "ventilation"}, GPLOT => "EnO_D2-50-xx:Temp/AirQuality,EnO_D2-50-xx_2:AirFlow/FanSpeed,"},
"D2.50.11" => {attr => {subType => "heatRecovery.00", webCmd => "ventilation"}, GPLOT => "EnO_D2-50-xx:Temp/AirQuality,EnO_D2-50-xx_2:AirFlow/FanSpeed,"}, "D2.50.11" => {attr => {subType => "heatRecovery.00", webCmd => "ventilation"}, GPLOT => "EnO_D2-50-xx:Temp/AirQuality,EnO_D2-50-xx_2:AirFlow/FanSpeed,"},
"D2.A0.01" => {attr => {subType => "valveCtrl.00", defaultChannel => 0, webCmd => "opens:closes"}, GPLOT => "EnO_valveCtrl:Valve,"}, "D2.A0.01" => {attr => {subType => "valveCtrl.00", defaultChannel => 0, webCmd => "opens:closes"}, GPLOT => "EnO_valveCtrl:Valve,"},
"D2.B0.51" => {attr => {subType => "liquidLeakage.51"}, GPLOT => "EnO_liquidLeakage:LiquidLeakage,"},
"D5.00.01" => {attr => {subType => "contact", manufID => "7FF"}, GPLOT => "EnO_contact:Contact,"}, "D5.00.01" => {attr => {subType => "contact", manufID => "7FF"}, GPLOT => "EnO_contact:Contact,"},
"F6.01.01" => {attr => {subType => "switch", sensorMode => "pushbutton"}},
"F6.02.01" => {attr => {subType => "switch"}}, "F6.02.01" => {attr => {subType => "switch"}},
"F6.02.02" => {attr => {subType => "switch"}}, "F6.02.02" => {attr => {subType => "switch"}},
"F6.02.03" => {attr => {subType => "switch"}}, "F6.02.03" => {attr => {subType => "switch"}},
@ -359,7 +357,9 @@ my %EnO_eepConfig = (
"F6.03.02" => {attr => {subType => "switch"}}, "F6.03.02" => {attr => {subType => "switch"}},
"F6.04.01" => {attr => {subType => "keycard"}, GPLOT => "EnO_keycard:Keycard,"}, "F6.04.01" => {attr => {subType => "keycard"}, GPLOT => "EnO_keycard:Keycard,"},
#"F6.04.02" => {attr => {subType => "keycard.02"}, GPLOT => "EnO_keycard:Keycard,"}, #"F6.04.02" => {attr => {subType => "keycard.02"}, GPLOT => "EnO_keycard:Keycard,"},
"F6.05.00" => {attr => {subType => "windSpeed.00"}},
"F6.05.01" => {attr => {subType => "liquidLeakage"}, GPLOT => "EnO_liquidLeakage:LiquidLeakage,"}, "F6.05.01" => {attr => {subType => "liquidLeakage"}, GPLOT => "EnO_liquidLeakage:LiquidLeakage,"},
"F6.05.02" => {attr => {subType => "smokeDetector.02"}},
"F6.10.00" => {attr => {subType => "windowHandle"}, GPLOT => "EnO_windowHandle:WindowHandle,"}, "F6.10.00" => {attr => {subType => "windowHandle"}, GPLOT => "EnO_windowHandle:WindowHandle,"},
#"F6.10.01" => {attr => {subType => "windowHandle.01"}, GPLOT => "EnO_windowHandle:WindowHandle,"}, #"F6.10.01" => {attr => {subType => "windowHandle.01"}, GPLOT => "EnO_windowHandle:WindowHandle,"},
"F6.3F.7F" => {attr => {subType => "switch.7F"}}, "F6.3F.7F" => {attr => {subType => "switch.7F"}},
@ -373,7 +373,7 @@ my %EnO_eepConfig = (
"M5.38.08" => {attr => {subType => "gateway", eep => "A5-38-08", gwCmd => "switching", manufID => "00D", webCmd => "on:off"}}, "M5.38.08" => {attr => {subType => "gateway", eep => "A5-38-08", gwCmd => "switching", manufID => "00D", webCmd => "on:off"}},
"N5.38.08" => {attr => {subType => "gateway", comMode => "confirm", eep => "A5-38-08", gwCmd => "switching", manufID => "00D", model => "TF", teachMethod => "confirm", webCmd => "on:off"}}, "N5.38.08" => {attr => {subType => "gateway", comMode => "confirm", eep => "A5-38-08", gwCmd => "switching", manufID => "00D", model => "TF", teachMethod => "confirm", webCmd => "on:off"}},
"G5.ZZ.ZZ" => {attr => {subType => "PM101", manufID => "005"}, GPLOT => "EnO_motion:Motion,EnO_brightness4:Brightness,"}, "G5.ZZ.ZZ" => {attr => {subType => "PM101", manufID => "005"}, GPLOT => "EnO_motion:Motion,EnO_brightness4:Brightness,"},
"L6.02.01" => {attr => {subType => "FRW", eep => "F6-02-01", manufID => "00D"}}, "L6.02.01" => {attr => {subType => "smokeDetector.02", eep => "F6-05-02", manufID => "00D"}},
"ZZ.ZZ.ZZ" => {attr => {subType => "raw"}}, "ZZ.ZZ.ZZ" => {attr => {subType => "raw"}},
); );
@ -6443,8 +6443,35 @@ sub EnOcean_Set($@)
return "Wrong parameter, choose GPSD <data 1 ... 512 Byte hex> [status 1 Byte hex]"; return "Wrong parameter, choose GPSD <data 1 ... 512 Byte hex> [status 1 Byte hex]";
} }
} elsif ($cmd eq "SEC") {
# secure telegram
if ($a[1] && $a[1] =~ m/^[\dA-Fa-f]{2,28}$/ && !(length($a[1]) % 2)) {
$data = uc($a[1]);
$rorg = "30";
} else { } else {
return "Unknown argument $cmd, choose one of 1BS 4BS GPCD GPSD GPTI GPTR MSC RPS UTE VLD"; return "Wrong parameter, choose SEC <data 1 ... 14 Byte hex> [status 1 Byte hex]";
}
} elsif ($cmd eq "ENC") {
# secure telegram with encapsulation
if ($a[1] && $a[1] =~ m/^[\dA-Fa-f]{2,28}$/ && !(length($a[1]) % 2)) {
$data = uc($a[1]);
$rorg = "31";
} else {
return "Wrong parameter, choose ENC <data 1 ... 14 Byte hex> [status 1 Byte hex]";
}
} elsif ($cmd eq "STE") {
# secure Teach-In
if ($a[1] && $a[1] =~ m/^[\dA-Fa-f]{2,28}$/ && !(length($a[1]) % 2)) {
$data = uc($a[1]);
$rorg = "35";
} else {
return "Wrong parameter, choose STE <data 1 ... 14 Byte hex> [status 1 Byte hex]";
}
} else {
return "Unknown argument $cmd, choose one of 1BS 4BS ENC GPCD GPSD GPTI GPTR MSC RPS SEC STE UTE VLD";
} }
if ($a[2]) { if ($a[2]) {
if ($a[2] !~ m/^[\dA-Fa-f]{2}$/) { if ($a[2] !~ m/^[\dA-Fa-f]{2}$/) {
@ -6938,6 +6965,12 @@ sub EnOcean_Parse($$)
Log3 $name, 2, "EnOcean $name security ERROR: $err"; Log3 $name, 2, "EnOcean $name security ERROR: $err";
return ""; return "";
} }
} elsif ($rorg eq "35") {
# pass second teach-in telegram
} else {
Log3 $name, 2, "EnOcean $name unsecure telegram locked";
return "";
} }
if ($rorg eq "32") { if ($rorg eq "32") {
if (defined $eep) { if (defined $eep) {
@ -6955,12 +6988,6 @@ sub EnOcean_Parse($$)
return ""; return "";
} }
} }
} elsif ($rorg eq "35") {
# pass second teach-in telegram
} else {
Log3 $name, 2, "EnOcean $name unsecure telegram locked";
return "";
} }
} }
@ -6996,18 +7023,16 @@ sub EnOcean_Parse($$)
$st = $subtypeReading if (defined $subtypeReading); $st = $subtypeReading if (defined $subtypeReading);
if ($rorg eq "F6") { if ($rorg eq "F6") {
# RPS Telegram (PTM200) # RPS Telegram
# Rocker Switch (EEP F6-02-01 ... F6-03-02)
# Position Switch, Home and Office Application (EEP F6-04-01)
# Mechanical Handle (EEP F6-10-00)
my $event = "state"; my $event = "state";
my $nu = (hex($status) & 0x10) >> 4; my $nu = (hex($status) & 0x10) >> 4;
# unused flags (AFAIK) # unused flags (AFAIK)
#push @event, "1:T21:".((hex($status) & 0x20) >> 5); #push @event, "1:T21:".((hex($status) & 0x20) >> 5);
#push @event, "1:NU:$nu"; #push @event, "1:NU:$nu";
if ($st eq "FRW") { if ($st eq "FRW" || $st eq "smokeDetector.02") {
# smoke detector Eltako FRW # smoke detector
if (!exists($hash->{helper}{lastEvent}) || $hash->{helper}{lastEvent} != $db[0]) {
if ($db[0] == 0x30) { if ($db[0] == 0x30) {
push @event, "3:battery:low"; push @event, "3:battery:low";
} elsif ($db[0] == 0x10) { } elsif ($db[0] == 0x10) {
@ -7019,6 +7044,37 @@ sub EnOcean_Parse($$)
$msg = "off"; $msg = "off";
} }
push @event, "3:$event:$msg"; push @event, "3:$event:$msg";
$hash->{helper}{lastEvent} = $db[0];
}
@{$hash->{helper}{alarmTimer}} = ($hash, 'alarm', 'dead_sensor', 1, 5);
@{$hash->{helper}{stateTimer}} = ($hash, 'state', 'dead_sensor', 1, 5);
RemoveInternalTimer($hash->{helper}{alarmTimer});
RemoveInternalTimer($hash->{helper}{stateTimer});
InternalTimer(gettimeofday() + 1320, 'EnOcean_readingsSingleUpdate', $hash->{helper}{alarmTimer}, 0);
InternalTimer(gettimeofday() + 1320, 'EnOcean_readingsSingleUpdate', $hash->{helper}{stateTimer}, 0);
} elsif ($st eq "windSpeed.00") {
# wind speed threshold detector
if (!exists($hash->{helper}{lastEvent}) || $hash->{helper}{lastEvent} != $db[0]) {
if ($db[0] == 0x30) {
push @event, "3:battery:low";
} elsif ($db[0] == 0x10) {
push @event, "3:windSpeed:on";
$msg = "on";
} elsif ($db[0] == 0) {
push @event, "3:windSpeed:off";
push @event, "3:battery:ok";
$msg = "off";
}
push @event, "3:$event:$msg";
$hash->{helper}{lastEvent} = $db[0];
}
@{$hash->{helper}{windSpeedTimer}} = ($hash, 'windSpeed', 'dead_sensor', 1, 5);
@{$hash->{helper}{stateTimer}} = ($hash, 'state', 'dead_sensor', 1, 5);
RemoveInternalTimer($hash->{helper}{windSpeedTimer});
RemoveInternalTimer($hash->{helper}{stateTimer});
InternalTimer(gettimeofday() + 1320, 'EnOcean_readingsSingleUpdate', $hash->{helper}{windSpeedTimer}, 0);
InternalTimer(gettimeofday() + 1320, 'EnOcean_readingsSingleUpdate', $hash->{helper}{stateTimer}, 0);
} elsif ($model eq "FAE14" || $model eq "FHK14" || $model eq "FHK61") { } elsif ($model eq "FAE14" || $model eq "FHK14" || $model eq "FHK61") {
# heating/cooling relay FAE14, FHK14, untested # heating/cooling relay FAE14, FHK14, untested
@ -8216,7 +8272,7 @@ sub EnOcean_Parse($$)
push @event, "3:state:$rn"; push @event, "3:state:$rn";
} elsif ($st eq "vocSensor.01") { } elsif ($st eq "vocSensor.01") {
# Gas Sensor, VOC Sensor (EEP A5-09-05) # Gas Sensor, VOC Sensor (EEP A5-09-05, A5-09-0C)
# [untested] # [untested]
# $db[3]_bit_7 ... $db[2]_bit_0 is the VOC concentration where 0 = 0 ppb ... 65535 = 65535 ppb # $db[3]_bit_7 ... $db[2]_bit_0 is the VOC concentration where 0 = 0 ppb ... 65535 = 65535 ppb
# $db[1] is the VOC identification # $db[1] is the VOC identification
@ -8259,6 +8315,15 @@ sub EnOcean_Parse($$)
24 => "2-Butanol", 24 => "2-Butanol",
25 => "2-Methylpropanol", 25 => "2-Methylpropanol",
26 => "Diethyl Ether", 26 => "Diethyl Ether",
27 => "Naphthalene",
28 => "4-Phenylcyclohexene",
29 => "Limonene",
30 => "Tricloroethylene",
31 => "Isovaleric Acid",
32 => "Indole",
33 => "Cadaverine",
34 => "Putrescine",
35 => "Caproic Acid",
255 => "Ozone", 255 => "Ozone",
); );
if (exists $vocID{$db[1]}) { if (exists $vocID{$db[1]}) {
@ -8267,6 +8332,7 @@ sub EnOcean_Parse($$)
push @event, "3:vocName:unknown"; push @event, "3:vocName:unknown";
} }
push @event, "3:concentration:$vocConc"; push @event, "3:concentration:$vocConc";
push @event, "3:concentrationUnit:" . $db[0] & 4 ? 'ug/m3' : 'ppb';
push @event, "3:state:$vocConc"; push @event, "3:state:$vocConc";
} elsif ($st eq "particlesSensor.01") { } elsif ($st eq "particlesSensor.01") {
@ -9466,6 +9532,43 @@ sub EnOcean_Parse($$)
push @event, "3:voltage:$voltage"; push @event, "3:voltage:$voltage";
push @event, "3:state:C: $contact V: $vibration E: $lux U: $voltage"; push @event, "3:state:C: $contact V: $vibration E: $lux U: $voltage";
} elsif ($st eq "doorContact") {
# dual door contact (EEP A5-14-07, A5-14-08)
if (!exists($hash->{helper}{lastEvent}) || $hash->{helper}{lastEvent} ne $data) {
my $voltage = sprintf "%0.1f", $db[3] * 0.02;
my $doorContact = $db[0] & 4 ? 'open' : 'closed';
my $lockContact = $db[0] & 2 ? 'unlocked' : 'locked';
my $vibration = $db[0] & 1 ? 'on' : 'off';
push @event, "3:voltage:$voltage";
push @event, "3:contact:$doorContact";
push @event, "3:block:$lockContact";
push @event, "3:vibration:$vibration";
push @event, "3:state:C: $doorContact B: $lockContact V: $vibration U: $voltage";
$hash->{helper}{lastEvent} = $data;
}
CommandDeleteReading(undef, "$name alarm");
@{$hash->{helper}{alarmTimer}} = ($hash, 'alarm', 'dead_sensor', 1, 5);
RemoveInternalTimer($hash->{helper}{alarmTimer});
InternalTimer(gettimeofday() + 66, 'EnOcean_readingsSingleUpdate', $hash->{helper}{alarmTimer}, 0);
} elsif ($st eq "windowContact") {
# window contact (EEP A5-14-09, A5-14-0A)
if (!exists($hash->{helper}{lastEvent}) || $hash->{helper}{lastEvent} ne $data) {
my $voltage = sprintf "%0.1f", $db[3] * 0.02;
my %window = (0 => 'closed', 1 => 'tilt', 2 => 'reserved', 3 => 'open');
my $window = $window{(($db[0] & 6) >> 1)};
my $vibration = $db[0] & 1 ? 'on' : 'off';
push @event, "3:voltage:$voltage";
push @event, "3:window:$window";
push @event, "3:vibration:$vibration";
push @event, "3:state:W: $window V: $vibration U: $voltage";
$hash->{helper}{lastEvent} = $data;
}
CommandDeleteReading(undef, "$name alarm");
@{$hash->{helper}{alarmTimer}} = ($hash, 'alarm', 'dead_sensor', 1, 5);
RemoveInternalTimer($hash->{helper}{alarmTimer});
InternalTimer(gettimeofday() + 66, 'EnOcean_readingsSingleUpdate', $hash->{helper}{alarmTimer}, 0);
} elsif ($st =~ m/^digitalInput\.0[12]$/) { } elsif ($st =~ m/^digitalInput\.0[12]$/) {
# Digital Input (EEP A5-30-01, A5-30-02) # Digital Input (EEP A5-30-01, A5-30-02)
my $contact; my $contact;
@ -10931,6 +11034,10 @@ sub EnOcean_Parse($$)
} }
} }
} elsif ($st eq "liquidLeakage.51") {
# liquid leakage sensor
push @event, "3:state:" . $db[0] & 3 ? 'wet' : 'dry';
} elsif ($st eq "raw") { } elsif ($st eq "raw") {
# raw # raw
push @event, "3:state:RORG: $rorg DATA: $data STATUS: $status ODATA: $odata"; push @event, "3:state:RORG: $rorg DATA: $data STATUS: $status ODATA: $odata";
@ -10938,6 +11045,7 @@ sub EnOcean_Parse($$)
for (my $dbCntr = 0; $dbCntr <= $#db; $dbCntr++) { for (my $dbCntr = 0; $dbCntr <= $#db; $dbCntr++) {
push @event, "3:DB_" . $dbCntr . ":" . $db[$dbCntr]; push @event, "3:DB_" . $dbCntr . ":" . $db[$dbCntr];
} }
} else { } else {
# unknown devices # unknown devices
push @event, "3:state:$data"; push @event, "3:state:$data";
@ -15258,16 +15366,10 @@ sub EnOcean_sec_parseTeachIn($$$$) {
my $mac_algo = unpack('C',pack('B8', '000000'.$3)); # Padd to byte, parse as unsigned char my $mac_algo = unpack('C',pack('B8', '000000'.$3)); # Padd to byte, parse as unsigned char
my $data_enc = unpack('C',pack('B8', '00000'.$4)); # Padd to byte, parse as unsigned char my $data_enc = unpack('C',pack('B8', '00000'.$4)); # Padd to byte, parse as unsigned char
#print "IDX: $idx, CNT: $cnt, PSK: $psk, TYPE: $type, INFO: $info\n"
# The teach-in information is split in two telegrams due to the ERP1 limitations on telegram length # The teach-in information is split in two telegrams due to the ERP1 limitations on telegram length
# So we should get a telegram with index 0 and count 2 with the first half of the infos needed # So we should get a telegram with index 0 and count 2 with the first half of the infos needed
if ($idx == 0 && $cnt == 2) { if ($idx == 0 && $cnt == 2) {
# First part of the teach in message # First part of the teach in message
#print "First part of 2 part teach in message received\n";
#print "RLC_ALGO: $rlc_algo, RLC_TX: $rlc_tx, MAC_ALGO: $mac_algo, DATA_ENC: $data_enc\n";
#print "RLC and KEY are ". ($psk == 1 ? "" : "not") . " encrypted\n";
#print "Application is ". ($type == 1 ? "a PTM" : "non-specfic") . "\n";
# Decode teach in type # Decode teach in type
if ($type == 0) { if ($type == 0) {
@ -15406,9 +15508,11 @@ sub EnOcean_sec_parseTeachIn($$$$) {
return ("Could not parse data encryption information, $data_enc", undef); return ("Could not parse data encryption information, $data_enc", undef);
} }
$hash->{helper}{teachInSTE} = $cnt - 1;
# Ok we got a lots of infos and the first part of the private key # Ok we got a lots of infos and the first part of the private key
return (undef, "part1: $name"); return (undef, "part1: $name");
} elsif ($idx == 1 && $cnt == 0) {
} elsif ($idx == 1 && exists($hash->{helper}{teachInSTE})) {
# Second part of the teach-in telegrams # Second part of the teach-in telegrams
# Extract byte fields from telegram # Extract byte fields from telegram
@ -15443,7 +15547,7 @@ sub EnOcean_sec_parseTeachIn($$$$) {
Log3 $name, $logLevel, "EnOcean $name $response"; Log3 $name, $logLevel, "EnOcean $name $response";
} }
} }
# We're done delete $hash->{helper}{teachInSTE};
return (undef, "part2: $name"); return (undef, "part2: $name");
} }
@ -15653,21 +15757,14 @@ sub EnOcean_sec_convertToNonsecure($$$) {
return ("Cryptographic functions are not available", undef, undef); return ("Cryptographic functions are not available", undef, undef);
} }
my $private_key; my $private_key;
# Prefix of pattern to extract the different cryptographic infos # Prefix of pattern to extract the different cryptographic infos
my $crypt_pattern = "^(.*)";; my $crypt_pattern = "^(.*)";;
# Flags and infos for fields to expect # Flags and infos for fields to expect
my $expect_rlc = 0; my $expect_rlc = 0;
my $expect_mac = 0; my $expect_mac = 0;
my $mac_len; my $mac_len;
my $expect_enc = 0; my $expect_enc = 0;
# Check if the RORG is supported
if ($rorg ne '30') {
return ("RORG $rorg unsupported", undef, undef);
}
#$attr{$name}{rlcAlgo} = '2++';
# Check if RLC is transmitted and when, which length to expect # Check if RLC is transmitted and when, which length to expect
if($attr{$name}{rlcTX} eq 'true') { if($attr{$name}{rlcTX} eq 'true') {
# Message should contain RLC # Message should contain RLC
@ -15700,11 +15797,11 @@ sub EnOcean_sec_convertToNonsecure($$$) {
# Suffix for crypt pattern # Suffix for crypt pattern
$crypt_pattern .= '$'; $crypt_pattern .= '$';
#print "Crypt_pattern: $crypt_pattern\n";
# Extract byte fields from message payload # Extract byte fields from message payload
$crypt_data =~ /$crypt_pattern/; $crypt_data =~ /$crypt_pattern/;
my $data_enc = $1; my $data_enc = $1;
my $dataLength = length($data_enc);
return ("Telegrams with a length of more than 16 bytes are not supported", undef, undef) if ($dataLength > 32);
my $rlc; my $rlc;
my $mac; my $mac;
if ($expect_rlc == 1 && $expect_mac == 1) { if ($expect_rlc == 1 && $expect_mac == 1) {
@ -15714,11 +15811,10 @@ sub EnOcean_sec_convertToNonsecure($$$) {
$mac = $2; $mac = $2;
} }
#print "DATA: $data_enc\n"; Log3 $name, 5, "EnOcean $name EnOcean_sec_convertToNonsecure RORG: $rorg DATA_ENC: $data_enc";
Log3 $name, 5, "EnOcean $name EnOcean_sec_convertToNonsecure DATA: $data_enc"; if ($expect_rlc == 1) {
#if ($expect_rlc == 1) { print "RLC: $rlc\n";}; Log3 $name, 5, "EnOcean $name EnOcean_sec_convertToNonsecure RLC: $rlc";
if ($expect_rlc == 1) { Log3 $name, 5, "EnOcean $name EnOcean_sec_convertToNonsecure RLC: $rlc";}; };
#print "MAC: $mac\n";
Log3 $name, 5, "EnOcean $name EnOcean_sec_convertToNonsecure MAC: $mac"; Log3 $name, 5, "EnOcean $name EnOcean_sec_convertToNonsecure MAC: $mac";
# TODO RLC could be transmitted with data, could not test this # TODO RLC could be transmitted with data, could not test this
@ -15730,12 +15826,9 @@ sub EnOcean_sec_convertToNonsecure($$$) {
# Maximum RLC search window is 128 # Maximum RLC search window is 128
foreach my $rlc_window (0..128) { foreach my $rlc_window (0..128) {
#print "Trying RLC offset $rlc_window\n"; #print "Trying RLC offset $rlc_window\n";
# Fetch stored RLC # Fetch stored RLC
$rlc = EnOcean_sec_getRLC($hash, "rlcRcv"); $rlc = EnOcean_sec_getRLC($hash, "rlcRcv");
# Fetch private Key for VAES # Fetch private Key for VAES
if ($attr{$name}{keyRcv} =~ /[\dA-F]{32}/) { if ($attr{$name}{keyRcv} =~ /[\dA-F]{32}/) {
$private_key = pack('H32',$attr{$name}{keyRcv}); $private_key = pack('H32',$attr{$name}{keyRcv});
} else { } else {
@ -15743,9 +15836,8 @@ sub EnOcean_sec_convertToNonsecure($$$) {
} }
# Generate and check MAC over RORG+DATA+RLC fields # Generate and check MAC over RORG+DATA+RLC fields
if($mac eq EnOcean_sec_generateMAC($private_key, $rorg.$data_enc.$rlc, $mac_len)) { if ($mac eq EnOcean_sec_generateMAC($private_key, $rorg.$data_enc.$rlc, $mac_len)) {
#print "RLC verfified\n"; #print "RLC verfified\n";
# Expand RLC to 16byte # Expand RLC to 16byte
my $rlc_expanded = pack('H32',$rlc); my $rlc_expanded = pack('H32',$rlc);
@ -15754,13 +15846,17 @@ sub EnOcean_sec_convertToNonsecure($$$) {
# Decode data using VAES # Decode data using VAES
my $data_dec = EnOcean_sec_decodeVAES($rlc_expanded, $private_key, $data_expanded); my $data_dec = EnOcean_sec_decodeVAES($rlc_expanded, $private_key, $data_expanded);
# Extract one nibble of data
my $data_end = unpack('H32', $data_dec); my $data_end = unpack('H32', $data_dec);
if ($rorg eq '30') {
# Extract one nibble of data
$data_end =~ /^.(.)/; $data_end =~ /^.(.)/;
#print "MSG: $1\n";
return (undef, '32', "0" . uc($1)); return (undef, '32', "0" . uc($1));
} else {
$dataLength -= 2;
$data_end =~ /^(..)(.{$dataLength})/;
Log3 $name, 5, "EnOcean $name EnOcean_sec_convertToNonsecure RORG: " . uc($1) . " DATA: " . uc($2);
return (undef, uc($1), uc($2));
}
} }
} }
# Couldn't verify or decrypt message in RLC window # Couldn't verify or decrypt message in RLC window
@ -18530,7 +18626,7 @@ EnOcean_Delete($$)
</li> </li>
<br><br> <br><br>
<li>Pushbutton Switch, Pushbutton Input Module (EEP F6-02-01 ... F6-02-02)<br> <li>Pushbutton Switch, Pushbutton Input Module (EEP F6-02-01 ... F6-02-02, F6-01-01)<br>
[Eltako FT55, FSM12, FSM61, FTS12]<br> [Eltako FT55, FSM12, FSM61, FTS12]<br>
<ul> <ul>
<li>A0</li> <li>A0</li>
@ -18595,20 +18691,6 @@ EnOcean_Delete($$)
</li> </li>
<br><br> <br><br>
<li>Smoke Detector (EEP F6-02-01 ... F6-02-02)<br>
[Eltako FRW]<br>
<ul>
<li>smoke-alarm</li>
<li>off</li>
<li>alarm: smoke-alarm|off</li>
<li>battery: low|ok</li>
<li>buttons: pressed|released</li>
<li>state: smoke-alarm|off</li>
</ul><br>
Set attr subType to FRW manually.
</li>
<br><br>
<li>Heating/Cooling Relay (EEP F6-02-01 ... F6-02-02)<br> <li>Heating/Cooling Relay (EEP F6-02-01 ... F6-02-02)<br>
[Eltako FAE14, FHK14, untested]<br> [Eltako FAE14, FHK14, untested]<br>
<ul> <ul>
@ -18635,6 +18717,19 @@ EnOcean_Delete($$)
</li> </li>
<br><br> <br><br>
<li>Wind Speed Threshold Detector (EEP F6-05-00)<br>
<ul>
<li>dead_sensor</li>
<li>on</li>
<li>off</li>
<li>windSpeed: dead_sensor|on|off</li>
<li>battery: low|ok</li>
<li>state: dead_sensor|on|off</li>
</ul><br>
Set attr subType to windSpeed.00 manually.
</li>
<br><br>
<li>Liquid Leakage Sensor (EEP F6-05-01)<br> <li>Liquid Leakage Sensor (EEP F6-05-01)<br>
[untested]<br> [untested]<br>
<ul> <ul>
@ -18646,6 +18741,20 @@ EnOcean_Delete($$)
</li> </li>
<br><br> <br><br>
<li>Smoke Detector (EEP F6-05-02)<br>
[Eltako FRW]<br>
<ul>
<li>dead_sensor</li>
<li>smoke-alarm</li>
<li>off</li>
<li>alarm: dead_sensor|smoke-alarm|off</li>
<li>battery: low|ok</li>
<li>state: dead_sensor|smoke-alarm|off</li>
</ul><br>
Set attr subType to smokeDetector.02 manually.
</li>
<br><br>
<li>Window Handle (EEP F6-10-00, D2-03-10)<br> <li>Window Handle (EEP F6-10-00, D2-03-10)<br>
[HOPPE SecuSignal, Eltako FHF, Eltako FTKE]<br> [HOPPE SecuSignal, Eltako FHF, Eltako FTKE]<br>
<ul> <ul>
@ -18903,12 +19012,13 @@ EnOcean_Delete($$)
</li> </li>
<br><br> <br><br>
<li>Gas Sensor, Volatile organic compounds (VOC) Sensor (EEP A5-09-05)<br> <li>Gas Sensor, Volatile organic compounds (VOC) Sensor (EEP A5-09-05, A5-09-0C)<br>
[untested]<br> [untested]<br>
<ul> <ul>
<li>concentration: c/ppb (Sensor Range: c = 0 ppb ... 655350 ppb)</li> <li>concentration: c/[unit] (Sensor Range: c = 0 ... 655350</li>
<li>concentrationUnit: ppb|&mu;/m3</li>
<li>vocName: Name of last measured VOC</li> <li>vocName: Name of last measured VOC</li>
<li>state: c/ppb</li> <li>state: c/[unit]</li>
</ul><br> </ul><br>
The attr subType must be vocSensor.01. This is done if the device was The attr subType must be vocSensor.01. This is done if the device was
created by autocreate. created by autocreate.
@ -19513,6 +19623,37 @@ EnOcean_Delete($$)
</li> </li>
<br><br> <br><br>
<li>Dual Door Contact (EEP A5-14-07, A5-14-08)<br>
[untested]<br>
<ul>
<li>C: open|closed B: unlocked|locked V: on|off U: U/V</li>
<li>alarm: dead_sensor</li>
<li>block: unlocked|locked</li>
<li>contact: open|closed</li>
<li>vibration: on|off</li>
<li>voltage: U/V (Sensor Range: U = 0 V ... 5.0 V)</li>
<li>state: C: open|closed B: unlocked|locked V: on|off U: U/V</li>
</ul><br>
The attr subType must be doorContact. This is done if the device was
created by autocreate.
</li>
<br><br>
<li>Window/Door Contact (EEP A5-14-09, A5-14-0A)<br>
[untested]<br>
<ul>
<li>W: open|tilt|closed B: unlocked|locked V: on|off U: U/V</li>
<li>alarm: dead_sensor</li>
<li>vibration: on|off</li>
<li>voltage: U/V (Sensor Range: U = 0 V ... 5.0 V)</li>
<li>window: open|tilt|closed</li>
<li>state: W: open|tilt|closed V: on|off U: U/V</li>
</ul><br>
The attr subType must be windowContact. This is done if the device was
created by autocreate.
</li>
<br><br>
<li>Battery Powered Actuator (EEP A5-20-01)<br> <li>Battery Powered Actuator (EEP A5-20-01)<br>
[Kieback&Peter MD15-FTL-xx]<br> [Kieback&Peter MD15-FTL-xx]<br>
<ul> <ul>
@ -20187,6 +20328,18 @@ EnOcean_Delete($$)
</li> </li>
<br><br> <br><br>
<li>Liquid Leakage Sensor (EEP D2-B0-51)<br>
[untested]<br>
<ul>
<li>dry</li>
<li>wet</li>
<li>state: dry|wet</li>
</ul><br>
The attr subType must be liquidLeakage.51. This is done if the device was
created by autocreate.
</li>
<br><br>
<li>Generic Profiles<br> <li>Generic Profiles<br>
<ul> <ul>
<li>&lt;00...64&gt;-&lt;channel name&gt;: &lt;value&gt;</li> <li>&lt;00...64&gt;-&lt;channel name&gt;: &lt;value&gt;</li>
@ -20203,8 +20356,8 @@ EnOcean_Delete($$)
<li>RAW Command<br> <li>RAW Command<br>
<ul> <ul>
<li>RORG: 1BS|4BS|MCS|RPS|UTE|VLD</li> <li>RORG: 1BS|4BS|ENC|MCS|RPS|SEC|STE|UTE|VLD</li>
<li>dataSent: data (Range: 1-byte hex ... 28-byte hex)</li> <li>dataSent: data (Range: 1 Byte hex ... 512 Byte hex)</li>
<li>statusSent: status (Range: 0x00 ... 0xFF)</li> <li>statusSent: status (Range: 0x00 ... 0xFF)</li>
<li>state: RORG: rorg DATA: data STATUS: status ODATA: odata</li> <li>state: RORG: rorg DATA: data STATUS: status ODATA: odata</li>
</ul><br> </ul><br>