2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-03 23:06:37 +00:00

10_EnOcean: new attribute setCmdTrigger

git-svn-id: https://svn.fhem.de/fhem/trunk@7512 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
klaus-schauer 2015-01-11 06:11:21 +00:00
parent ac65d93e7e
commit 27c4df1c13

View File

@ -328,7 +328,7 @@ EnOcean_Initialize($)
"showtime:1,0 " . "showtime:1,0 " .
"actualTemp angleMax:slider,-180,20,180 alarmAction:no,stop,opens,closes " . "actualTemp angleMax:slider,-180,20,180 alarmAction:no,stop,opens,closes " .
"angleMin:slider,-180,20,180 " . "angleMin:slider,-180,20,180 " .
"angleTime blockUnknownMSC:no,yes blockMotion:no,yes " . "angleTime setCmdTrigger:man,refDev blockUnknownMSC:no,yes blockMotion:no,yes " .
"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 comMode:biDir,uniDir " . "blockFanSpeed:no,yes blockKey:no,yes comMode:biDir,uniDir " .
@ -336,10 +336,10 @@ EnOcean_Initialize($)
"defaultChannel:" . join(",", @EnO_defaultChannel) . " " . "defaultChannel:" . join(",", @EnO_defaultChannel) . " " .
"demandRespAction demandRespRefDev demandRespMax:A0,AI,B0,BI,C0,CI,D0,DI ". "demandRespAction demandRespRefDev demandRespMax:A0,AI,B0,BI,C0,CI,D0,DI ".
"demandRespMin:A0,AI,B0,BI,C0,CI,D0,DI demandRespRandomTime " . "demandRespMin:A0,AI,B0,BI,C0,CI,D0,DI demandRespRandomTime " .
"demandRespThreshold:slider,0,1,15 destinationID " . "demandRespThreshold:slider,0,1,15 demandRespTimeoutLevel:max,last destinationID " .
"devChannel devUpdate:off,auto,demand,polling,interrupt dimValueOn " . "devChannel devUpdate:off,auto,demand,polling,interrupt dimValueOn " .
"disable:0,1 disabledForIntervals " . "disable:0,1 disabledForIntervals " .
"displayContent:humidity,off,setPointTemp,tempertureExtern,temperatureIntern,time,default,no_change " . "displayContent:default,humidity,off,setPointTemp,tempertureExtern,temperatureIntern,time,no_change " .
"eep gwCmd:" . join(",", sort @EnO_gwCmd) . " humidityRefDev " . "eep gwCmd:" . join(",", sort @EnO_gwCmd) . " humidityRefDev " .
"key macAlgo " . "key macAlgo " .
"manufID:" . join(",", sort keys %EnO_manuf) . " " . "manufID:" . join(",", sort keys %EnO_manuf) . " " .
@ -763,7 +763,8 @@ EnOcean_Set($@)
$cmdID = 0x201; $cmdID = 0x201;
$manufID = 0x7FF; $manufID = 0x7FF;
$rorg = "C5"; $rorg = "C5";
my $seq = int(rand(2) + 1) << 6; # SEQ = 0...3
my $seq = int(rand(4)) << 6;
shift(@a); shift(@a);
my $cntr = (((4 << 11) | $manufID) << 12) | $cmdID; my $cntr = (((4 << 11) | $manufID) << 12) | $cmdID;
#### ####
@ -1584,6 +1585,95 @@ EnOcean_Set($@)
} elsif ($st eq "energyManagement.01") { } elsif ($st eq "energyManagement.01") {
# Energy Management, Demand Response # Energy Management, Demand Response
# (A5-37-01) # (A5-37-01)
$rorg = "A5";
$updateState = 0;
my $drLevel = 15;
my $powerUsage = 100;
my $powerUsageLevel = 1;
my $powerUsageScale = 0;
my $randomStart = 0;
my $randomEnd = 0;
my $randomTime = rand(AttrVal($name, "demandRespRandomTime", 1));
my $setpoint = 255;
my $timeout = 0;
my $threshold = AttrVal($name, "demandRespThreshold", 8);
if($cmd eq "teach") {
# teach-in EEP A5-37-01, Manufacturer "Multi user Manufacturer ID"
$data = "940FFF80";
($err, $subDef) = EnOcean_AssignSenderID(undef, $hash, "subDef");
readingsSingleUpdate($hash, "state", "teach", 1);
Log3 $name, 3, "EnOcean set $name demand response $cmd";
} elsif ($cmd eq "level") {
return "Usage: $cmd 0...15 [yes|no [yes|no [timeout/min]]]]"
if(@a < 2 || $a[1] !~ m/^\d+$/ || $a[1] < 0 || $a[1] > 15 );
$drLevel = $a[1];
$powerUsage = $a[1] / 15 * 100;
$powerUsageLevel = $drLevel >= $threshold ? 1 : 0;
$setpoint = $a[1] * 17;
shift(@a);
} elsif ($cmd eq "max") {
} elsif ($cmd eq "min") {
$drLevel = 0;
$powerUsage = 0;
$powerUsageLevel = 0;
$setpoint = 0;
} elsif ($cmd eq "power") {
return "Usage: $cmd 0...100 [yes|no [yes|no [timeout/min]]]]"
if(@a < 2 || $a[1] !~ m/^\d+$/ || $a[1] < 0 || $a[1] > 100);
$drLevel = $a[1] / 100 * 15;
$powerUsage = $a[1];
$powerUsageLevel = $drLevel >= $threshold ? 1 : 0;
$setpoint = $a[1] * 2.55;
shift(@a);
} elsif ($cmd eq "setpoint") {
return "Usage: $cmd 0...255 [yes|no [yes|no [timeout/min]]]]"
if(@a < 2 || $a[1] !~ m/^\d+$/ || $a[1] < 0 || $a[1] > 255 );
$drLevel = $a[1] / 255 * 15 ;
$powerUsage = $a[1] / 255 * 100;
$powerUsageLevel = $drLevel >= $threshold ? 1 : 0;
$setpoint = $a[1];
shift(@a);
} else {
return "Unknown argument " . $cmd . ", choose one of " . $cmdList . "level:slider,0,1,15 max:noArg min:noArg power:slider,0,5,100 setpoint:slider,0,5,255 teach:noArg"
}
if ($cmd ne "teach") {
if (@a > 1) {
return "Usage: $cmd [<cmdValue>] [max|rel [yes|no [yes|no [timeout/min]]]]" if($a[1] !~ m/^max|rel$/);
$powerUsageScale = $a[1] eq "rel" ? 0x80 : 0;
shift(@a);
}
if (@a > 1) {
return "Usage: $cmd [<cmdValue>] [max|rel [yes|no [yes|no [timeout/min]]]]" if($a[1] !~ m/^yes|no$/);
$randomStart = $a[1] eq "yes" ? 4 : 0;
shift(@a);
}
if (@a > 1) {
return "Usage: $cmd [<cmdValue>] [max|rel [yes|no [yes|no [timeout/min]]]]" if($a[1] !~ m/^yes|no$/);
$randomEnd = $a[1] eq "yes" ? 2 : 0;
shift(@a);
}
if (@a > 1) {
return "Usage: $cmd [<cmdValue>] [max|rel [yes|no [yes|no [timeout/min]]]]"
if($a[1] !~ m/^\d+$/ || $a[1] < 0 || $a[1] > 3825);
$timeout = int($a[1] / 15);
shift(@a);
}
$data = sprintf "%02X%02X%02X%02X", $setpoint, $powerUsageScale | $powerUsage, $timeout,
$drLevel << 4 | $randomStart | $randomEnd | $powerUsageLevel;
my @db = ($drLevel << 4 | $randomStart | $randomEnd | $powerUsageLevel,
$timeout, $powerUsageScale | $powerUsage, $setpoint);
EnOcean_energyManagement_01Parse($hash, @db);
}
shift(@a);
Log3 $name, 3, "EnOcean $name data: $data";
} elsif ($st eq "manufProfile") { } elsif ($st eq "manufProfile") {
if ($manufID eq "00D") { if ($manufID eq "00D") {
@ -4466,56 +4556,8 @@ EnOcean_Parse($$)
} elsif ($st eq "energyManagement.01") { } elsif ($st eq "energyManagement.01") {
# Energy Management, Demand Response # Energy Management, Demand Response
# (A5-37-01) # (A5-37-01)
my $setpoint = $db[3]; EnOcean_energyManagement_01Parse($hash, @db);
$hash->{helper}{setpoint} = ReadingsVal($name, "setpoint", undef);
my $powerUsage = $db[2] & 0x7F;
$hash->{helper}{powerUsage} = ReadingsVal($name, "powerUsage", undef);
my $powerUsageScale = $db[2] & 0x80 ? "rel" : "abs";
$hash->{helper}{powerUsageScale} = ReadingsVal($name, "powerUsageScale", undef);
my $timeout = $db[1] * 15 * 60;
my $drLevel = $db[0] & 0xF0 >> 4;
$hash->{helper}{drLevel} = ReadingsVal($name, "drLevel", undef);
my $randomStart = $db[0] & 4 ? "yes" : "no";
my $randomEnd = $db[0] & 2 ? "yes" : "no";
my $powerUsageLevel = $db[0] & 1 ? "max" : "min";
$hash->{helper}{powerUsageLevel} = ReadingsVal($name, "powerUsageLevel", undef);
my $drState;
if ($randomStart eq "yes" || $randomEnd eq "yes") {
push @event, "3:state:waiting";
} elsif ($drLevel == 15) {
push @event, "3:state:off";
} else {
push @event, "3:state:on";
}
push @event, "3:drLevel:$drLevel";
push @event, "3:powerUsage:$powerUsage";
push @event, "3:powerUsageLevel:$powerUsageLevel";
push @event, "3:powerUsageScale:$powerUsageScale";
push @event, "3:randomEnd:$randomEnd";
push @event, "3:randomStart:$randomStart";
push @event, "3:setpoint:$setpoint";
push @event, "3:timeout:$timeout";
my $actionCmd = AttrVal($name, "demandRespAction", undef);
my $randomTime = AttrVal($name, "demandRespRandomTime", 1);
my $threshold = AttrVal($name, "demandRespThreshold", 8);
if ($randomStart eq "yes") {
# gettimeofday()
} else {
if (defined $actionCmd) {
# action exec
my %specials= ("%NAME" => $name,
"%TYPE" => $hash->{TYPE},
"%EVENT" => ($drLevel, $setpoint, $powerUsage, $powerUsageScale, $powerUsageLevel,
$randomStart, $randomEnd, $timeout)
);
$actionCmd = EvalSpecials($actionCmd, %specials);
#$actionCmd = SemicolonEscape($actionCmd);
my $ret = AnalyzeCommandChain(undef, $actionCmd);
Log3 $name, 2, "$name: $ret" if($ret);
}
}
} elsif ($st eq "manufProfile") { } elsif ($st eq "manufProfile") {
# Manufacturer Specific Applications (EEP A5-3F-7F) # Manufacturer Specific Applications (EEP A5-3F-7F)
if ($manufID eq "002") { if ($manufID eq "002") {
@ -5452,7 +5494,7 @@ sub EnOcean_Attr(@) {
if (AttrVal($name, "subType", "") eq "blindsCtrl.00") { if (AttrVal($name, "subType", "") eq "blindsCtrl.00") {
# no rotation # no rotation
$data = "7FFF000705"; $data = "7FFF000705";
EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "FFFFFFFF"), "00", $hash->{DEF}); EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "00000000"), "00", $hash->{DEF});
} }
} elsif (AttrVal($name, "subType", "") eq "blindsCtrl.00" && $attrVal =~ m/^[+-]?\d+(\.\d+)?$/ && $attrVal >= 0 && $attrVal <= 2.54) { } elsif (AttrVal($name, "subType", "") eq "blindsCtrl.00" && $attrVal =~ m/^[+-]?\d+(\.\d+)?$/ && $attrVal >= 0 && $attrVal <= 2.54) {
if ($attrVal < 1) { if ($attrVal < 1) {
@ -5462,7 +5504,7 @@ sub EnOcean_Attr(@) {
} }
$data = sprintf "7FFF%02X0705", $attrVal; $data = sprintf "7FFF%02X0705", $attrVal;
#EnOcean_SndRadio(undef, $hash, $packetType, $rorg, $data, $subDef, $status, $destinationID); #EnOcean_SndRadio(undef, $hash, $packetType, $rorg, $data, $subDef, $status, $destinationID);
EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "FFFFFFFF"), "00", $hash->{DEF}); EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "00000000"), "00", $hash->{DEF});
} elsif (AttrVal($name, "subType", "") eq "manufProfile" && AttrVal($name, "manufID", "") eq "00D" && } elsif (AttrVal($name, "subType", "") eq "manufProfile" && AttrVal($name, "manufID", "") eq "00D" &&
$attrVal =~ m/^[+-]?\d+?$/ && $attrVal >= 1 && $attrVal <= 6) { $attrVal =~ m/^[+-]?\d+?$/ && $attrVal >= 1 && $attrVal <= 6) {
@ -5477,7 +5519,7 @@ sub EnOcean_Attr(@) {
if (AttrVal($name, "subType", "") eq "blindsCtrl.00") { if (AttrVal($name, "subType", "") eq "blindsCtrl.00") {
# no alarm action # no alarm action
$data = "7FFFFF0005"; $data = "7FFFFF0005";
EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "FFFFFFFF"), "00", $hash->{DEF}); EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "00000000"), "00", $hash->{DEF});
} }
} elsif ($attrVal =~ m/(no|stop|opens|closes)$/) { } elsif ($attrVal =~ m/(no|stop|opens|closes)$/) {
if (AttrVal($name, "subType", "") eq "blindsCtrl.00") { if (AttrVal($name, "subType", "") eq "blindsCtrl.00") {
@ -5493,13 +5535,21 @@ sub EnOcean_Attr(@) {
} }
$data = sprintf "7FFFFF%02X05", $alarmAction; $data = sprintf "7FFFFF%02X05", $alarmAction;
#EnOcean_SndRadio(undef, $hash, $packetType, $rorg, $data, $subDef, $status, $destinationID); #EnOcean_SndRadio(undef, $hash, $packetType, $rorg, $data, $subDef, $status, $destinationID);
EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "FFFFFFFF"), "00", $hash->{DEF}); EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "00000000"), "00", $hash->{DEF});
} }
} else { } else {
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong"; Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName"); CommandDeleteAttr(undef, "$name $attrName");
} }
} elsif ($attrName eq "setCmdTrigger") {
if (!defined $attrVal){
} elsif ($attrVal !~ m/^man|refDev$/) {
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName");
}
} elsif ($attrName =~ m/^block.*/) { } elsif ($attrName =~ m/^block.*/) {
if (!defined $attrVal){ if (!defined $attrVal){
@ -5663,13 +5713,13 @@ sub EnOcean_Attr(@) {
if (AttrVal($name, "subType", "") eq "blindsCtrl.00") { if (AttrVal($name, "subType", "") eq "blindsCtrl.00") {
# set shutTime to max # set shutTime to max
$data = "7530FF0705"; $data = "7530FF0705";
EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "FFFFFFFF"), "00", $hash->{DEF}); EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "00000000"), "00", $hash->{DEF});
} }
} elsif (AttrVal($name, "subType", "") eq "blindsCtrl.00" && $attrVal =~ m/^[+-]?\d+$/ && $attrVal >= 5 && $attrVal <= 300) { } elsif (AttrVal($name, "subType", "") eq "blindsCtrl.00" && $attrVal =~ m/^[+-]?\d+$/ && $attrVal >= 5 && $attrVal <= 300) {
$attrVal = int($attrVal * 100); $attrVal = int($attrVal * 100);
$data = sprintf "%04XFF0705", $attrVal; $data = sprintf "%04XFF0705", $attrVal;
#EnOcean_SndRadio(undef, $hash, $packetType, $rorg, $data, $subDef, $status, $destinationID); #EnOcean_SndRadio(undef, $hash, $packetType, $rorg, $data, $subDef, $status, $destinationID);
EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "FFFFFFFF"), "00", $hash->{DEF}); EnOcean_SndRadio(undef, $hash, 1, "D2", $data, AttrVal($name, "subDef", "00000000"), "00", $hash->{DEF});
} elsif (AttrVal($name, "subType", "") eq "manufProfile" && AttrVal($name, "manufID", "") eq "00D" && } elsif (AttrVal($name, "subType", "") eq "manufProfile" && AttrVal($name, "manufID", "") eq "00D" &&
$attrVal =~ m/^[+-]?\d+$/ && $attrVal >= 1 && $attrVal <= 255) { $attrVal =~ m/^[+-]?\d+$/ && $attrVal >= 1 && $attrVal <= 255) {
@ -5773,6 +5823,10 @@ sub EnOcean_Notify(@) {
if (AttrVal($name, "observeRefDev", undef) eq $1) { if (AttrVal($name, "observeRefDev", undef) eq $1) {
CommandAttr(undef, "$name observeRefDev $2"); CommandAttr(undef, "$name observeRefDev $2");
} }
} elsif (defined AttrVal($name, "demandRespRefDev", undef)) {
if (AttrVal($name, "demandRespRefDev", undef) eq $1) {
CommandAttr(undef, "$name demandRespRefDev $2");
}
} }
#Log3($name, 5, "EnOcean $name <notify> RENAMED old: $1 new: $2"); #Log3($name, 5, "EnOcean $name <notify> RENAMED old: $1 new: $2");
@ -5790,6 +5844,10 @@ sub EnOcean_Notify(@) {
if (AttrVal($name, "observeRefDev", undef) eq $1) { if (AttrVal($name, "observeRefDev", undef) eq $1) {
CommandDeleteAttr(undef, "$name observeRefDev"); CommandDeleteAttr(undef, "$name observeRefDev");
} }
} elsif (defined AttrVal($name, "demandRespRefDev", undef)) {
if (AttrVal($name, "demandRespRefDev", undef) eq $1) {
CommandDeleteAttr(undef, "$name demandRespRefDev");
}
} }
#Log3($name, 5, "EnOcean $name <notify> DELETED $1"); #Log3($name, 5, "EnOcean $name <notify> DELETED $1");
@ -5824,11 +5882,12 @@ sub EnOcean_Notify(@) {
#Log3($name, 5, "EnOcean $name <notify> SHUTDOWN"); #Log3($name, 5, "EnOcean $name <notify> SHUTDOWN");
} else { } else {
my (@parts, $reading, $value) = (undef, "", ""); my @parts = split(/: | /, $s);
if (defined AttrVal($name, "observeRefDev", undef)) { if (defined AttrVal($name, "observeRefDev", undef)) {
my @observeRefDev = split("[ \t][ \t]*", AttrVal($name, "observeRefDev", undef)); my @observeRefDev = split("[ \t][ \t]*", AttrVal($name, "observeRefDev", undef));
if (grep /^$devName$/, @observeRefDev) { if (grep /^$devName$/, @observeRefDev) {
@parts = split(/: /, $s); my ($reading, $value) = ("", "");
$reading = shift @parts; $reading = shift @parts;
if (!defined($parts[0]) || @parts > 1) { if (!defined($parts[0]) || @parts > 1) {
$value = $s; $value = $s;
@ -5838,11 +5897,112 @@ sub EnOcean_Notify(@) {
} }
my @cmdObserve = ($devName, $reading, $value); my @cmdObserve = ($devName, $reading, $value);
EnOcean_observeParse(2, $hash, @cmdObserve); EnOcean_observeParse(2, $hash, @cmdObserve);
#Log3($name, 5, "EnOcean $name <notify> observeRefDev $devName $reading: $value"); #Log3($name, 5, "EnOcean $name <notify> observeRefDev: $devName $reading: $value");
} }
} else {
#Log3($name, 5, "EnOcean $name <notify> $devName $s");
} }
if (defined AttrVal($name, "demandRespRefDev", undef)) {
my @demandRespRefDev = split("[ \t][ \t]*", AttrVal($name, "demandRespRefDev", undef));
if (grep /^$devName$/, @demandRespRefDev) {
my @cmdDemandResponse;
my $actionCmd = AttrVal($name, "demandRespAction", undef);
if (defined $actionCmd) {
if ($parts[0] =~ m/^on|off$/) {
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set $parts[0]");
my %specials= ("%NAME" => $name,
"%DEMANDRESPNAME" => $devName,
"%TYPE" => $hash->{TYPE},
"%DEMANDRESPTYPE" => $dev->{TYPE},
"%LEVEL" => ReadingsVal($devName, "level", 15),
"%SETPOINT" => ReadingsVal($devName, "setpoint", 255),
"%POWERUSAGE" => ReadingsVal($devName, "powerUsage", 100),
"%POWERUSAGESCALE" => ReadingsVal($devName, "powerUsageScale", "max"),
"%POWERUSAGELEVEL" => ReadingsVal($devName, "powerUsageLevel", "max"),
"%STATE" => ReadingsVal($name, "state", "off")
);
# action exec
$actionCmd = EvalSpecials($actionCmd, %specials);
my $ret = AnalyzeCommandChain(undef, $actionCmd);
Log3 $name, 2, "$name: $ret" if($ret);
}
} elsif (AttrVal($name, "subType", "") eq "switch" || AttrVal($name, "subTypeSet", "") eq "switch") {
if ($parts[0] eq "powerUsageLevel" && $parts[1] eq "max") {
@cmdDemandResponse = ($name, AttrVal($name, "demandRespMax", "B0"));
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
} elsif ($parts[0] eq "powerUsageLevel" && $parts[1] eq "min") {
@cmdDemandResponse = ($name, AttrVal($name, "demandRespMin", "BI"));
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
}
} elsif (AttrVal($name, "subType", "") eq "gateway" && AttrVal($name, "gwCmd", "") eq "switching") {
if ($parts[0] eq "powerUsageLevel" && $parts[1] eq "max") {
@cmdDemandResponse = ($name, "on");
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
} elsif ($parts[0] eq "powerUsageLevel" && $parts[1] eq "min") {
@cmdDemandResponse = ($name, "off");
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
}
} elsif ((AttrVal($name, "subType", "") eq "gateway" && AttrVal($name, "gwCmd", "") eq "dimming")
|| AttrVal($name, "subType", "") eq "actuator.01") {
if ($parts[0] eq "powerUsage") {
if (ReadingsVal($devName, "powerUsageScale", "max") eq "rel") {
@cmdDemandResponse = ($name, "dim", $parts[1] * ReadingsVal($name, "dimValueLast", 100) / 100);
} else {
@cmdDemandResponse = ($name, "dim", $parts[1]);
}
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
}
} elsif ((AttrVal($name, "subType", "") eq "roomSensorControl.05" && AttrVal($name, "manufID", "") eq "00D")) {
if ($parts[0] eq "level") {
@cmdDemandResponse = ($name, "nightReduction", int(5 - 1/3 * $parts[1]));
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
}
} elsif (AttrVal($name, "subType", "") eq "roomSensorControl.05") {
if ($parts[0] eq "setpoint") {
@cmdDemandResponse = ($name, $parts[0], $parts[1]);
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
}
} elsif (AttrVal($name, "subType", "") eq "roomCtrlPanel.00") {
if ($parts[0] eq "powerUsageLevel" && $parts[1] eq "max") {
@cmdDemandResponse = ($name, "roomCtrlMode", "comfort");
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
} elsif ($parts[0] eq "powerUsageLevel" && $parts[1] eq "min") {
@cmdDemandResponse = ($name, "roomCtrlMode", "economy");
Log3($name, 3, "EnOcean $name <notify> demandRespRefDev: $devName Cmd: set " . join(" ", @cmdDemandResponse));
EnOcean_Set($hash, @cmdDemandResponse);
}
}
}
}
if (defined(AttrVal($name, "temperatureRefDev", undef)) && AttrVal($name, "setCmdTrigger", "man") eq "refDev") {
if ($devName eq AttrVal($name, "temperatureRefDev", "")) {
if ($parts[0] eq "temperature") {
if (AttrVal($name, "subType", "") eq "roomSensorControl.05" && AttrVal($name, "manufID", "") eq "00D") {
my @setCmd = ($name, "setpointTemp");
EnOcean_Set($hash, @setCmd);
} elsif (AttrVal($name, "subType", "") eq "roomSensorControl.05") {
my @setCmd = ($name, "setpoint");
EnOcean_Set($hash, @setCmd);
}
}
}
#Log3 $name, 2, "EnOcean $name <notify> $devName $s";
}
} }
} }
return undef; return undef;
@ -6065,22 +6225,6 @@ EnOcean_roomCtrlPanel_00Cmd($$$$)
$response = "room control setup send $data"; $response = "room control setup send $data";
$logLevel = 2; $logLevel = 2;
# } elsif ($waitingCmds & 4) {
# # configuration message (set time) waiting
# my ($sec, $min, $hour, $day, $month, $year) = localtime();
# $month += 1;
# $year += 1900;
# my ($db7, $db6, $db5, $db4, $db1, $db0) = (64, 0, 0, 0, $min << 2, $hour << 3 | 1);
# my $db32 = ($day << 4 | $month) << 7 | $year - 2000;
# $data = sprintf "%02X%02X%02X%02X%04X%02X%02X", $db7, $db6, $db5, $db4, $db32, $db1, $db0;
# $min = $min < 10 ? $min = "0" . $min : $min;
# $hour = $hour < 10 ? $hour = "0" . $hour : $hour;
# $day = $day < 10 ? $day = "0" . $day : $day;
# $month = $month < 10 ? $month = "0". $month : $month;
# # clear command
# $waitingCmds = $waitingCmds & 251 + 256;
# $response = "configuration message send $year-$month-$day $hour:$min $data";
} elsif ($waitingCmds & 64 || $waitingCmds & 4) { } elsif ($waitingCmds & 64 || $waitingCmds & 4) {
# configuration message waiting # configuration message waiting
my ($sec, $min, $hour, $day, $month, $year) = localtime(); my ($sec, $min, $hour, $day, $month, $year) = localtime();
@ -6613,6 +6757,7 @@ sub EnOcean_InternalTimer($$$$$)
} }
InternalTimer($tim, $callback, $mHash, $waitIfInitNotDone); InternalTimer($tim, $callback, $mHash, $waitIfInitNotDone);
Log3 $hash->{NAME}, 5, "EnOcean setting timer $timerName at " . strftime("%Y-%m-%d %H:%M:%S", localtime($tim)); Log3 $hash->{NAME}, 5, "EnOcean setting timer $timerName at " . strftime("%Y-%m-%d %H:%M:%S", localtime($tim));
return;
} }
# #
@ -6631,6 +6776,7 @@ sub EnOcean_RemoveInternalTimer($$)
} }
} }
Log3 $hash->{NAME}, 5, "EnOcean removing timer $timerName"; Log3 $hash->{NAME}, 5, "EnOcean removing timer $timerName";
return;
} }
# #
@ -6663,6 +6809,7 @@ sub EnOcean_observeInit($$@)
$hash->{helper}{observeCmds}{$cmdValue[1]} = $cmdValue[1]; $hash->{helper}{observeCmds}{$cmdValue[1]} = $cmdValue[1];
} }
$hash->{helper}{observeCntr} = 1; $hash->{helper}{observeCntr} = 1;
CommandDeleteReading(undef, "$name observeFailedDev");
my %functionHash = (hash => $hash, function => "observe"); my %functionHash = (hash => $hash, function => "observe");
RemoveInternalTimer(\%functionHash); RemoveInternalTimer(\%functionHash);
InternalTimer(gettimeofday() + 1, "EnOcean_observeRepeat", \%functionHash, 0); InternalTimer(gettimeofday() + 1, "EnOcean_observeRepeat", \%functionHash, 0);
@ -6750,21 +6897,23 @@ sub EnOcean_observeRepeat($)
InternalTimer(gettimeofday() + 1, "EnOcean_observeRepeat", $functionHash, 0); InternalTimer(gettimeofday() + 1, "EnOcean_observeRepeat", $functionHash, 0);
} else { } else {
# reached the maximum number of retries, clear last command # reached the maximum number of retries, clear last command
Log3 $name, 2, "EnOcean set " . join(" ", @{$hash->{helper}{lastCmdValue}}) . " observing failed"; Log3 $name, 2, "EnOcean set " . join(" ", @{$hash->{helper}{lastCmdValue}}) .
" observing " . join(" ", @{$hash->{helper}{observeRefDev}}) . " failed";
#splice(@{$hash->{helper}{observeRefDev}}, 0); #splice(@{$hash->{helper}{observeRefDev}}, 0);
my $actionCmd = AttrVal($name, "observeErrorAction", undef); my $actionCmd = AttrVal($name, "observeErrorAction", undef);
if (defined $actionCmd) { if (defined $actionCmd) {
# error action exec # error action exec
my %specials= ( my %specials= (
"%NAME" => shift(@{$hash->{helper}{lastCmdValue}}), "%NAME" => shift(@{$hash->{helper}{lastCmdValue}}),
"%FAILEDDEV" => join(" ", @{$hash->{helper}{observeRefDev}}),
"%TYPE" => $hash->{TYPE}, "%TYPE" => $hash->{TYPE},
"%EVENT" => ReplaceEventMap($name, join(" ", @{$hash->{helper}{lastCmdValue}}), 1) "%EVENT" => ReplaceEventMap($name, join(" ", @{$hash->{helper}{lastCmdValue}}), 1)
); );
$actionCmd = EvalSpecials($actionCmd, %specials); $actionCmd = EvalSpecials($actionCmd, %specials);
#$actionCmd = SemicolonEscape($actionCmd);
my $ret = AnalyzeCommandChain(undef, $actionCmd); my $ret = AnalyzeCommandChain(undef, $actionCmd);
Log3 $name, 2, "$name: $ret" if($ret); Log3 $name, 2, "$name: $ret" if($ret);
} }
readingsSingleUpdate($hash, "observeFailedDev", join(" ", @{$hash->{helper}{observeRefDev}}), 1);
delete $hash->{helper}{observeCmds}; delete $hash->{helper}{observeCmds};
delete $hash->{helper}{observeCntr}; delete $hash->{helper}{observeCntr};
delete $hash->{helper}{observeRefDev}; delete $hash->{helper}{observeRefDev};
@ -6774,6 +6923,190 @@ sub EnOcean_observeRepeat($)
} }
return; return;
} }
#
sub EnOcean_energyManagement_01Parse($@)
{
my ($hash, @db) = @_;
my $name = $hash->{NAME};
# [drLevel] = 15 : no requests for reduction in power consumptions
my $drLevel = ($db[0] & 0xF0) >> 4;
my $powerUsage = $db[2] & 0x7F;
my $powerUsageLevel = $db[0] & 1 ? "max" : "min";
my $powerUsageScale = $db[2] & 0x80 ? "rel" : "max";
my $randomStart = $db[0] & 4 ? "yes" : "no";
my $randomEnd = $db[0] & 2 ? "yes" : "no";
my $randomTime = rand(AttrVal($name, "demandRespRandomTime", 1));
my $setpoint = $db[3];
my $timeout = $db[1] * 15 * 60;
$randomTime = $randomTime > $timeout && $timeout > 0 ? rand($timeout) : rand($randomTime);
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "randomEnd", $randomEnd);
readingsBulkUpdate($hash, "randomStart", $randomStart);
my %timeoutHash = (hash => $hash, function => "demandResponseTimeout");
my %functionHash = (hash => $hash,
function => "demandResponseExec",
drLevel => $drLevel,
powerUsage => $powerUsage,
powerUsageLevel => $powerUsageLevel,
powerUsageScale => $powerUsageScale,
setpoint => $setpoint
);
RemoveInternalTimer(\%timeoutHash);
RemoveInternalTimer(\%functionHash);
if ($timeout > 0 && $drLevel < 15) {
# timeout timer
InternalTimer(gettimeofday() + $timeout, "EnOcean_demandResponseTimeout", \%timeoutHash, 0);
my ($sec, $min, $hour, $day, $month, $year) = localtime(time + $timeout);
$month += 1;
$year += 1900;
$min = $min < 10 ? $min = "0" . $min : $min;
$hour = $hour < 10 ? $hour = "0" . $hour : $hour;
$day = $day < 10 ? $day = "0" . $day : $day;
$month = $month < 10 ? $month = "0". $month : $month;
readingsBulkUpdate($hash, "timeout", "$year-$month-$day $hour:$min:$sec");
} else {
CommandDeleteReading(undef, "$name timeout");
}
if ($randomStart eq "yes" && ReadingsVal($name, "level", 15) == 15) {
readingsBulkUpdate($hash, "state", "waiting_for_start");
Log3 $name, 3, "EnOcean set $name demand response waiting for start";
InternalTimer(gettimeofday() + $randomTime, "EnOcean_demandResponseExec", \%functionHash, 0);
} elsif ($randomEnd eq "yes" && ReadingsVal($name, "level", 15) < 15) {
readingsBulkUpdate($hash, "state", "waiting_for_stop");
Log3 $name, 3, "EnOcean set $name demand response waiting for stop";
InternalTimer(gettimeofday() + $randomTime, "EnOcean_demandResponseExec", \%functionHash, 0);
} else {
EnOcean_demandResponseExec(\%functionHash);
}
readingsEndUpdate($hash, 1);
return;
}
#
sub EnOcean_demandResponseExec($)
{
my ($functionHash) = @_;
my $function = $functionHash->{function};
my $hash = $functionHash->{hash};
my $drLevel = $functionHash->{drLevel};
my $powerUsage = $functionHash->{powerUsage};
my $powerUsageLevel = $functionHash->{powerUsageLevel};
my $powerUsageScale = $functionHash->{powerUsageScale};
my $setpoint = $functionHash->{setpoint};
my $name = $hash->{NAME};
my $actionCmd = AttrVal($name, "demandRespAction", undef);
# save old values
$hash->{helper}{drLevel} = ReadingsVal($name, "level", 15);
$hash->{helper}{powerUsage} = ReadingsVal($name, "powerUsage", 100);
$hash->{helper}{powerUsageLevel} = ReadingsVal($name, "powerUsageLevel", "max");
$hash->{helper}{powerUsageScale} = ReadingsVal($name, "powerUsageScale", "max");
$hash->{helper}{setpoint} = ReadingsVal($name, "setpoint", 255);
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "level", $drLevel);
readingsBulkUpdate($hash, "powerUsage", $powerUsage);
readingsBulkUpdate($hash, "powerUsageLevel", $powerUsageLevel);
readingsBulkUpdate($hash, "powerUsageScale", $powerUsageScale);
readingsBulkUpdate($hash, "setpoint", $setpoint);
if ($drLevel == 15) {
readingsBulkUpdate($hash, "state", "off");
Log3 $name, 3, "EnOcean set $name demand response off";
} else {
readingsBulkUpdate($hash, "state", "on");
Log3 $name, 3, "EnOcean set $name demand response on";
}
readingsEndUpdate($hash, 1);
if (defined $actionCmd) {
# action exec
# my %specials= ("%NAME" => $name,
# "%TYPE" => $hash->{TYPE},
# "%EVENT" => "$drLevel $setpoint $powerUsage $powerUsageScale $powerUsageLevel"
# );
my %specials= ("%NAME" => $name,
"%TYPE" => $hash->{TYPE},
"%LEVEL" => $drLevel,
"%SETPOINT" => $setpoint,
"%POWERUSAGE" => $powerUsage,
"%POWERUSAGESCALE" => $powerUsageScale,
"%POWERUSAGELEVEL" => $powerUsageLevel,
"%STATE" => ReadingsVal($name, "state", "off")
);
$actionCmd = EvalSpecials($actionCmd, %specials);
my $ret = AnalyzeCommandChain(undef, $actionCmd);
Log3 $name, 2, "$name: $ret" if($ret);
}
return;
}
#
sub EnOcean_demandResponseTimeout($)
{
my ($functionHash) = @_;
my $function = $functionHash->{function};
my $hash = $functionHash->{hash};
my $name = $hash->{NAME};
my $actionCmd = AttrVal($name, "demandRespAction", undef);
my $data;
my $timeoutLevel = AttrVal($name, "demandRespTimeoutLevel", "max");
RemoveInternalTimer($functionHash);
CommandDeleteReading(undef, "$name timeout");
my $drLevel = 15;
my $powerUsage = 100;
my $powerUsageLevel = "max";
my $powerUsageScale = "max";
my $setpoint = 255;
my $timeout = 0;
if ($timeoutLevel eq "last" && defined($hash->{helper}{drLevel})) {
# restore old values
$drLevel = $hash->{helper}{drLevel};
$powerUsage = $hash->{helper}{powerUsage};
$powerUsageScale = $hash->{helper}{powerUsageLevel};
$powerUsageLevel = $hash->{helper}{powerUsageScale};
$setpoint = $hash->{helper}{setpoint};
}
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "level", $drLevel);
readingsBulkUpdate($hash, "powerUsage", $powerUsage);
readingsBulkUpdate($hash, "powerUsageLevel", $powerUsageLevel);
readingsBulkUpdate($hash, "powerUsageScale", $powerUsageScale);
readingsBulkUpdate($hash, "setpoint", $setpoint);
if ($drLevel == 15) {
readingsBulkUpdate($hash, "state", "off");
Log3 $name, 3, "EnOcean set $name demand response off";
} else {
readingsBulkUpdate($hash, "state", "on");
Log3 $name, 3, "EnOcean set $name demand response on";
}
readingsEndUpdate($hash, 1);
#my %specials= ("%NAME" => $name,
# "%TYPE" => $hash->{TYPE},
# "%EVENT" => "$drLevel $setpoint $powerUsage $powerUsageScale $powerUsageLevel"
# );
my %specials= ("%NAME" => $name,
"%TYPE" => $hash->{TYPE},
"%LEVEL" => $drLevel,
"%SETPOINT" => $setpoint,
"%POWERUSAGE" => $powerUsage,
"%POWERUSAGESCALE" => $powerUsageScale,
"%POWERUSAGELEVEL" => $powerUsageLevel,
"%STATE" => ReadingsVal($name, "state", "off")
);
$powerUsageLevel = $powerUsageLevel eq "max" ? 1 : 0;
$powerUsageScale = $powerUsageScale eq "rel" ? 0x80 : 0;
my $randomStart = ReadingsVal($name, "randomStart", "no") eq "yes" ? 4 : 0;
my $randomEnd = ReadingsVal($name, "randomEnd", "no") eq "yes" ? 2 : 0;
$data = sprintf "%02X%02X%02X%02X", $setpoint, $powerUsageScale | $powerUsage, $timeout,
$drLevel << 4 | $randomStart | $randomEnd | $powerUsageLevel;
#EnOcean_SndRadio(undef, $hash, $packetType, $rorg, $data, $subDef, $status, $destinationID);
EnOcean_SndRadio(undef, $hash, 1, "A5", $data, AttrVal($name, "subDef", $hash->{DEF}), "00", "FFFFFFFF");
if (defined $actionCmd) {
# action exec
$actionCmd = EvalSpecials($actionCmd, %specials);
my $ret = AnalyzeCommandChain(undef, $actionCmd);
Log3 $name, 2, "$name: $ret" if($ret);
}
return;
}
# Parse Secure Teach-In Telegrams # Parse Secure Teach-In Telegrams
sub EnOcean_sec_parseTeachIn($$) { sub EnOcean_sec_parseTeachIn($$) {
@ -7385,8 +7718,9 @@ EnOcean_Undef($$)
If the <a href="#EnOcean_observeLogic">observeLogic</a> attribute is set to "and", the monitoring is stopped when a telegram If the <a href="#EnOcean_observeLogic">observeLogic</a> attribute is set to "and", the monitoring is stopped when a telegram
was received by all devices (AND logic). Please note that the name of the own device has also to be entered in the was received by all devices (AND logic). Please note that the name of the own device has also to be entered in the
<a href="#EnOcean_observeRefDev">observeRefDev</a> if required.<br> <a href="#EnOcean_observeRefDev">observeRefDev</a> if required.<br>
If the maximum number of retries is reached and still no all acknowledgment telegrams has been received, the command If the maximum number of retries is reached and still no all acknowledgment telegrams has been received, the reading
can be executed, that is stored in the <a href="#EnOcean_observeErrorAction">observeErrorAction</a> attribute. "observeFailedDev" shows the faulty devices and the command can be executed, that is stored in the
<a href="#EnOcean_observeErrorAction">observeErrorAction</a> attribute.
<br><br> <br><br>
</ul> </ul>
@ -8297,7 +8631,7 @@ EnOcean_Undef($$)
Command being executed after an error. If &lt;command&gt; is enclosed in {}, Command being executed after an error. If &lt;command&gt; is enclosed in {},
then it is a perl expression, if it is enclosed in "", then it is a shell command, then it is a perl expression, if it is enclosed in "", then it is a shell command,
else it is a "plain" fhem.pl command (chain). In the &lt;command&gt; you can access the set else it is a "plain" fhem.pl command (chain). In the &lt;command&gt; you can access the set
command. $TYPE, $NAME, $EVENT, $EVTPART0, $EVTPART1, $EVTPART2, etc. contains the space separated command. $TYPE, $NAME, $FAILEDDEV, $EVENT, $EVTPART0, $EVTPART1, $EVTPART2, etc. contains the space separated
set parts. The <a href="#eventMap">eventMap</a> replacements are taken into account. This data set parts. The <a href="#eventMap">eventMap</a> replacements are taken into account. This data
is available as a local variable in perl, as environment variable for shell is available as a local variable in perl, as environment variable for shell
scripts, and will be textually replaced for Fhem commands. scripts, and will be textually replaced for Fhem commands.
@ -8356,6 +8690,11 @@ EnOcean_Undef($$)
The status "released" will be shown in the reading state if the The status "released" will be shown in the reading state if the
attribute is set to "pushbutton". attribute is set to "pushbutton".
</li> </li>
<li><a name="EnOcean_setCmdTrigger">setCmdTrigger</a> man|refDev, [setCmdTrigger] = man is default.<br>
Operation mode to send set commands<br>
If the attribute is set to "refDev", a device-specific set command is sent when the reference device is updated.
For the subType "roomsensorcontrol.05" the reference "temperatureRefDev" is supported.
</li>
<li><a href="#showtime">showtime</a></li> <li><a href="#showtime">showtime</a></li>
<li><a name="shutTime">shutTime</a> t/s<br> <li><a name="shutTime">shutTime</a> t/s<br>
subType blindsCtrl.00: [shutTime] = 5 ... 300, 300 is default.<br> subType blindsCtrl.00: [shutTime] = 5 ... 300, 300 is default.<br>