mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-01 07:19:24 +00:00
10_EnOcean: new EEP: multisensor.50 (EEP D2-06-50), profil roomSensorControl.05: signOfLife function added, signal telegram: new MID 0x0B, 0x10, 0x11, MID 0x0D modified, constant light controller: open loop control functions
git-svn-id: https://svn.fhem.de/fhem/trunk@24267 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
539d2b08be
commit
aa72fdc906
@ -63,7 +63,7 @@ my %EnO_rorgname = (
|
|||||||
"C5" => "SYSEX", # remote management >> packet type 7 used
|
"C5" => "SYSEX", # remote management >> packet type 7 used
|
||||||
"C6" => "SMLRNREQ", # Smart Ack Learn Request
|
"C6" => "SMLRNREQ", # Smart Ack Learn Request
|
||||||
"C7" => "SMLRNANS", # Smart Ack Learn Answer
|
"C7" => "SMLRNANS", # Smart Ack Learn Answer
|
||||||
"D0" => "SIGNAL", # Smart Ack Mail Box Functions
|
"D0" => "SIGNAL", # signal telegram
|
||||||
"D1" => "MSC", # MSC
|
"D1" => "MSC", # MSC
|
||||||
"D2" => "VLD", # VLD
|
"D2" => "VLD", # VLD
|
||||||
"D4" => "UTE", # UTE
|
"D4" => "UTE", # UTE
|
||||||
@ -394,6 +394,7 @@ my %EnO_eepConfig = (
|
|||||||
"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", defaultChannel => 1, webCmd => "opens:stop:closes:position"}, GPLOT => "EnO_position4angle4:Position/AnglePos,"},
|
"D2.05.02" => {attr => {subType => "blindsCtrl.00", defaultChannel => 1, 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.06.50" => {attr => {subType => "multisensor.50"}},
|
||||||
"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,"},
|
||||||
"D2.10.02" => {attr => {subType => "roomCtrlPanel.00", webCmd => "setpointTemp"}, GPLOT => "EnO_D2-10-xx:Temp/SPT/Humi,"},
|
"D2.10.02" => {attr => {subType => "roomCtrlPanel.00", webCmd => "setpointTemp"}, GPLOT => "EnO_D2-10-xx:Temp/SPT/Humi,"},
|
||||||
@ -787,7 +788,7 @@ sub EnOcean_Initialize($) {
|
|||||||
"blockTemp:no,yes blockDisplay:no,yes blockDateTime:no,yes " .
|
"blockTemp:no,yes blockDisplay:no,yes blockDateTime:no,yes " .
|
||||||
"blockTimeProgram:no,yes blockOccupancy:no,yes blockSetpointTemp:no,yes " .
|
"blockTimeProgram:no,yes blockOccupancy:no,yes blockSetpointTemp:no,yes " .
|
||||||
"blockFanSpeed:no,yes blockKey:no,yes " .
|
"blockFanSpeed:no,yes blockKey:no,yes " .
|
||||||
"brightnessDayNight brightnessDayNightCtrl:custom,sensor brightnessDayNightDelay " .
|
"brightnessDayNight brightnessDayNightCtrl:custom,sensor brightnessDayNightDelay brightnessRefDev " .
|
||||||
"brightnessSunny brightnessSunnySouth brightnessSunnyWest brightnessSunnyEast " .
|
"brightnessSunny brightnessSunnySouth brightnessSunnyWest brightnessSunnyEast " .
|
||||||
"brightnessSunnyDelay brightnessSunnySouthDelay brightnessSunnyWestDelay brightnessSunnyEastDelay " .
|
"brightnessSunnyDelay brightnessSunnySouthDelay brightnessSunnyWestDelay brightnessSunnyEastDelay " .
|
||||||
"calAtEndpoints:no,yes comMode:confirm,biDir,uniDir creator:autocreate,manual " .
|
"calAtEndpoints:no,yes comMode:confirm,biDir,uniDir creator:autocreate,manual " .
|
||||||
@ -812,7 +813,7 @@ sub EnOcean_Initialize($) {
|
|||||||
"model:" . join(",", sort keys %EnO_models) . " " .
|
"model:" . join(",", sort keys %EnO_models) . " " .
|
||||||
"observe:on,off observeCmdRepetition:1,2,3,4,5 observeErrorAction:textField-long observeInterval observeLogic:and,or " .
|
"observe:on,off observeCmdRepetition:1,2,3,4,5 observeErrorAction:textField-long observeInterval observeLogic:and,or " .
|
||||||
#observeCmds observeExeptions
|
#observeCmds observeExeptions
|
||||||
"observeRefDev pidActorErrorAction:errorPos,freeze pidActorCallBeforeSetting pidActorErrorPos " .
|
"observeRefDev openLoopCtrlScale pidActorErrorAction:errorPos,freeze pidActorCallBeforeSetting pidActorErrorPos " .
|
||||||
"pidActorLimitLower pidActorLimitUpper pidActorTreshold pidCtrl:on,off pidDeltaTreshold pidFactor_D pidFactor_I " .
|
"pidActorLimitLower pidActorLimitUpper pidActorTreshold pidCtrl:on,off pidDeltaTreshold pidFactor_D pidFactor_I " .
|
||||||
"pidFactor_P pidIPortionCallBeforeSetting pidSensorTimeout " .
|
"pidFactor_P pidIPortionCallBeforeSetting pidSensorTimeout " .
|
||||||
"pollInterval postmasterID productID rampTime rcvRespAction:textField-long ".
|
"pollInterval postmasterID productID rampTime rcvRespAction:textField-long ".
|
||||||
@ -1054,12 +1055,20 @@ sub EnOcean_Define($$) {
|
|||||||
$attr{$name}{teachMethod} = 'RPS';
|
$attr{$name}{teachMethod} = 'RPS';
|
||||||
Log3 $name, 2, "EnOcean $name teach-in EEP F6-10-00 Manufacturer: no ID";
|
Log3 $name, 2, "EnOcean $name teach-in EEP F6-10-00 Manufacturer: no ID";
|
||||||
}
|
}
|
||||||
|
# signal telegram learn mode status
|
||||||
|
$data = EnOcean_signalLearnModeStatus(0, 1, 0, 0, 0, $hash->{DEF}, $attr{$name}{eep});
|
||||||
|
EnOcean_SndRadio(undef, $hash, 1, 'D0', $data, '0' x 8, '00', 'F' x 8);
|
||||||
|
|
||||||
} elsif ($attr{$name}{subType} eq "contact" && hex($data) & 8) {
|
} elsif ($attr{$name}{subType} eq "contact" && hex($data) & 8) {
|
||||||
$attr{$name}{eep} = "D5-00-01";
|
$attr{$name}{eep} = "D5-00-01";
|
||||||
$attr{$name}{manufID} = "7FF";
|
$attr{$name}{manufID} = "7FF";
|
||||||
readingsSingleUpdate($hash, "teach", "1BS teach-in accepted EEP D5-00-01 Manufacturer: no ID", 1);
|
readingsSingleUpdate($hash, "teach", "1BS teach-in accepted EEP D5-00-01 Manufacturer: no ID", 1);
|
||||||
$attr{$name}{teachMethod} = '1BS';
|
$attr{$name}{teachMethod} = '1BS';
|
||||||
Log3 $name, 2, "EnOcean $name teach-in EEP D5-00-01 Manufacturer: no ID";
|
Log3 $name, 2, "EnOcean $name teach-in EEP D5-00-01 Manufacturer: no ID";
|
||||||
|
# signal telegram learn mode status
|
||||||
|
$data = EnOcean_signalLearnModeStatus(0, 1, 0, 0, 0, $hash->{DEF}, $attr{$name}{eep});
|
||||||
|
EnOcean_SndRadio(undef, $hash, 1, 'D0', $data, '0' x 8, '00', 'F' x 8);
|
||||||
|
|
||||||
} elsif ($attr{$name}{subType} eq "4BS" && hex(substr($data, 6, 2)) & 8) {
|
} elsif ($attr{$name}{subType} eq "4BS" && hex(substr($data, 6, 2)) & 8) {
|
||||||
$hash->{helper}{teachInWait} = "4BS";
|
$hash->{helper}{teachInWait} = "4BS";
|
||||||
readingsSingleUpdate($hash, "teach", "4BS teach-in is missing", 1);
|
readingsSingleUpdate($hash, "teach", "4BS teach-in is missing", 1);
|
||||||
@ -3474,6 +3483,7 @@ sub EnOcean_Set($@) {
|
|||||||
$updateState = 0;
|
$updateState = 0;
|
||||||
($err, $subDef) = EnOcean_AssignSenderID(undef, $hash, "subDef", "confirm");
|
($err, $subDef) = EnOcean_AssignSenderID(undef, $hash, "subDef", "confirm");
|
||||||
EnOcean_setTeachConfirmWaitHash(undef, $hash);
|
EnOcean_setTeachConfirmWaitHash(undef, $hash);
|
||||||
|
|
||||||
} elsif ($cmd eq "dim") {
|
} elsif ($cmd eq "dim") {
|
||||||
return "Usage: $cmd dim/% [rampTime/s lock|unlock]"
|
return "Usage: $cmd dim/% [rampTime/s lock|unlock]"
|
||||||
if(@a < 2 || $a[1] !~ m/^\d+$/ || $a[1] < 0 || $a[1] > 100);
|
if(@a < 2 || $a[1] !~ m/^\d+$/ || $a[1] < 0 || $a[1] > 100);
|
||||||
@ -3552,6 +3562,12 @@ sub EnOcean_Set($@) {
|
|||||||
$setCmd = 8;
|
$setCmd = 8;
|
||||||
$sendDimCmd = 1;
|
$sendDimCmd = 1;
|
||||||
|
|
||||||
|
} elsif ($cmd eq "openLoopCtrl") {
|
||||||
|
$hash->{constLightCtrl} = 'openLoopCtrl';
|
||||||
|
$dimVal = $dimVal // 0;
|
||||||
|
$setCmd = $dimVal == 0 ? 8 : 9;
|
||||||
|
$sendDimCmd = 1;
|
||||||
|
|
||||||
} elsif ($cmd eq "local") {
|
} elsif ($cmd eq "local") {
|
||||||
if ($a[1]) {
|
if ($a[1]) {
|
||||||
return "Usage: $cmd [learn]" if ($a[1] ne "learn");
|
return "Usage: $cmd [learn]" if ($a[1] ne "learn");
|
||||||
@ -3569,9 +3585,16 @@ sub EnOcean_Set($@) {
|
|||||||
$data = sprintf "%02X%02X%02X%02X", $gwCmdID, $dimVal, $rampTime, $setCmd;
|
$data = sprintf "%02X%02X%02X%02X", $gwCmdID, $dimVal, $rampTime, $setCmd;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
my $cmdList = "dim:slider,0,1,100 local:learn on:noArg off:noArg teach:noArg";
|
my $cmdList = "dim:slider,0,1,100 local:learn off:noArg on:noArg openLoopCtrl:noArg teach:noArg";
|
||||||
return SetExtensions ($hash, $cmdList, $name, @a);
|
return SetExtensions ($hash, $cmdList, $name, @a);
|
||||||
}
|
}
|
||||||
|
$hash->{helper}{constLightCtrl}[0] = $hash;
|
||||||
|
$hash->{helper}{constLightCtrl}[1] = 'set';
|
||||||
|
$hash->{helper}{constLightCtrl}[2] = $cmd;
|
||||||
|
$hash->{helper}{constLightCtrl}[3] = $dimVal;
|
||||||
|
$hash->{helper}{constLightCtrl}[4] = 4;
|
||||||
|
$logLevel = EnOcean_constLightCtrl($hash->{helper}{constLightCtrl});
|
||||||
|
######*
|
||||||
if ($sendDimCmd) {
|
if ($sendDimCmd) {
|
||||||
readingsSingleUpdate($hash, "block", "unlock", 1);
|
readingsSingleUpdate($hash, "block", "unlock", 1);
|
||||||
if (defined $a[1]) {
|
if (defined $a[1]) {
|
||||||
@ -3965,7 +3988,7 @@ sub EnOcean_Set($@) {
|
|||||||
} else {
|
} else {
|
||||||
return "Unknown Gateway command " . $cmd . ", choose one of ". $cmdList . join(" ", sort keys %EnO_gwCmd);
|
return "Unknown Gateway command " . $cmd . ", choose one of ". $cmdList . join(" ", sort keys %EnO_gwCmd);
|
||||||
}
|
}
|
||||||
Log3 $name, 3, "EnOcean set $name $cmd";
|
Log3 $name, $logLevel // 3, "EnOcean set $name $cmd";
|
||||||
|
|
||||||
} elsif ($st eq "energyManagement.01") {
|
} elsif ($st eq "energyManagement.01") {
|
||||||
# Energy Management, Demand Response (A5-37-01)
|
# Energy Management, Demand Response (A5-37-01)
|
||||||
@ -7279,7 +7302,6 @@ sub EnOcean_Parse($$) {
|
|||||||
# store changes
|
# store changes
|
||||||
EnOcean_CommandSave(undef, undef);
|
EnOcean_CommandSave(undef, undef);
|
||||||
readingsSingleUpdate($hash, 'teach', '4BS teach-in accepted', 1);
|
readingsSingleUpdate($hash, 'teach', '4BS teach-in accepted', 1);
|
||||||
#push @event, "3:teach:4BS teach-in accepted";
|
|
||||||
Log3 $name, 2, "EnOcean $name remote device with SenderID $senderID assigned";
|
Log3 $name, 2, "EnOcean $name remote device with SenderID $senderID assigned";
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
@ -7365,9 +7387,9 @@ sub EnOcean_Parse($$) {
|
|||||||
"91" => "BASEID_MAX_REACHED",
|
"91" => "BASEID_MAX_REACHED",
|
||||||
);
|
);
|
||||||
my $rcTxt = $codes{$funcNumber} if($codes{$funcNumber});
|
my $rcTxt = $codes{$funcNumber} if($codes{$funcNumber});
|
||||||
|
$funcNumber = hex($funcNumber);
|
||||||
if($hash) {
|
if($hash) {
|
||||||
$name = $hash->{NAME};
|
$name = $hash->{NAME};
|
||||||
$funcNumber = hex($funcNumber);
|
|
||||||
Log3 $name, $funcNumber == 0 ? 5 : 2, "EnOcean $name RESPONSE: $rcTxt DATA: $data ODATA: $odata";
|
Log3 $name, $funcNumber == 0 ? 5 : 2, "EnOcean $name RESPONSE: $rcTxt DATA: $data ODATA: $odata";
|
||||||
return $name;
|
return $name;
|
||||||
} else {
|
} else {
|
||||||
@ -7756,6 +7778,7 @@ sub EnOcean_Parse($$) {
|
|||||||
|
|
||||||
} elsif ($st eq "switch.7F" && $manufID eq "00D") {
|
} elsif ($st eq "switch.7F" && $manufID eq "00D") {
|
||||||
$msg = $EnO_ptm200btn[($db[0] & 0xE0) >> 5];
|
$msg = $EnO_ptm200btn[($db[0] & 0xE0) >> 5];
|
||||||
|
# 2nd action
|
||||||
$msg .= "," . $EnO_ptm200btn[($db[0] & 0x0E) >> 1] if ($db[0] & 1);
|
$msg .= "," . $EnO_ptm200btn[($db[0] & 0x0E) >> 1] if ($db[0] & 1);
|
||||||
$msg .= " released" if (!($db[0] & 0x10));
|
$msg .= " released" if (!($db[0] & 0x10));
|
||||||
push @event, "3:buttons:" . ($db[0] & 0x10 ? "pressed" : "released");
|
push @event, "3:buttons:" . ($db[0] & 0x10 ? "pressed" : "released");
|
||||||
@ -7777,10 +7800,17 @@ sub EnOcean_Parse($$) {
|
|||||||
} elsif ($st eq "liquidLeakage") {
|
} elsif ($st eq "liquidLeakage") {
|
||||||
# liquid leakage sensor, not tested
|
# liquid leakage sensor, not tested
|
||||||
$msg = "wet" if ($db[0] == 0x11);
|
$msg = "wet" if ($db[0] == 0x11);
|
||||||
|
# } elsif (($db[0] & 7) == 6) {
|
||||||
|
# # bistable switch
|
||||||
|
# $msg = ($db[0] & 0xE0) >> 5 == 2 ? 'BI' : 'B0';
|
||||||
|
# push @event, "3:buttons:pressed";
|
||||||
|
# push @event, "3:channelB:$msg";
|
||||||
|
# push @event, "3:$event:$msg";
|
||||||
} else {
|
} else {
|
||||||
# Theoretically there can be a released event with some of the A0, BI
|
# Theoretically there can be a released event with some of the A0, BI
|
||||||
# pins set, but with the plastic cover on this wont happen.
|
# pins set, but with the plastic cover on this wont happen.
|
||||||
$msg = $EnO_ptm200btn[($db[0] & 0xE0) >> 5];
|
$msg = $EnO_ptm200btn[($db[0] & 0xE0) >> 5];
|
||||||
|
# 2nd action
|
||||||
$msg .= "," . $EnO_ptm200btn[($db[0] & 0x0E) >> 1] if ($db[0] & 1);
|
$msg .= "," . $EnO_ptm200btn[($db[0] & 0x0E) >> 1] if ($db[0] & 1);
|
||||||
$msg .= " released" if (!($db[0] & 0x10));
|
$msg .= " released" if (!($db[0] & 0x10));
|
||||||
push @event, "3:buttons:" . ($db[0] & 0x10 ? "pressed" : "released");
|
push @event, "3:buttons:" . ($db[0] & 0x10 ? "pressed" : "released");
|
||||||
@ -8025,6 +8055,10 @@ sub EnOcean_Parse($$) {
|
|||||||
$st = "raw";
|
$st = "raw";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# signal telegram learn mode status
|
||||||
|
my $signalData = EnOcean_signalLearnModeStatus(0, 1, 0, $attr{$name}{eep} eq 'raw' ? 1 : 0, 0, $hash->{DEF}, $attr{$name}{eep} eq 'raw' ? 'FF-FF-FF' : $attr{$name}{eep});
|
||||||
|
EnOcean_SndRadio(undef, $hash, 1, 'D0', $signalData, defined($attr{$name}{subDef}) ? $attr{$name}{subDef} : '0' x 8, '00', 'F' x 8);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log3 $name, 4, "EnOcean $name teach-in with subType $st locked, set transceiver in teach mode.";
|
Log3 $name, 4, "EnOcean $name teach-in with subType $st locked, set transceiver in teach mode.";
|
||||||
return "";
|
return "";
|
||||||
@ -9369,7 +9403,7 @@ sub EnOcean_Parse($$) {
|
|||||||
|
|
||||||
} elsif ($st eq "roomSensorControl.05") {
|
} elsif ($st eq "roomSensorControl.05") {
|
||||||
# Room Sensor and Control Unit (EEP A5-10-01 ... A5-10-0D)
|
# Room Sensor and Control Unit (EEP A5-10-01 ... A5-10-0D)
|
||||||
# [Eltako FTR55D, FTR55H, Thermokon SR04 *, Thanos SR *, untested]
|
# [Eltako FTR55D, FTR55H, Thermokon SR04 *, Thanos SR *]
|
||||||
# $db[3] is the fan speed or night reduction for Eltako
|
# $db[3] is the fan speed or night reduction for Eltako
|
||||||
# $db[2] is the setpoint where 0x00 = min ... 0xFF = max or
|
# $db[2] is the setpoint where 0x00 = min ... 0xFF = max or
|
||||||
# reference temperature for Eltako where 0x00 = 0°C ... 0xFF = 40°C
|
# reference temperature for Eltako where 0x00 = 0°C ... 0xFF = 40°C
|
||||||
@ -9404,6 +9438,12 @@ sub EnOcean_Parse($$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
push @event, "3:temperature:$temp";
|
push @event, "3:temperature:$temp";
|
||||||
|
readingsDelete($hash, "alarm");
|
||||||
|
if (AttrVal($name, "signOfLife", 'off') eq 'on') {
|
||||||
|
RemoveInternalTimer($hash->{helper}{timer}{alarm}) if(exists $hash->{helper}{timer}{alarm});
|
||||||
|
@{$hash->{helper}{timer}{alarm}} = ($hash, 'alarm', 'dead_sensor', 1, 5);
|
||||||
|
InternalTimer(gettimeofday() + AttrVal($name, "signOfLifeInterval", 1320), 'EnOcean_readingsSingleUpdate', $hash->{helper}{timer}{alarm}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
} elsif ($st eq "roomSensorControl.01") {
|
} elsif ($st eq "roomSensorControl.01") {
|
||||||
# Room Sensor and Control Unit (EEP A5-04-01, A5-10-10 ... A5-10-14)
|
# Room Sensor and Control Unit (EEP A5-04-01, A5-10-10 ... A5-10-14)
|
||||||
@ -10766,14 +10806,18 @@ sub EnOcean_Parse($$) {
|
|||||||
# $db[0]_bit_2 is store final value, not used, because
|
# $db[0]_bit_2 is store final value, not used, because
|
||||||
# dimming value is always stored
|
# dimming value is always stored
|
||||||
push @event, "3:rampTime:$db[1]";
|
push @event, "3:rampTime:$db[1]";
|
||||||
push @event, "3:state:" . ($db[0] & 0x01 ? "on" : "off");
|
push @event, "3:state:" . ($db[0] & 1 ? "on" : "off");
|
||||||
if ($db[0] & 4) {
|
my $dim = $db[0] & 4 ? sprintf("%d", $db[2] * 100 / 255) : $db[2];
|
||||||
# Relative Dimming Range
|
push @event, "3:dim:$dim";
|
||||||
push @event, "3:dim:" . sprintf "%d", $db[2] * 100 / 255;
|
push @event, "3:dimValueLast:$dim" if ($dim > 0);
|
||||||
} else {
|
# constLightCtrl
|
||||||
push @event, "3:dim:$db[2]";
|
$hash->{helper}{constLightCtrl}[0] = $hash;
|
||||||
}
|
$hash->{helper}{constLightCtrl}[1] = 'parse';
|
||||||
push @event, "3:dimValueLast:$db[2]" if ($db[2] > 0);
|
$hash->{helper}{constLightCtrl}[2] = 'response';
|
||||||
|
$hash->{helper}{constLightCtrl}[3] = $dim;
|
||||||
|
$hash->{helper}{constLightCtrl}[4] = 4;
|
||||||
|
EnOcean_constLightCtrl($hash->{helper}{constLightCtrl});
|
||||||
|
|
||||||
} elsif ($db[3] == 3) {
|
} elsif ($db[3] == 3) {
|
||||||
# Setpoint shift
|
# Setpoint shift
|
||||||
# $db1 is setpoint shift where 0 = -12.7 K ... 255 = 12.8 K
|
# $db1 is setpoint shift where 0 = -12.7 K ... 255 = 12.8 K
|
||||||
@ -11808,6 +11852,115 @@ sub EnOcean_Parse($$) {
|
|||||||
#EnOcean_multisensor_01Snd($ctrl, $hash, $packetType);
|
#EnOcean_multisensor_01Snd($ctrl, $hash, $packetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} elsif ($st eq "multisensor.50") {
|
||||||
|
# Multisensor Windows Handle
|
||||||
|
# (D2-06-50)
|
||||||
|
# message type
|
||||||
|
my $msgType = hex(substr($data, 0, 2));
|
||||||
|
if ($msgType == 1) {
|
||||||
|
# windows status
|
||||||
|
push @event, "1:telegramType:" . ($db[6] & 0x80 ? "heartbeat" : "event");
|
||||||
|
my %handlePosition = (
|
||||||
|
0 => ["none", undef],
|
||||||
|
1 => ["closed", 'F0'],
|
||||||
|
2 => ["open", 'E0'],
|
||||||
|
3 => ["tilted", 'D0'],
|
||||||
|
4 => ["closed", 'F0'],
|
||||||
|
5 => ["open", 'E0'],
|
||||||
|
6 => ["tilted", 'D0'],
|
||||||
|
7 => ["closed", 'F0'],
|
||||||
|
8 => ["open", 'E0'],
|
||||||
|
9 => ["tilted", 'D0']
|
||||||
|
);
|
||||||
|
my %windowPosition = (
|
||||||
|
0 => ["none", undef],
|
||||||
|
1 => ["closed", '09'],
|
||||||
|
2 => ["closed", '09'],
|
||||||
|
3 => ["closed", '09'],
|
||||||
|
4 => ["open", '08'],
|
||||||
|
5 => ["open", '08'],
|
||||||
|
6 => ["open", '08'],
|
||||||
|
7 => ["tilted", '08'],
|
||||||
|
8 => ["tilted", '08'],
|
||||||
|
9 => ["tilted", '08']
|
||||||
|
);
|
||||||
|
my $position = $db[6] & 0x7F;
|
||||||
|
my $handle;
|
||||||
|
if (exists $handlePosition{$position}) {
|
||||||
|
$handle = $handlePosition{$position}[0];
|
||||||
|
} else {
|
||||||
|
$handle = "unknown";
|
||||||
|
}
|
||||||
|
push @event, "1:handle:$handle";
|
||||||
|
# forward handle position (RPS telegam)
|
||||||
|
if (defined($handlePosition{$position}[1]) && defined(AttrVal($name, "subDefH", undef))) {
|
||||||
|
EnOcean_SndRadio(undef, $hash, $packetType, "F6", $handlePosition{$position}[1], AttrVal($name, "subDefH", "0" x 8), '20', 'FFFFFFFF');
|
||||||
|
}
|
||||||
|
my $window;
|
||||||
|
if (exists $windowPosition{$position}) {
|
||||||
|
$window = $windowPosition{$position}[0];
|
||||||
|
} else {
|
||||||
|
$window = 'unknown';
|
||||||
|
}
|
||||||
|
push @event, "1:window:$window";
|
||||||
|
# forward window state (1BS telegam)
|
||||||
|
if (defined($windowPosition{$position}[1]) && defined(AttrVal($name, "subDefW", undef))) {
|
||||||
|
EnOcean_SndRadio(undef, $hash, $packetType, "D5", $windowPosition{$position}[1], AttrVal($name, "subDefW", "0" x 8), '00', 'FFFFFFFF');
|
||||||
|
}
|
||||||
|
push @event, "1:statusCntr:". substr($data, 4, 8);
|
||||||
|
my $battery = $db[1] & 0x80 ? 'low' : 'ok';
|
||||||
|
push @event, "1:battery:$battery";
|
||||||
|
push @event, "1:batteryPercent:". ($db[1] & 0x7F);
|
||||||
|
my %errorStatus = (
|
||||||
|
0 => "ok",
|
||||||
|
1 => "error",
|
||||||
|
2 => "not_supported",
|
||||||
|
3 => "reserved"
|
||||||
|
);
|
||||||
|
push @event, "1:statusMotion:" . $errorStatus{(($db[0] & 0xC0) >> 6)};
|
||||||
|
push @event, "1:statusAcceleration:" . $errorStatus{(($db[0] & 0x30) >> 4)};
|
||||||
|
push @event, "1:statusMagnetic:" . $errorStatus{(($db[0] & 0x0C) >> 2)};
|
||||||
|
push @event, "1:statusSystem:" . $errorStatus{($db[0] & 3)};
|
||||||
|
push @event, "1:state:W: $window H: $handle B: $battery";
|
||||||
|
} elsif ($msgType == 2) {
|
||||||
|
# alarm status
|
||||||
|
push @event, "1:burglaryAlarm:" . ($db[0] & 1 ? 'on' : 'off');
|
||||||
|
} elsif ($msgType == 0x11) {
|
||||||
|
# calibrate
|
||||||
|
my %calStatus = (
|
||||||
|
0 => "ok",
|
||||||
|
1 => "error",
|
||||||
|
2 => "invalid"
|
||||||
|
);
|
||||||
|
my $calStatus = $db[0] & 0xC0;
|
||||||
|
if (exists $calStatus{$calStatus}) {
|
||||||
|
push @event, "3:statusCalibration:$calStatus{$calStatus}";
|
||||||
|
} else {
|
||||||
|
push @event, "3:statusCalibration:unknown";
|
||||||
|
}
|
||||||
|
my %cal = (
|
||||||
|
0 => "none",
|
||||||
|
1 => "close_handle",
|
||||||
|
2 => "open_handle",
|
||||||
|
3 => "tilt_handle",
|
||||||
|
0x0A => "close_window"
|
||||||
|
);
|
||||||
|
my $cal = $db[0] & 0x3F;
|
||||||
|
if (exists $cal{$cal}) {
|
||||||
|
push @event, "3:calibrationStep:$cal{$cal}";
|
||||||
|
} else {
|
||||||
|
push @event, "3:calibrationStep:unknown";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
readingsDelete($hash, "alarm");
|
||||||
|
if (AttrVal($name, "signOfLife", 'on') eq 'on') {
|
||||||
|
RemoveInternalTimer($hash->{helper}{timer}{alarm}) if(exists $hash->{helper}{timer}{alarm});
|
||||||
|
@{$hash->{helper}{timer}{alarm}} = ($hash, 'alarm', 'dead_sensor', 1, 5);
|
||||||
|
InternalTimer(gettimeofday() + AttrVal($name, "signOfLifeInterval", 990), 'EnOcean_readingsSingleUpdate', $hash->{helper}{timer}{alarm}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
} elsif ($st eq "roomCtrlPanel.01") {
|
} elsif ($st eq "roomCtrlPanel.01") {
|
||||||
# Room Control Panel
|
# Room Control Panel
|
||||||
# (D2-11-01 - D2-11-08)
|
# (D2-11-01 - D2-11-08)
|
||||||
@ -12553,18 +12706,27 @@ sub EnOcean_Parse($$) {
|
|||||||
my $repeatingCounter = $db[0] & 0x0F;
|
my $repeatingCounter = $db[0] & 0x0F;
|
||||||
if ($repeatingCounter < 0x0F) {$hash->{Dev_RepeatingCounter} = $repeatingCounter};
|
if ($repeatingCounter < 0x0F) {$hash->{Dev_RepeatingCounter} = $repeatingCounter};
|
||||||
} elsif ($signalMID == 11) {
|
} elsif ($signalMID == 11) {
|
||||||
DoTrigger($name, "SIGNAL: DUTYCYCLE_LIMIT: " . ($db[0] >> 4 == 1 ? 'released' : 'reached'), 1);
|
DoTrigger($name, "SIGNAL: DUTYCYCLE_LIMIT: " . (($db[0] & 0x0F) == 1 ? 'released' : 'reached'), 1);
|
||||||
Log3 $name, 2, "EnOcean $name SIGNAL DUTYCYCLE_LIMIT: " . ($db[0] >> 4 == 1 ? 'released' : 'reached');
|
Log3 $name, 2, "EnOcean $name SIGNAL DUTYCYCLE_LIMIT: " . ($db[0] >> 4 == 1 ? 'released' : 'reached');
|
||||||
} elsif ($signalMID == 12) {
|
} elsif ($signalMID == 12) {
|
||||||
DoTrigger($name, "SIGNAL: Dev_CHANGED", 1);
|
DoTrigger($name, "SIGNAL: Dev_CHANGED", 1);
|
||||||
Log3 $name, 2, "EnOcean $name SIGNAL Dev_CHANGED";
|
Log3 $name, 2, "EnOcean $name SIGNAL Dev_CHANGED";
|
||||||
} elsif ($signalMID == 13) {
|
} elsif ($signalMID == 13) {
|
||||||
my @harvester = ('very_good', 'good', 'average', 'bad', 'very_bad');
|
my @harvester = ('very_good', 'good', 'average', 'bad', 'very_bad');
|
||||||
push @event, "3:harvester:" . $harvester[$db[0]];
|
push @event, "3:harvester:" . $harvester[$db[0] & 0x0F];
|
||||||
} elsif ($signalMID == 14) {
|
} elsif ($signalMID == 14) {
|
||||||
DoTrigger($name, "SIGNAL: TX_MODE_OFF", 1);
|
DoTrigger($name, "SIGNAL: TX_MODE_OFF", 1);
|
||||||
} elsif ($signalMID == 15) {
|
} elsif ($signalMID == 15) {
|
||||||
DoTrigger($name, "SIGNAL: TX_MODE_ON", 1);
|
DoTrigger($name, "SIGNAL: TX_MODE_ON", 1);
|
||||||
|
} elsif ($signalMID == 16) {
|
||||||
|
if ($db[0] <= 100) {
|
||||||
|
push @event, "3:batteryPercentBackup:$db[0]";
|
||||||
|
} else {
|
||||||
|
readingsDelete($hash, "batteryPercentBackup");
|
||||||
|
}
|
||||||
|
} elsif ($signalMID == 17) {
|
||||||
|
# learn mode status
|
||||||
|
#push @event, "3:batteryPercent:$db[0]";
|
||||||
}
|
}
|
||||||
|
|
||||||
} elsif ($rorg eq "B2") {
|
} elsif ($rorg eq "B2") {
|
||||||
@ -12768,6 +12930,9 @@ sub EnOcean_Parse($$) {
|
|||||||
$mid = $EnO_manuf{$mid} if($EnO_manuf{$mid});
|
$mid = $EnO_manuf{$mid} if($EnO_manuf{$mid});
|
||||||
push @event, "3:teach:GP teach-in accepted Manufacturer: $mid";
|
push @event, "3:teach:GP teach-in accepted Manufacturer: $mid";
|
||||||
Log3 $name, 2, "EnOcean $name GP teach-in accepted Manufacturer: $mid";
|
Log3 $name, 2, "EnOcean $name GP teach-in accepted Manufacturer: $mid";
|
||||||
|
# signal telegram learn mode status
|
||||||
|
my $signalData = EnOcean_signalLearnModeStatus(0, 1, 0, 0, 0, $hash->{DEF}, $attr{$name}{eep});
|
||||||
|
EnOcean_SndRadio(undef, $hash, 1, 'D0', $signalData, defined($attr{$name}{subDef}) ? $attr{$name}{subDef} : '0' x 8, '00', 'F' x 8);
|
||||||
# store attr subType, manufID, gpDef ...
|
# store attr subType, manufID, gpDef ...
|
||||||
EnOcean_CommandSave(undef, undef);
|
EnOcean_CommandSave(undef, undef);
|
||||||
|
|
||||||
@ -12781,7 +12946,9 @@ sub EnOcean_Parse($$) {
|
|||||||
Log3 $name, 2, "EnOcean $name GP teach-in deletion response send to $senderID";
|
Log3 $name, 2, "EnOcean $name GP teach-in deletion response send to $senderID";
|
||||||
}
|
}
|
||||||
Log3 $name, 2, "EnOcean $name GP teach-in delete request executed";
|
Log3 $name, 2, "EnOcean $name GP teach-in delete request executed";
|
||||||
|
# signal telegram learn mode status
|
||||||
|
my $signalData = EnOcean_signalLearnModeStatus(0, 1, 0, 4, 0, $hash->{DEF}, $attr{$name}{eep});
|
||||||
|
EnOcean_SndRadio(undef, $hash, 1, 'D0', $signalData, defined($attr{$name}{subDef}) ? $attr{$name}{subDef} : '0' x 8, '00', 'F' x 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
} elsif ($rorg eq "B1" && $teach) {
|
} elsif ($rorg eq "B1" && $teach) {
|
||||||
@ -12855,7 +13022,6 @@ sub EnOcean_Parse($$) {
|
|||||||
|
|
||||||
} elsif ($rorg eq "D4" && $teach) {
|
} elsif ($rorg eq "D4" && $teach) {
|
||||||
# UTE - Universal Uni- and Bidirectional Teach-In / Teach-Out
|
# UTE - Universal Uni- and Bidirectional Teach-In / Teach-Out
|
||||||
#
|
|
||||||
Log3 $name, 5, "EnOcean $name UTE teach-in received from $senderID";
|
Log3 $name, 5, "EnOcean $name UTE teach-in received from $senderID";
|
||||||
my $rorg = sprintf "%02X", $db[0];
|
my $rorg = sprintf "%02X", $db[0];
|
||||||
my $func = sprintf "%02X", $db[1];
|
my $func = sprintf "%02X", $db[1];
|
||||||
@ -12904,6 +13070,9 @@ sub EnOcean_Parse($$) {
|
|||||||
Log3 $name, 2, "EnOcean $name UTE teach-in response send to $senderID";
|
Log3 $name, 2, "EnOcean $name UTE teach-in response send to $senderID";
|
||||||
}
|
}
|
||||||
Log3 $name, 2, "EnOcean $name UTE teach-in accepted EEP $rorg-$func-$type Manufacturer: $mid";
|
Log3 $name, 2, "EnOcean $name UTE teach-in accepted EEP $rorg-$func-$type Manufacturer: $mid";
|
||||||
|
# signal telegram learn mode status
|
||||||
|
my $signalData = EnOcean_signalLearnModeStatus(0, 1, 0, 0, 0, $hash->{DEF}, $attr{$name}{eep});
|
||||||
|
EnOcean_SndRadio(undef, $hash, 1, 'D0', $signalData, defined($attr{$name}{subDef}) ? $attr{$name}{subDef} : '0' x 8, '00', 'F' x 8);
|
||||||
} else {
|
} else {
|
||||||
# Teach-In EEP not supported
|
# Teach-In EEP not supported
|
||||||
$attr{$name}{subType} = "raw";
|
$attr{$name}{subType} = "raw";
|
||||||
@ -12921,6 +13090,9 @@ sub EnOcean_Parse($$) {
|
|||||||
Log3 $name, 2, "EnOcean $name UTE teach-in response send to $senderID";
|
Log3 $name, 2, "EnOcean $name UTE teach-in response send to $senderID";
|
||||||
}
|
}
|
||||||
Log3 $name, 2, "EnOcean $name UTE teach-in accepted EEP $rorg-$func-$type not supported Manufacturer: $mid";
|
Log3 $name, 2, "EnOcean $name UTE teach-in accepted EEP $rorg-$func-$type not supported Manufacturer: $mid";
|
||||||
|
# signal telegram learn mode status
|
||||||
|
my $signalData = EnOcean_signalLearnModeStatus(0, 1, 0, 1, 0, $hash->{DEF}, "$rorg-$func-$type");
|
||||||
|
EnOcean_SndRadio(undef, $hash, 1, 'D0', $signalData, defined($attr{$name}{subDef}) ? $attr{$name}{subDef} : '0' x 8, '00', 'F' x 8);
|
||||||
}
|
}
|
||||||
# store attr subType, manufID ...
|
# store attr subType, manufID ...
|
||||||
EnOcean_CommandSave(undef, undef);
|
EnOcean_CommandSave(undef, undef);
|
||||||
@ -12936,6 +13108,9 @@ sub EnOcean_Parse($$) {
|
|||||||
Log3 $name, 2, "EnOcean $name UTE teach-in deletion response send to $senderID";
|
Log3 $name, 2, "EnOcean $name UTE teach-in deletion response send to $senderID";
|
||||||
}
|
}
|
||||||
Log3 $name, 2, "EnOcean $name UTE teach-in delete request executed";
|
Log3 $name, 2, "EnOcean $name UTE teach-in delete request executed";
|
||||||
|
# signal telegram learn mode status
|
||||||
|
my $signalData = EnOcean_signalLearnModeStatus(0, 1, 0, 4, 0, $hash->{DEF}, $attr{$name}{eep});
|
||||||
|
EnOcean_SndRadio(undef, $hash, 1, 'D0', $signalData, defined($attr{$name}{subDef}) ? $attr{$name}{subDef} : '0' x 8, '00', 'F' x 8);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
# Teach-In Respose telegram received
|
# Teach-In Respose telegram received
|
||||||
@ -14924,6 +15099,113 @@ sub EnOcean_Notify(@) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#####*
|
||||||
|
sub EnOcean_constLightCtrl($) {
|
||||||
|
my ($param) = @_;
|
||||||
|
my ($hash, $mode, $cmd, $dimSet) = @$param;
|
||||||
|
my $lightCtrl = $hash->{constLightCtrl} // return;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
#Log3 $hash->{NAME}, 3, "EnOcean $hash->{NAME} constLightCtrl: 1 CMD: $hash->{helper}{constLightCtrl}[2] " . "CTRL: " . ($hash->{helper}{constLightCtrl}[6] // 'undef') . " RESPONSE: " . ($hash->{helper}{constLightCtrl}[7] // 'undef');
|
||||||
|
RemoveInternalTimer($hash->{helper}{constLightCtrl}) if(exists $hash->{helper}{constLightCtrl});
|
||||||
|
# stop constLightCtrl
|
||||||
|
if (!defined($attr{$name}{brightnessRefDev}) || $cmd !~ m/^dim|response|openLoopCtrl|closedLoopCtrl$/) {
|
||||||
|
delete $hash->{constLightCtrl};
|
||||||
|
delete $hash->{helper}{constLightCtrl};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
# constLightCtrl command set dim is executed, lock recursion
|
||||||
|
return if (!defined($hash->{helper}{constLightCtrl}[6]) && $cmd eq 'dim');
|
||||||
|
my $brightness = ReadingsVal($attr{$name}{brightnessRefDev}, "brightness", undef);
|
||||||
|
# stop constLightCtrl
|
||||||
|
if (!defined($brightness)) {
|
||||||
|
delete $hash->{constLightCtrl};
|
||||||
|
delete $hash->{helper}{constLightCtrl};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#Log3 $hash->{NAME}, 3, "EnOcean $hash->{NAME} constLightCtrl: 2 CMD: $hash->{helper}{constLightCtrl}[2] " . "CTRL: " . ($hash->{helper}{constLightCtrl}[6] // 'undef');
|
||||||
|
my $dimCalc = $dimSet;
|
||||||
|
my $dimTemp;
|
||||||
|
my $logLevel = 3;
|
||||||
|
if ($hash->{constLightCtrl} eq 'openLoopCtrl') {
|
||||||
|
# calc dim
|
||||||
|
my $openLoopCtrlScale = $attr{$name}{openLoopCtrlScale} // '100:100 0:0';
|
||||||
|
my ($scaleHigh, $scaleLow) = split("[ \t][ \t]*", $openLoopCtrlScale);
|
||||||
|
my ($brightnessHigh, $dimHigh) = split(":", $scaleHigh);
|
||||||
|
my ($brightnessLow, $dimLow) = split(":", $scaleLow);
|
||||||
|
$brightnessHigh = $brightnessHigh // 100;
|
||||||
|
$brightnessLow = $brightnessLow // 0;
|
||||||
|
$dimHigh = $dimHigh // 100;
|
||||||
|
$dimLow = $dimLow // 0;
|
||||||
|
$dimCalc = ($dimLow*$brightnessHigh-$brightnessLow*$dimHigh)/($dimLow-$dimHigh)+
|
||||||
|
($brightnessLow-$brightnessHigh)/($dimLow-$dimHigh)*$brightness;
|
||||||
|
#Log3 $hash->{NAME}, 3, "EnOcean $hash->{NAME} constLightCtrl: 3 BRIGHTNESS: $brightness DIM: $dimCalc";
|
||||||
|
$dimCalc = $dimCalc < 0 ? 0 : $dimCalc;
|
||||||
|
$dimCalc = $dimCalc > 100 ? 100 : $dimCalc;
|
||||||
|
$dimTemp = $dimCalc;
|
||||||
|
$dimCalc = int(EnOcean_EMA($hash, 'dim', $dimCalc, 0.25));
|
||||||
|
}
|
||||||
|
if ($cmd eq 'dim') {
|
||||||
|
if (abs($dimCalc - $dimSet) > 5) {
|
||||||
|
# constLightCtrl execute flag
|
||||||
|
$hash->{helper}{constLightCtrl}[6] = undef;
|
||||||
|
# maximum of two responses are expected
|
||||||
|
$hash->{helper}{constLightCtrl}[7] = 2;
|
||||||
|
my @setCmd = ($name, 'dim', $dimCalc);
|
||||||
|
if (defined $hash->{helper}{constLightCtrl}[4]) {
|
||||||
|
$setCmd[3] = $hash->{helper}{constLightCtrl}[4];
|
||||||
|
$setCmd[4] = $hash->{helper}{constLightCtrl}[5] if (defined $hash->{helper}{constLightCtrl}[5])
|
||||||
|
}
|
||||||
|
EnOcean_Set($hash, @setCmd);
|
||||||
|
} else {
|
||||||
|
# clear response flag
|
||||||
|
$hash->{helper}{constLightCtrl}[7] = undef;
|
||||||
|
}
|
||||||
|
$hash->{helper}{constLightCtrl}[6] = 5;
|
||||||
|
} elsif ($cmd eq 'response') {
|
||||||
|
if (defined $hash->{helper}{constLightCtrl}[7]) {
|
||||||
|
# continue constLightCtrl
|
||||||
|
$hash->{helper}{constLightCtrl}[2] = 'dim';
|
||||||
|
$hash->{helper}{constLightCtrl}[6] = 5;
|
||||||
|
# clear response flag
|
||||||
|
-- $hash->{helper}{constLightCtrl}[7] || ($hash->{helper}{constLightCtrl}[7] = undef);
|
||||||
|
} else {
|
||||||
|
# user interaction on the actuator terminates the constLightCtrl
|
||||||
|
delete $hash->{constLightCtrl};
|
||||||
|
delete $hash->{helper}{constLightCtrl};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# start constLightCtrl
|
||||||
|
$hash->{helper}{constLightCtrl}[2] = 'dim';
|
||||||
|
$hash->{helper}{constLightCtrl}[6] = 2;
|
||||||
|
# maximum of two responses are expected
|
||||||
|
$hash->{helper}{constLightCtrl}[7] = 2;
|
||||||
|
}
|
||||||
|
InternalTimer(gettimeofday() + $hash->{helper}{constLightCtrl}[6], 'EnOcean_constLightCtrl', $hash->{helper}{constLightCtrl}, 0);
|
||||||
|
Log3 $hash->{NAME}, 3, "EnOcean $hash->{NAME} constLightCtrl: 4 B: $brightness D: $dimTemp >> $dimCalc CMD: $hash->{helper}{constLightCtrl}[2] " . "CTRL: " . ($hash->{helper}{constLightCtrl}[6] // 'undef') . " RESPONSE: " . ($hash->{helper}{constLightCtrl}[7] // 'undef');
|
||||||
|
return $logLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub EnOcean_EMA($$$$) {
|
||||||
|
# exponential moving average (EMA)
|
||||||
|
# 0 < $wheight < 1
|
||||||
|
my ($hash, $readingName, $readingVal, $wheight) = @_;
|
||||||
|
my $average = exists($hash->{helper}{ema}{$readingName}{average}) ? $hash->{helper}{ema}{$readingName}{average} : $readingVal;
|
||||||
|
$average = $wheight * $readingVal + (1 - $wheight) * $average;
|
||||||
|
$hash->{helper}{ema}{$readingName}{average} = $average;
|
||||||
|
return $average;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub EnOcean_signalLearnModeStatus($$$$$$$) {
|
||||||
|
my ($linkTable, $recTeachRequMsg, $learnModeType, $teachResult, $LearnModeTimeout, $devID, $eep) = @_;
|
||||||
|
my $data = '11';
|
||||||
|
$data .= sprintf "%02X%02X", $linkTable << 7 | $recTeachRequMsg << 6 | $learnModeType << 4 | $teachResult, $LearnModeTimeout;
|
||||||
|
$eep = defined($eep) ? $eep : 'FF-FF-FF';
|
||||||
|
$eep =~ m/^(..)-(..)-(..)$/;
|
||||||
|
$data .= $devID . $1 . $2 . $3;
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
sub EnOcean_environmentAppCustomCmd($) {
|
sub EnOcean_environmentAppCustomCmd($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -18182,6 +18464,30 @@ sub EnOcean_Delete($$) {
|
|||||||
<br><br>
|
<br><br>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<b>Constant Light Controller</b><br>
|
||||||
|
<ul>
|
||||||
|
The constant light controller dims lamps depending on the ambient brightness. Two types of constant light
|
||||||
|
controller are used.<br><br>
|
||||||
|
For the closed loop control, the ambient brightness in the room itself is measured.
|
||||||
|
This value is entered as an actual value in the control. The sensor must measure the brightness,
|
||||||
|
for example, on the table top of the desk. For a stable control, changes in the brightness value
|
||||||
|
by the outside light and the lamps must be detected immediately and at short intervals.
|
||||||
|
Currently, the function of the closed loop control is not yet available in the EnOcean module.<br><br>
|
||||||
|
In the case of open loop control, the lamps are dimmed linearly depending on the outside light.
|
||||||
|
The brightness sensor must detect the outside brightness and must not be affected by the luminous flux
|
||||||
|
of the lamps itself. The open loop control is switched on by
|
||||||
|
<ul><br>
|
||||||
|
<code>set <device> openLoopCtrl</code><br>
|
||||||
|
</ul><br><br>
|
||||||
|
The automatic control can be turned off by any other command. If the dimmaktor reports its stats,
|
||||||
|
the control is also deactivated any manual input, for example on a wall switch.<br>
|
||||||
|
The straight-line characteristic is determined via the attribute <a href="#EnOcean_openLoopCtrlScale">openLoopCtrlScale</a>.
|
||||||
|
Below and above the characteristic thresholds, the dimming values remain constant at the value of dimHigh or dimLow.
|
||||||
|
The name of the brightness sensor must be specified in the <a href="#EnOcean_brightnessRefDev">brightnessRefDev</a> attribute.<br>
|
||||||
|
Currently, the constant light control is available for the gateway/dimming profile. More profiles will follow.
|
||||||
|
<br><br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<b>Remote Management</b><br>
|
<b>Remote Management</b><br>
|
||||||
<ul>
|
<ul>
|
||||||
Remote Management allows EnOcean devices to be configured and maintained over the air.
|
Remote Management allows EnOcean devices to be configured and maintained over the air.
|
||||||
@ -18302,6 +18608,7 @@ sub EnOcean_Delete($$) {
|
|||||||
<li>Energy harvesting and reporting</li>
|
<li>Energy harvesting and reporting</li>
|
||||||
<li>Failure & issues reporting</li>
|
<li>Failure & issues reporting</li>
|
||||||
<li>Radio link quality reporting</li>
|
<li>Radio link quality reporting</li>
|
||||||
|
<li>Learn Mode Status</li>
|
||||||
</ul>
|
</ul>
|
||||||
The Signal Telegram function commands are activated by the attribute <a href="#EnOcean_signal">signal</a>.
|
The Signal Telegram function commands are activated by the attribute <a href="#EnOcean_signal">signal</a>.
|
||||||
All commands are described in the signal telegram chapter of the <a href="#EnOcean_signalGet">get</a>-commands.
|
All commands are described in the signal telegram chapter of the <a href="#EnOcean_signalGet">get</a>-commands.
|
||||||
@ -18336,21 +18643,35 @@ sub EnOcean_Delete($$) {
|
|||||||
<b>Security features</b><br>
|
<b>Security features</b><br>
|
||||||
<ul>
|
<ul>
|
||||||
The receiving and sending of encrypted messages is supported. This module currently allows the secure operating mode of
|
The receiving and sending of encrypted messages is supported. This module currently allows the secure operating mode of
|
||||||
a variety of sensors and PTM 215 based switches.<br>
|
a variety of sensors and PTM 210 / PTM 215 based switches.<br>
|
||||||
To receive secured telegrams, you first have to start the teach in mode via<br><br>
|
To receive secured telegrams, you first have to start the teach in mode via<br><br>
|
||||||
<code>set <IODev> teach <t/s></code><br><br>
|
<code>set <IODev> teach <t/s></code><br><br>
|
||||||
On the PTM 215 module doing the following:<br>
|
Since the beginning of 2021, the PTM 210 / PTM 215 modules offer a normal mode and two secure modes
|
||||||
|
<ul>
|
||||||
|
<li>Implicit RLC (legacy, not recommended)</li>
|
||||||
|
<li>Explicit RLC (recommended)</li><br>
|
||||||
|
</ul>
|
||||||
|
In the case of the Implicit RLC doing the following:<br>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Remove the switch cover of the module</li>
|
<li>Remove the switch cover of the module</li>
|
||||||
<li>Press both buttons of one rocker side (A0 & A1 or B0 & B1)</li>
|
<li>Press both nipples of one rocker side (A0 & AI or B0 & BI)</li>
|
||||||
<li>While keeping the buttons pressed actuate the energy bow twice.</li><br>
|
<li>While keeping the nipples pressed actuate the energy bow twice.</li><br>
|
||||||
</ul>
|
</ul>
|
||||||
This generates two teach-in telegrams which create a Fhem device with the subType "switch.00" and synchronize the Fhem with
|
This generates two teach-in telegrams which create a Fhem device with the subType "switch.00" and synchronize the Fhem with
|
||||||
the PTM 215. Both the Fhem and the PTM 215 now maintain a counter which is used to generate a rolling code encryption scheme.
|
the PTM 210 / PTM 215. Both the Fhem and the PTM210 / PTM 215 now maintain a counter which is used to generate a rolling code encryption scheme.
|
||||||
Also during teach-in, a private key is transmitted to the Fhem. The counter value is allowed to desynchronize for a maximum of
|
Also during teach-in, a private key is transmitted to the Fhem. The counter value is allowed to desynchronize for a maximum of
|
||||||
128 counts, to allow compensating for missed telegrams, if this value is crossed you need to teach-in the PTM 215 again. Also
|
128 counts, to allow compensating for missed telegrams, if this value is crossed you need to teach-in the PTM 215 again. Also
|
||||||
if your Fhem installation gets erased including the state information, you need to teach in the PTM 215 modules again (which
|
if your Fhem installation gets erased including the state information, you need to teach in the PTM 210 / PTM 215 modules again (which
|
||||||
you would need to do anyway).<br><br>
|
you would need to do anyway).<br><br>
|
||||||
|
In the case of the Explicit RLC doing the following:<br>
|
||||||
|
<ul>
|
||||||
|
<li>Remove the switch cover of the module</li>
|
||||||
|
<li>Press any 3 nipples</li>
|
||||||
|
<li>While keeping the nipples pressed actuate the energy bow twice.</li><br>
|
||||||
|
</ul>
|
||||||
|
In this mode, the PTM module sends the RLC value as part of every data telegram. With
|
||||||
|
transmission of the RLC in every data telegram a desynchronization of the RLC counters
|
||||||
|
between receivers and transmitter like described above cannot happen.<br><br>
|
||||||
|
|
||||||
To send secured telegrams, you first have send a secure teach-in to the remode device<br><br>
|
To send secured telegrams, you first have send a secure teach-in to the remode device<br><br>
|
||||||
<ul>
|
<ul>
|
||||||
@ -18819,6 +19140,9 @@ sub EnOcean_Delete($$) {
|
|||||||
or to a setpoint deviation of +/- 3 K be limited. For this use the optional parameter
|
or to a setpoint deviation of +/- 3 K be limited. For this use the optional parameter
|
||||||
[block] = lock|unlock, unlock is default.<br>
|
[block] = lock|unlock, unlock is default.<br>
|
||||||
The profile behaves like a master or slave, see <a href="#EnOcean_devMode">devMode</a>.<br>
|
The profile behaves like a master or slave, see <a href="#EnOcean_devMode">devMode</a>.<br>
|
||||||
|
A monitoring period can be set for signOfLife telegrams of the sensor, see
|
||||||
|
<a href="#EnOcean_signOfLife">signOfLife</a> and <a href="#EnOcean_signOfLifeInterval">signOfLifeInterval</a>.
|
||||||
|
Default is "off" and an interval of 1320 sec.<br>
|
||||||
The attr subType must be roomSensorControl.05 and attr manufID must be 00D.
|
The attr subType must be roomSensorControl.05 and attr manufID must be 00D.
|
||||||
The attributes must be set manually.
|
The attributes must be set manually.
|
||||||
</li>
|
</li>
|
||||||
@ -19246,7 +19570,9 @@ sub EnOcean_Delete($$) {
|
|||||||
for Eltako: t = 1 = fast dimming ... 255 = slow dimming or 0 = dimming speed on the dimmer used<br>
|
for Eltako: t = 1 = fast dimming ... 255 = slow dimming or 0 = dimming speed on the dimmer used<br>
|
||||||
The attr subType must be gateway and gwCmd must be dimming. This is done if the device was
|
The attr subType must be gateway and gwCmd must be dimming. This is done if the device was
|
||||||
created by autocreate.<br>
|
created by autocreate.<br>
|
||||||
For Eltako devices attributes must be set manually. Use the sensor type "PC/FVS" for Eltako devices.
|
For Eltako devices this attributes must be set manually. In addition, the attribute manufID must be set with 00D.
|
||||||
|
Alternatively, the Eltako device can be fully defined using the inofficial EEPs G5-38-08, H5-38-08 or I5-38-08.
|
||||||
|
Use the sensor type "PC/FVS" for Eltako devices.
|
||||||
</li>
|
</li>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
@ -20225,6 +20551,10 @@ sub EnOcean_Delete($$) {
|
|||||||
Set switching delay for reading dayNight based on the reading brightness. The reading dayNight is reset or set
|
Set switching delay for reading dayNight based on the reading brightness. The reading dayNight is reset or set
|
||||||
if the thresholds are permanently undershot or exceed during the delay time.
|
if the thresholds are permanently undershot or exceed during the delay time.
|
||||||
</li>
|
</li>
|
||||||
|
<li><a name="EnOcean_brightnessRefDev">brightnessRefDev</a> <name><br>
|
||||||
|
Name of the device whose reference value is read. The reference values is
|
||||||
|
the reading brightness.
|
||||||
|
</li>
|
||||||
<li><a name="EnOcean_brightnessSunny">brightnessSunny</a> E_min/lx:E_max/lx,
|
<li><a name="EnOcean_brightnessSunny">brightnessSunny</a> E_min/lx:E_max/lx,
|
||||||
[brightnessSunny] = 0...99000:0...99000, 20000:40000 is default.<br>
|
[brightnessSunny] = 0...99000:0...99000, 20000:40000 is default.<br>
|
||||||
Set switching thresholds for reading isSunny based on the reading brightness.
|
Set switching thresholds for reading isSunny based on the reading brightness.
|
||||||
@ -20501,6 +20831,10 @@ sub EnOcean_Delete($$) {
|
|||||||
[observeRefDev] = <name of the own device> is default<br>
|
[observeRefDev] = <name of the own device> is default<br>
|
||||||
Names of the devices to be observed. The list must be separated by spaces.
|
Names of the devices to be observed. The list must be separated by spaces.
|
||||||
</li>
|
</li>
|
||||||
|
<li><a name="EnOcean_openLoopCtrlScale">openLoopCtrlScale</a> <dimHigh>:<brightness1> <dimLow>:<brightness2>,
|
||||||
|
[openLoopCtrlScale] = 100:100 0:0 is default.<br>
|
||||||
|
Bases of the straight-line characteristic of the open loop control dimming function.
|
||||||
|
</li>
|
||||||
<li><a name="EnOcean_pidActorCallBeforeSetting">pidActorCallBeforeSetting</a>,
|
<li><a name="EnOcean_pidActorCallBeforeSetting">pidActorCallBeforeSetting</a>,
|
||||||
[pidActorCallBeforeSetting] = not defined is default<br>
|
[pidActorCallBeforeSetting] = not defined is default<br>
|
||||||
Callback-function, which can manipulate the actorValue. Further information see modul PID20.
|
Callback-function, which can manipulate the actorValue. Further information see modul PID20.
|
||||||
@ -20935,7 +21269,8 @@ sub EnOcean_Delete($$) {
|
|||||||
</li>
|
</li>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<li>Switch (EEP F6-02-01 ... F6-03-02)<br>
|
<li>Pushbutton Switch (EEP F6-02-01 ... F6-03-02)<br>
|
||||||
|
[EnOcean PTM 210, PTM 215 Module]<br>
|
||||||
<ul>
|
<ul>
|
||||||
<li>A0</li>
|
<li>A0</li>
|
||||||
<li>AI</li>
|
<li>AI</li>
|
||||||
@ -21002,7 +21337,7 @@ sub EnOcean_Delete($$) {
|
|||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<li>Pushbutton Switch (EEP D2-03-00)<br>
|
<li>Pushbutton Switch (EEP D2-03-00)<br>
|
||||||
[EnOcean PTM 215 Modul]<br>
|
[EnOcean PTM 210 / PTM 215 Module]<br>
|
||||||
<ul>
|
<ul>
|
||||||
<li>A0</li>
|
<li>A0</li>
|
||||||
<li>AI</li>
|
<li>AI</li>
|
||||||
@ -21484,6 +21819,9 @@ sub EnOcean_Delete($$) {
|
|||||||
<a href="#scaleDecimals">scaleDecimals</a> for the additional scaled reading
|
<a href="#scaleDecimals">scaleDecimals</a> for the additional scaled reading
|
||||||
setpointScaled. Use attribut <a href="#userReadings">userReadings</a> to
|
setpointScaled. Use attribut <a href="#userReadings">userReadings</a> to
|
||||||
adjust the scaling alternatively.<br>
|
adjust the scaling alternatively.<br>
|
||||||
|
A monitoring period can be set for signOfLife telegrams of the sensor, see
|
||||||
|
<a href="#EnOcean_signOfLife">signOfLife</a> and <a href="#EnOcean_signOfLifeInterval">signOfLifeInterval</a>.
|
||||||
|
Default is "off" and an interval of 1320 sec.<br>
|
||||||
The attr subType must be roomSensorControl.05 and attr
|
The attr subType must be roomSensorControl.05 and attr
|
||||||
manufID must be 00D for Eltako Devices. This is done if the device was
|
manufID must be 00D for Eltako Devices. This is done if the device was
|
||||||
created by autocreate.
|
created by autocreate.
|
||||||
@ -22581,6 +22919,7 @@ sub EnOcean_Delete($$) {
|
|||||||
see <a href="#EnOcean_teach-in">Bidirectional Teach-In / Teach-Out</a>.
|
see <a href="#EnOcean_teach-in">Bidirectional Teach-In / Teach-Out</a>.
|
||||||
</li>
|
</li>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<li>Multisensor Window Handle (D2-06-01)<br>
|
<li>Multisensor Window Handle (D2-06-01)<br>
|
||||||
[Soda GmbH]<br>
|
[Soda GmbH]<br>
|
||||||
<ul>
|
<ul>
|
||||||
@ -22588,16 +22927,16 @@ sub EnOcean_Delete($$) {
|
|||||||
<li>alarms: <alarms> (Range: alarms = 00000000 ... FFFFFFFF)</li>
|
<li>alarms: <alarms> (Range: alarms = 00000000 ... FFFFFFFF)</li>
|
||||||
<li>battery: ok|low</li>
|
<li>battery: ok|low</li>
|
||||||
<li>batteryLowClick: enabled|disabled</li>
|
<li>batteryLowClick: enabled|disabled</li>
|
||||||
<li>burglaryAlarm: off|on|invalid|not_supported|unknown</li>
|
|
||||||
<li>handle: up|down|left|right|invalid|not_supported|unknown</li>
|
|
||||||
<li>blinkInterval: t/s|unknown (Range: t = 3 s ... 255 s)</li>
|
<li>blinkInterval: t/s|unknown (Range: t = 3 s ... 255 s)</li>
|
||||||
<li>blinkIntervalSet: t/s|unknown (Range: t = 3 s ... 255 s)</li>
|
<li>blinkIntervalSet: t/s|unknown (Range: t = 3 s ... 255 s)</li>
|
||||||
<li>brightness: E/lx|over_range|invalid|not_supported|unknown (Sensor Range: E = 0 lx ... 60000 lx)</li>
|
<li>brightness: E/lx|over_range|invalid|not_supported|unknown (Sensor Range: E = 0 lx ... 60000 lx)</li>
|
||||||
|
<li>burglaryAlarm: off|on|invalid|not_supported|unknown</li>
|
||||||
<li>buttonLeft: pressed|released|invalid|not_supported|unknown</li>
|
<li>buttonLeft: pressed|released|invalid|not_supported|unknown</li>
|
||||||
<li>buttonLeftPresses: <buttonLeftPresses> (Range: buttonLeftPresses = 00000000 ... FFFFFFFF)</li>
|
<li>buttonLeftPresses: <buttonLeftPresses> (Range: buttonLeftPresses = 00000000 ... FFFFFFFF)</li>
|
||||||
<li>buttonRight: pressed|released|invalid|not_supported|unknown</li>
|
<li>buttonRight: pressed|released|invalid|not_supported|unknown</li>
|
||||||
<li>buttonRightPresses: <buttonRightPresses> (Range: buttonRightPresses = 00000000 ... FFFFFFFF)</li>
|
<li>buttonRightPresses: <buttonRightPresses> (Range: buttonRightPresses = 00000000 ... FFFFFFFF)</li>
|
||||||
<li>energyStorage: 1/%|unknown</li>
|
<li>energyStorage: 1/%|unknown</li>
|
||||||
|
<li>handle: up|down|left|right|invalid|not_supported|unknown</li>
|
||||||
<li>handleClosedClick: enabled|disabled</li>
|
<li>handleClosedClick: enabled|disabled</li>
|
||||||
<li>handleMoveClosed: <handleMoveClosed> (Range: handleMoveClosed = 00000000 ... FFFFFFFF)</li>
|
<li>handleMoveClosed: <handleMoveClosed> (Range: handleMoveClosed = 00000000 ... FFFFFFFF)</li>
|
||||||
<li>handleMoveOpend: <handleMoveOpend> (Range: handleMoveOpend = 00000000 ... FFFFFFFF)</li>
|
<li>handleMoveOpend: <handleMoveOpend> (Range: handleMoveOpend = 00000000 ... FFFFFFFF)</li>
|
||||||
@ -22621,6 +22960,41 @@ sub EnOcean_Delete($$) {
|
|||||||
</li>
|
</li>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
<li>Window and Handle Position Multisensor (D2-06-50)<br>
|
||||||
|
[senso secure SIEGENIA-AUBI KG]<br>
|
||||||
|
<ul>
|
||||||
|
<li>closed|open|tilted</li>
|
||||||
|
<li>alarm: dead_sensor</li>
|
||||||
|
<li>battery: ok|low</li>
|
||||||
|
<li>batteryPercent: 0 ... 100/%</li>
|
||||||
|
<li>burglaryAlarm: off|on</li>
|
||||||
|
<li>calibrationStep: none|close_handle|open_handle|tilt_handle|close_window</li>
|
||||||
|
<li>handle: closed|open|tilted</li>
|
||||||
|
<li>statusAcceleration: ok|error|not_supported</li>
|
||||||
|
<li>statusCalibration: ok|error|invalid</li>
|
||||||
|
<li>statusCntr: <statusCntr> (Range: statusCntr = 00000000 ... FFFFFFFF)</li>
|
||||||
|
<li>statusMagnetic: ok|error|not_supported</li>
|
||||||
|
<li>statusMotion: ok|error|not_supported</li>
|
||||||
|
<li>statusSystem: ok|error|not_supported</li>
|
||||||
|
<li>telegramType: event|heartbeat</li>
|
||||||
|
<li>window: closed|open|tilted</li>
|
||||||
|
<li>state: W: closed|open|tilted H: closed|open|tilted B: ok|low</li>
|
||||||
|
</ul><br>
|
||||||
|
The multisensor is configured using the following attributes:<br>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#EnOcean_subDefH">subDefH</a></li>
|
||||||
|
<li><a href="#EnOcean_subDefW">subDefW</a></li>
|
||||||
|
</ul>
|
||||||
|
A monitoring period can be set for signOfLife telegrams of the sensor, see
|
||||||
|
<a href="#EnOcean_signOfLife">signOfLife</a> and <a href="#EnOcean_signOfLifeInterval">signOfLifeInterval</a>.
|
||||||
|
Default is "on" and an interval of 990 sec.<br>
|
||||||
|
After the teach-in, the sensor must be calibrated immediately. The procedure is described in the user manual.
|
||||||
|
If calibration was successful, the reading calibrationStep displays none and statusCalibration ok.<br>
|
||||||
|
The attr subType must be multisensor.50. This is done if the device was
|
||||||
|
created by autocreate.
|
||||||
|
</li>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
<li>Room Control Panels (D2-10-00 - D2-10-02)<br>
|
<li>Room Control Panels (D2-10-00 - D2-10-02)<br>
|
||||||
[Kieback & Peter RBW322-FTL]<br>
|
[Kieback & Peter RBW322-FTL]<br>
|
||||||
<ul>
|
<ul>
|
||||||
|
Loading…
Reference in New Issue
Block a user