Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ce95150df | ||
|
|
59c63c4f5d | ||
|
|
f6216d23d4 | ||
|
|
6ec7ca22a8 | ||
|
|
b422b35553 | ||
|
|
6b5345e8bb | ||
|
|
1264675b48 | ||
|
|
64de3f28fe | ||
|
|
7b2248799c | ||
|
|
edd01ab85d | ||
|
|
fb5b1eece5 | ||
|
|
906ef34d77 | ||
|
|
20b5a1faa2 | ||
|
|
d7b24fc124 | ||
|
|
6690605865 | ||
|
|
56304e1e32 | ||
|
|
8aefaa4fbf | ||
|
|
5064c6ccd9 | ||
|
|
c3a2c11402 | ||
|
|
3d185a8eb0 | ||
|
|
aca7655c96 | ||
|
|
55a54847c1 | ||
|
|
f6c3222f62 | ||
|
|
98cf85c6eb | ||
|
|
4331f0808d | ||
|
|
f3eeb3feba | ||
|
|
e3d5ab4337 | ||
|
|
5608b10481 | ||
|
|
d1bf6bf66f |
6
CHANGED
6
CHANGED
@@ -5,6 +5,12 @@
|
|||||||
- feature: SVG: filled area support, some ls/lw fixes
|
- feature: SVG: filled area support, some ls/lw fixes
|
||||||
- feature: WOL (wake on lan) module added (by Matthias)
|
- feature: WOL (wake on lan) module added (by Matthias)
|
||||||
- feature: additional groups from /etc/groups are applied (Christopher)
|
- feature: additional groups from /etc/groups are applied (Christopher)
|
||||||
|
- feature: updatefhem backup is using tar+gzip now
|
||||||
|
- feature: EIB: introduce Get, interpret received values upon defined model
|
||||||
|
(by datapoint types) (Maz)
|
||||||
|
- feature: NetIO230B module by Andy
|
||||||
|
- feature: Retaining configfile comments (not within a define statement)
|
||||||
|
- feature: EnOcean PM101 by Ignaz
|
||||||
|
|
||||||
- 2011-12-31 (5.2)
|
- 2011-12-31 (5.2)
|
||||||
- bugfix: applying smallscreen attributes to firefox/opera
|
- bugfix: applying smallscreen attributes to firefox/opera
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ TCM_Initialize($)
|
|||||||
|
|
||||||
# Normal devices
|
# Normal devices
|
||||||
$hash->{DefFn} = "TCM_Define";
|
$hash->{DefFn} = "TCM_Define";
|
||||||
|
$hash->{UndefFn} = "TCM_Undef";
|
||||||
$hash->{GetFn} = "TCM_Get";
|
$hash->{GetFn} = "TCM_Get";
|
||||||
$hash->{SetFn} = "TCM_Set";
|
$hash->{SetFn} = "TCM_Set";
|
||||||
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 loglevel:0,1,2,3,4,5,6";
|
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 loglevel:0,1,2,3,4,5,6";
|
||||||
@@ -82,9 +83,14 @@ TCM_Define($$)
|
|||||||
my $ret = DevIo_OpenDev($hash, 0, undef);
|
my $ret = DevIo_OpenDev($hash, 0, undef);
|
||||||
|
|
||||||
if($hash->{STATE} eq "opened") {
|
if($hash->{STATE} eq "opened") {
|
||||||
my $answer=TCM_Get($hash, ($name, "baseid") );
|
# Read Base-Id of Enocean-Module
|
||||||
my @fields=split(/[=,]/, $answer);
|
my $cnt=0;
|
||||||
$hash->{BASEID}=$fields[1];
|
do { # this does not always work, so we try several times
|
||||||
|
my $answer=TCM_Get($hash, ($name, "baseid") );
|
||||||
|
my @fields=split(/[=,]/, $answer);
|
||||||
|
$hash->{BASEID}=$fields[1];
|
||||||
|
$cnt++;
|
||||||
|
} while ($cnt<3 and $hash->{BASEID} eq "");
|
||||||
}
|
}
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
@@ -616,7 +622,7 @@ TCM_ReadAnswer($$)
|
|||||||
|
|
||||||
if(defined($buf)) {
|
if(defined($buf)) {
|
||||||
$data .= uc(unpack('H*', $buf));
|
$data .= uc(unpack('H*', $buf));
|
||||||
Log 5, "TCM/RAW (ReadAnswer): $data";
|
Log $ll5, "TCM/RAW (ReadAnswer): $data";
|
||||||
|
|
||||||
if($hash->{MODEL} eq "120") {
|
if($hash->{MODEL} eq "120") {
|
||||||
if(length($data) >= 28) {
|
if(length($data) >= 28) {
|
||||||
@@ -651,7 +657,26 @@ TCM_ReadAnswer($$)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
TCM_Undef($$)
|
||||||
|
{
|
||||||
|
my ($hash, $arg) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
foreach my $d (sort keys %defs) {
|
||||||
|
if(defined($defs{$d}) &&
|
||||||
|
defined($defs{$d}{IODev}) &&
|
||||||
|
$defs{$d}{IODev} == $hash)
|
||||||
|
{
|
||||||
|
my $lev = ($reread_active ? 4 : 2);
|
||||||
|
Log GetLogLevel($name,$lev), "deleting port for $d";
|
||||||
|
delete $defs{$d}{IODev};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DevIo_CloseDev($hash);
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ TUL_Get($@)
|
|||||||
my $rsp;
|
my $rsp;
|
||||||
my $name = $a[0];
|
my $name = $a[0];
|
||||||
|
|
||||||
return "No $a[1] for dummies" if(IsDummy($name));
|
#return "No $a[1] for dummies" if(IsDummy($name));
|
||||||
|
|
||||||
TUL_SimpleWrite($hash, "B".$gets{$a[1]}[0] . $arg);
|
TUL_SimpleWrite($hash, "B".$gets{$a[1]}[0] . $arg);
|
||||||
$rsp = TUL_SimpleRead($hash);
|
$rsp = TUL_SimpleRead($hash);
|
||||||
|
|||||||
@@ -194,11 +194,16 @@ CUL_FHTTK_Parse($$)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $prevState = $defs{$self}{PREV}{STATE};
|
if (! defined($defs{$self}{READINGS}{"Previous"})) {
|
||||||
if ($prevState != $state) {
|
$defs{$self}{READINGS}{"Previous"}{VAL} = "";
|
||||||
|
$defs{$self}{READINGS}{"Previous"}{TIME} = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined($defs{$self}{PREV}{STATE}) && $defs{$self}{PREV}{STATE} != $state) {
|
||||||
|
my $prevState = $defs{$self}{PREV}{STATE};
|
||||||
my ($windowReading,$windowState) = split(/:/, $fhttfk_codes{$prevState});
|
my ($windowReading,$windowState) = split(/:/, $fhttfk_codes{$prevState});
|
||||||
$defs{$self}{READINGS}{"PreviousWindow"}{VAL} = $windowState;
|
$defs{$self}{READINGS}{"Previous"}{VAL} = $windowState if defined($windowState) && $windowState ne "";
|
||||||
$defs{$self}{READINGS}{"PreviousWindow"}{TIME} = $def->{PREVTIMESTAMP};
|
$defs{$self}{READINGS}{"Previous"}{TIME} = TimeNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
$def->{PREVTIMESTAMP} = defined($defs{$self}{PREV}{TIMESTAMP})?$defs{$self}{PREV}{TIMESTAMP}:time();
|
$def->{PREVTIMESTAMP} = defined($defs{$self}{PREV}{TIMESTAMP})?$defs{$self}{PREV}{TIMESTAMP}:time();
|
||||||
|
|||||||
@@ -367,9 +367,9 @@ CUL_HM_Parse($$)
|
|||||||
my $msg;
|
my $msg;
|
||||||
if($plist == 5) {
|
if($plist == 5) {
|
||||||
if($o1 eq "05") {
|
if($o1 eq "05") {
|
||||||
$msg = sprintf("windowopen-temp-%d: %.1f (sensor:%s)",
|
$msg = sprintf("windowopen-temp-%d: %.1f (sensor:%s)",
|
||||||
$tchan, $v1/2, $tdev);
|
$tchan, $v1/2, $tdev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push @event, $msg if $msg;
|
push @event, $msg if $msg;
|
||||||
}
|
}
|
||||||
@@ -396,7 +396,7 @@ CUL_HM_Parse($$)
|
|||||||
my $dayidx = int($idx/48);
|
my $dayidx = int($idx/48);
|
||||||
if($idx % 4 == 0 && $dayidx < $maxdays) {
|
if($idx % 4 == 0 && $dayidx < $maxdays) {
|
||||||
$idx -= 48*$dayidx;
|
$idx -= 48*$dayidx;
|
||||||
$idx /= 2;
|
$idx /= 2;
|
||||||
my $ptr = $shash->{TEMPLIST}{$days[$dayidx+$dayoff]};
|
my $ptr = $shash->{TEMPLIST}{$days[$dayidx+$dayoff]};
|
||||||
$ptr->{$idx}{HOUR} = int($v1/6);
|
$ptr->{$idx}{HOUR} = int($v1/6);
|
||||||
$ptr->{$idx}{MINUTE} = ($v1 - int($v1/6)*6)*10;
|
$ptr->{$idx}{MINUTE} = ($v1 - int($v1/6)*6)*10;
|
||||||
@@ -408,25 +408,60 @@ CUL_HM_Parse($$)
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach my $wd (@days) {
|
foreach my $wd (@days) {
|
||||||
my $twentyfour = 0;
|
my $twentyfour = 0;
|
||||||
my $msg = sprintf("tempList%s:", $wd);
|
my $msg = sprintf("tempList%s:", $wd);
|
||||||
foreach(my $idx=0; $idx<24; $idx+=1) {
|
foreach(my $idx=0; $idx<24; $idx+=1) {
|
||||||
my $ptr = $shash->{TEMPLIST}{$wd}{$idx};
|
my $ptr = $shash->{TEMPLIST}{$wd}{$idx};
|
||||||
if(defined ($ptr->{TEMP}) && $ptr->{TEMP} ne "") {
|
if(defined ($ptr->{TEMP}) && $ptr->{TEMP} ne "") {
|
||||||
if($twentyfour == 0) {
|
if($twentyfour == 0) {
|
||||||
$msg .= sprintf(" %02d:%02d %.1f",
|
$msg .= sprintf(" %02d:%02d %.1f",
|
||||||
$ptr->{HOUR}, $ptr->{MINUTE}, $ptr->{TEMP});
|
$ptr->{HOUR}, $ptr->{MINUTE}, $ptr->{TEMP});
|
||||||
} else {
|
} else {
|
||||||
$ptr->{HOUR} = $ptr->{MINUTE} = $ptr->{TEMP} = "";
|
$ptr->{HOUR} = $ptr->{MINUTE} = $ptr->{TEMP} = "";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(defined ($ptr->{HOUR}) && 0+$ptr->{HOUR} == 24) {
|
if(defined ($ptr->{HOUR}) && 0+$ptr->{HOUR} == 24) {
|
||||||
$twentyfour = 1; # next value uninteresting, only first counts.
|
$twentyfour = 1; # next value uninteresting, only first counts.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push @event, $msg if($msg);
|
push @event, $msg if($msg);
|
||||||
}
|
}
|
||||||
|
# 0402000000000501090000
|
||||||
|
} elsif($cmd eq "A410" && $p =~ m/^0402000000000(.)(..)(..)/) {
|
||||||
|
my ($plist, $o1, $v1) =
|
||||||
|
(hex($1),hex($2),hex($3));
|
||||||
|
my $msg;
|
||||||
|
my @days = ("Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri");
|
||||||
|
if($plist == 5) {
|
||||||
|
$msg = sprintf("param-change: offset=%s, value=%s", $o1, $v1);
|
||||||
|
if($o1 == 1) { ### bitfield containing multiple values...
|
||||||
|
$msg = "displayMode:temperature only" if ($v1 & 1) == 0;
|
||||||
|
$msg = "displayMode:temperature and humidity" if ($v1 & 1) == 1;
|
||||||
|
push @event, $msg if $msg;
|
||||||
|
$msg = "displayTemp:actual" if ($v1 & 2) == 0;
|
||||||
|
$msg = "displayTemp:setpoint" if ($v1 & 2) == 2;
|
||||||
|
push @event, $msg if $msg;
|
||||||
|
$msg = "displayTempUnit:celsius" if ($v1 & 4) == 0;
|
||||||
|
$msg = "displayTempUnit:fahrenheit" if ($v1 & 4) == 4;
|
||||||
|
push @event, $msg if $msg;
|
||||||
|
$msg = "controlMode:manual" if ($v1 & 0x18) == 0;
|
||||||
|
$msg = "controlMode:auto" if ($v1 & 0x18) == 8;
|
||||||
|
$msg = "controlMode:central" if ($v1 & 0x18) == 0x10;
|
||||||
|
$msg = "controlMode:party" if ($v1 & 0x18) == 0x18;
|
||||||
|
push @event, $msg if $msg;
|
||||||
|
my $day = $days[($v1 & 0xE0) - 0xD9 + 1];
|
||||||
|
$msg = sprintf("decalcDay:%s", $day);
|
||||||
|
|
||||||
|
# remember state for subsequent set operations
|
||||||
|
$shash->{helper}{state251} = $v1;
|
||||||
|
} elsif($o1 == 2) {
|
||||||
|
$msg = "tempValveMode:Auto" if ($v1 & 0xC0) == 0;
|
||||||
|
$msg = "tempValveMode:Closed" if ($v1 & 0xC0) == 0x40;
|
||||||
|
$msg = "tempValveMode:Open" if ($v1 & 0xC0) == 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push @event, $msg if $msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($cmd eq "A001" && $p =~ m/^01080900(..)(..)/) {
|
if($cmd eq "A001" && $p =~ m/^01080900(..)(..)/) {
|
||||||
@@ -444,6 +479,10 @@ CUL_HM_Parse($$)
|
|||||||
push @event, "desired-temp:" .hex($1)/2;
|
push @event, "desired-temp:" .hex($1)/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($cmd eq "8002" && $p =~ m/^0102(..)(....)/) { # Ack for fhem-command
|
||||||
|
push @event, "desired-temp-ack:" .hex($1)/2;
|
||||||
|
}
|
||||||
|
|
||||||
CUL_HM_SendCmd($shash, "++8002$id${src}00",1,0) # Send Ack
|
CUL_HM_SendCmd($shash, "++8002$id${src}00",1,0) # Send Ack
|
||||||
if($id eq $dst && $cmd ne "8002");
|
if($id eq $dst && $cmd ne "8002");
|
||||||
|
|
||||||
@@ -662,8 +701,9 @@ CUL_HM_Parse($$)
|
|||||||
|
|
||||||
if($p =~ m/^(....)(..)$/) {
|
if($p =~ m/^(....)(..)$/) {
|
||||||
my ($t, $h) = ($1, $2);
|
my ($t, $h) = ($1, $2);
|
||||||
$t = hex($t)/10;
|
$t = hex($t);
|
||||||
$t -= 3276.8 if($t > 1638.4);
|
$t -= 32768 if($t > 16384);
|
||||||
|
$t = sprintf("%0.1f", $t/10);
|
||||||
$h = hex($h);
|
$h = hex($h);
|
||||||
push @event, "state:T: $t H: $h";
|
push @event, "state:T: $t H: $h";
|
||||||
push @event, "temperature:$t";
|
push @event, "temperature:$t";
|
||||||
@@ -716,6 +756,7 @@ CUL_HM_Parse($$)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#push @event, "unknownMsg:$p" if(!@event);
|
#push @event, "unknownMsg:$p" if(!@event);
|
||||||
|
push @event, "unknownMsg:($cmd) $p" if(!@event);
|
||||||
|
|
||||||
my @changed;
|
my @changed;
|
||||||
for(my $i = 0; $i < int(@event); $i++) {
|
for(my $i = 0; $i < int(@event); $i++) {
|
||||||
@@ -759,6 +800,23 @@ CUL_HM_Parse($$)
|
|||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
###################################
|
||||||
|
sub
|
||||||
|
CUL_HM_TC_missing($)
|
||||||
|
{
|
||||||
|
#
|
||||||
|
# find out missing configuration parameters
|
||||||
|
#
|
||||||
|
my ($hash) = @_ ;
|
||||||
|
my $missingSettings = "please complete settings for ";
|
||||||
|
$missingSettings .= "displayTemp " unless($hash->{READINGS}{displayTemp}{VAL});
|
||||||
|
$missingSettings .= "displayTempUnit " unless($hash->{READINGS}{displayTempUnit}{VAL});
|
||||||
|
$missingSettings .= "displayMode " unless($hash->{READINGS}{displayMode}{VAL});
|
||||||
|
$missingSettings .= "controlMode " unless($hash->{READINGS}{controlMode}{VAL});
|
||||||
|
$missingSettings .= "decalcDay " unless($hash->{READINGS}{decalcDay}{VAL});
|
||||||
|
return $missingSettings;
|
||||||
|
}
|
||||||
|
|
||||||
my %culHmGlobalSets = (
|
my %culHmGlobalSets = (
|
||||||
raw => "data ...",
|
raw => "data ...",
|
||||||
reset => "",
|
reset => "",
|
||||||
@@ -796,6 +854,11 @@ my %culHmModelSets = (
|
|||||||
"tempListThu"=> "HH:MM temp ...",
|
"tempListThu"=> "HH:MM temp ...",
|
||||||
"tempListWed"=> "HH:MM temp ...",
|
"tempListWed"=> "HH:MM temp ...",
|
||||||
"tempListFri"=> "HH:MM temp ...",
|
"tempListFri"=> "HH:MM temp ...",
|
||||||
|
"displayMode" => "[temp-only|temp-hum]",
|
||||||
|
"displayTemp" => "[actual|setpoint]",
|
||||||
|
"displayTempUnit" => "[celsius|fahrenheit]",
|
||||||
|
"controlMode" => "[manual|auto|central|party]",
|
||||||
|
"decalcDay" => "day",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -828,6 +891,10 @@ CUL_HM_Set($@)
|
|||||||
|
|
||||||
my $isSender = (AttrVal($name,"hmClass","") eq "sender" || $md eq "HM-CC-TC");
|
my $isSender = (AttrVal($name,"hmClass","") eq "sender" || $md eq "HM-CC-TC");
|
||||||
|
|
||||||
|
# HM-CC-TC control mode bits for day encoding
|
||||||
|
my %tc_day2bits = ( "Sat"=>"0", "Sun"=>"0x20", "Mon"=>"0x40",
|
||||||
|
"Tue"=>"0x60", "Wed"=>"0x80", "Thu"=>"0xA0",
|
||||||
|
"Fri"=>"0xC0");
|
||||||
|
|
||||||
if(!defined($h) && defined($culHmSubTypeSets{$st}{pct}) && $cmd =~ m/^\d+/) {
|
if(!defined($h) && defined($culHmSubTypeSets{$st}{pct}) && $cmd =~ m/^\d+/) {
|
||||||
$cmd = "pct";
|
$cmd = "pct";
|
||||||
@@ -938,6 +1005,198 @@ CUL_HM_Set($@)
|
|||||||
|
|
||||||
CUL_HM_pushConfig($hash, $id, $dst, $bn, 1, $l1);
|
CUL_HM_pushConfig($hash, $id, $dst, $bn, 1, $l1);
|
||||||
|
|
||||||
|
} elsif($cmd =~ m/^displayMode$/) { ###############################
|
||||||
|
my $tcnf;
|
||||||
|
if($hash->{helper}{state251}) {
|
||||||
|
$tcnf = $hash->{helper}{state251};
|
||||||
|
if($a[2] eq "temp-only") {
|
||||||
|
$tcnf &= 0xFE;
|
||||||
|
} else {
|
||||||
|
$tcnf |= 0x1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# look if index 1 subfields are complete, construct state251,
|
||||||
|
# if incomplete, issue errormessage, set reading and wait for
|
||||||
|
# completion of state251
|
||||||
|
if($hash->{READINGS}{displayTemp}{VAL} &&
|
||||||
|
$hash->{READINGS}{displayTempUnit}{VAL} &&
|
||||||
|
$hash->{READINGS}{controlMode}{VAL} &&
|
||||||
|
$hash->{READINGS}{decalcDay}{VAL}) {
|
||||||
|
|
||||||
|
$tcnf = 0;
|
||||||
|
$tcnf |= 1 if($a[2] ne "temp-only"); # the parameter actually to be changed
|
||||||
|
$tcnf |= 2 if($hash->{READINGS}{displayTemp}{VAL} eq "setpoint");
|
||||||
|
$tcnf |= 4 if($hash->{READINGS}{displayTempUnit}{VAL} eq "fahrenheit");
|
||||||
|
$tcnf |= 8 if($hash->{READINGS}{controlMode}{VAL} eq "auto");
|
||||||
|
$tcnf |= 0x10 if($hash->{READINGS}{controlMode}{VAL} eq "central");
|
||||||
|
$tcnf |= 0x18 if($hash->{READINGS}{controlMode}{VAL} eq "party");
|
||||||
|
my $dbit = $tc_day2bits{$hash->{READINGS}{decalcDay}{VAL}};
|
||||||
|
$tcnf |= $dbit;
|
||||||
|
} else {
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return CUL_HM_TC_missing($hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CUL_HM_pushConfig($hash, $id, $dst, 2, 5, "01$tcnf");
|
||||||
|
$hash->{helper}{state251} = $tcnf;
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} elsif($cmd =~ m/^displayTemp$/) { ###############################
|
||||||
|
my $tcnf;
|
||||||
|
if($hash->{helper}{state251}) {
|
||||||
|
$tcnf = $hash->{helper}{state251};
|
||||||
|
if($a[2] eq "setpoint") {
|
||||||
|
$tcnf &= 0xFD;
|
||||||
|
} else {
|
||||||
|
$tcnf |= 0x2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# look if index 1 subfields are complete, construct state251,
|
||||||
|
# if incomplete, issue errormessage, set reading and wait for
|
||||||
|
# completion of state251
|
||||||
|
if($hash->{READINGS}{displayMode}{VAL} &&
|
||||||
|
$hash->{READINGS}{displayTempUnit}{VAL} &&
|
||||||
|
$hash->{READINGS}{controlMode}{VAL} &&
|
||||||
|
$hash->{READINGS}{decalcDay}{VAL}) {
|
||||||
|
|
||||||
|
$tcnf = 0;
|
||||||
|
$tcnf |= 1 if($hash->{READINGS}{displayMode}{VAL} ne "temp-only");
|
||||||
|
$tcnf |= 2 if($a[2] ne "setpoint"); # the parameter actually to be changed
|
||||||
|
$tcnf |= 4 if($hash->{READINGS}{displayTempUnit}{VAL} eq "fahrenheit");
|
||||||
|
$tcnf |= 8 if($hash->{READINGS}{controlMode}{VAL} eq "auto");
|
||||||
|
$tcnf |= 0x10 if($hash->{READINGS}{controlMode}{VAL} eq "central");
|
||||||
|
$tcnf |= 0x18 if($hash->{READINGS}{controlMode}{VAL} eq "party");
|
||||||
|
my $dbit = $tc_day2bits{$hash->{READINGS}{decalcDay}{VAL}};
|
||||||
|
$tcnf |= $dbit;
|
||||||
|
} else {
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return CUL_HM_TC_missing($hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CUL_HM_pushConfig($hash, $id, $dst, 2, 5, "01$tcnf");
|
||||||
|
$hash->{helper}{state251} = $tcnf;
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} elsif($cmd =~ m/^displayTempUnit$/) { ###############################
|
||||||
|
my $tcnf;
|
||||||
|
if($hash->{helper}{state251}) {
|
||||||
|
$tcnf = $hash->{helper}{state251};
|
||||||
|
if($a[2] eq "celsius") {
|
||||||
|
$tcnf &= 0xFD;
|
||||||
|
} else {
|
||||||
|
$tcnf |= 0xFB;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# look if index 1 subfields are complete, construct state251,
|
||||||
|
# if incomplete, issue errormessage, set reading and wait for
|
||||||
|
# completion of state251
|
||||||
|
if($hash->{READINGS}{displayTemp}{VAL} &&
|
||||||
|
$hash->{READINGS}{displayMode}{VAL} &&
|
||||||
|
$hash->{READINGS}{controlMode}{VAL} &&
|
||||||
|
$hash->{READINGS}{decalcDay}{VAL}) {
|
||||||
|
|
||||||
|
$tcnf = 0;
|
||||||
|
$tcnf |= 1 if($hash->{READINGS}{displayMode}{VAL} ne "temp-only");
|
||||||
|
$tcnf |= 2 if($hash->{READINGS}{displayTemp}{VAL} eq "setpoint");
|
||||||
|
$tcnf |= 4 if($a[2] ne "fahrenheit"); # the parameter actually to be changed
|
||||||
|
$tcnf |= 8 if($hash->{READINGS}{controlMode}{VAL} eq "auto");
|
||||||
|
$tcnf |= 0x10 if($hash->{READINGS}{controlMode}{VAL} eq "central");
|
||||||
|
$tcnf |= 0x18 if($hash->{READINGS}{controlMode}{VAL} eq "party");
|
||||||
|
my $dbit = $tc_day2bits{$hash->{READINGS}{decalcDay}{VAL}};
|
||||||
|
$tcnf |= $dbit;
|
||||||
|
} else {
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return CUL_HM_TC_missing($hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CUL_HM_pushConfig($hash, $id, $dst, 2, 5, "01$tcnf");
|
||||||
|
$hash->{helper}{state251} = $tcnf;
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} elsif($cmd =~ m/^controlMode$/) { ###############################
|
||||||
|
my $tcnf;
|
||||||
|
if($hash->{helper}{state251}) {
|
||||||
|
$tcnf = $hash->{helper}{state251};
|
||||||
|
$tcnf &= 0xE7; # blank out the control mode bits (equals mode manual)
|
||||||
|
$tcnf |= 0x08 if($a[2] eq "auto");
|
||||||
|
$tcnf |= 0x10 if($a[2] eq "central");
|
||||||
|
$tcnf |= 0x18 if($a[2] eq "party");
|
||||||
|
} else {
|
||||||
|
# look if index 1 subfields are complete, construct state251,
|
||||||
|
# if incomplete, issue errormessage, set reading and wait for
|
||||||
|
# completion of state251
|
||||||
|
if($hash->{READINGS}{displayTemp}{VAL} &&
|
||||||
|
$hash->{READINGS}{displayMode}{VAL} &&
|
||||||
|
$hash->{READINGS}{displayTempUnit}{VAL} &&
|
||||||
|
$hash->{READINGS}{decalcDay}{VAL}) {
|
||||||
|
|
||||||
|
$tcnf = 0;
|
||||||
|
$tcnf |= 1 if($hash->{READINGS}{displayMode}{VAL} ne "temp-only");
|
||||||
|
$tcnf |= 2 if($hash->{READINGS}{displayTemp}{VAL} eq "setpoint");
|
||||||
|
$tcnf |= 4 if($hash->{READINGS}{displayTempUnit}{VAL} eq "fahrenheit");
|
||||||
|
$tcnf |= 8 if($a[2] eq "auto"); # the parameter actually to be changed
|
||||||
|
$tcnf |= 0x10 if($a[2] eq "central");
|
||||||
|
$tcnf |= 0x18 if($a[2] eq "party");
|
||||||
|
my $dbit = $tc_day2bits{$hash->{READINGS}{decalcDay}{VAL}};
|
||||||
|
$tcnf |= $dbit;
|
||||||
|
} else {
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return CUL_HM_TC_missing($hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CUL_HM_pushConfig($hash, $id, $dst, 2, 5, "01$tcnf");
|
||||||
|
$hash->{helper}{state251} = $tcnf;
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} elsif($cmd =~ m/^decalcDay$/) { ###############################
|
||||||
|
my $tcnf;
|
||||||
|
my $dbit = $tc_day2bits{$a[2]};
|
||||||
|
|
||||||
|
if($hash->{helper}{state251}) {
|
||||||
|
$tcnf = $hash->{helper}{state251};
|
||||||
|
$tcnf &= 0x1F; # blank out the decalc day bits (equals Sat)
|
||||||
|
$tcnf |= $dbit;
|
||||||
|
} else {
|
||||||
|
# look if index 1 subfields are complete, construct state251,
|
||||||
|
# if incomplete, issue errormessage, set reading and wait for
|
||||||
|
# completion of state251
|
||||||
|
if($hash->{READINGS}{displayTemp}{VAL} &&
|
||||||
|
$hash->{READINGS}{displayMode}{VAL} &&
|
||||||
|
$hash->{READINGS}{displayTempUnit}{VAL} &&
|
||||||
|
$hash->{READINGS}{controlMode}{VAL}) {
|
||||||
|
|
||||||
|
$tcnf = 0;
|
||||||
|
$tcnf |= 1 if($hash->{READINGS}{displayMode}{VAL} ne "temp-only");
|
||||||
|
$tcnf |= 2 if($hash->{READINGS}{displayTemp}{VAL} eq "setpoint");
|
||||||
|
$tcnf |= 4 if($hash->{READINGS}{displayTempUnit}{VAL} eq "fahrenheit");
|
||||||
|
$tcnf |= 8 if($hash->{READINGS}{controlMode}{VAL} eq "auto");
|
||||||
|
$tcnf |= 0x10 if($hash->{READINGS}{controlMode}{VAL} eq "central");
|
||||||
|
$tcnf |= 0x18 if($hash->{READINGS}{controlMode}{VAL} eq "party");
|
||||||
|
$tcnf |= $dbit; # the parameter actually to be changed
|
||||||
|
} else {
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return CUL_HM_TC_missing($hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CUL_HM_pushConfig($hash, $id, $dst, 2, 5, "01$tcnf");
|
||||||
|
$hash->{helper}{state251} = $tcnf;
|
||||||
|
$hash->{READINGS}{$cmd}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{$cmd}{VAL} = sprintf("%s", $a[2]);
|
||||||
|
return;
|
||||||
|
|
||||||
} elsif($cmd =~ m/^desired-temp$/) { ##################
|
} elsif($cmd =~ m/^desired-temp$/) { ##################
|
||||||
my $temp = CUL_HM_convTemp($a[2]);
|
my $temp = CUL_HM_convTemp($a[2]);
|
||||||
return $temp if(length($temp) > 2);
|
return $temp if(length($temp) > 2);
|
||||||
|
|||||||
192
FHEM/10_EIB.pm
192
FHEM/10_EIB.pm
@@ -27,12 +27,47 @@ my $eib_simple ="off on value on-for-timer on-till";
|
|||||||
my %models = (
|
my %models = (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
my %eib_dpttypes = (
|
||||||
|
|
||||||
|
# 1-Octet unsigned value (handled as dpt7)
|
||||||
|
"dpt5" => {"CODE"=>"dpt7", "UNIT"=>""},
|
||||||
|
"percent" => {"CODE"=>"dpt7", "UNIT"=>"%"},
|
||||||
|
|
||||||
|
# 2-Octet unsigned Value (current, length, brightness)
|
||||||
|
"dpt7" => {"CODE"=>"dpt7", "UNIT"=>""},
|
||||||
|
"length-mm" => {"CODE"=>"dpt7", "UNIT"=>"mm"},
|
||||||
|
"current-mA" => {"CODE"=>"dpt7", "UNIT"=>"mA"},
|
||||||
|
"brightness" => {"CODE"=>"dpt7", "UNIT"=>"lux"},
|
||||||
|
"timeperiod-ms" => {"CODE"=>"dpt7", "UNIT"=>"ms"},
|
||||||
|
"timeperiod-min" => {"CODE"=>"dpt7", "UNIT"=>"min"},
|
||||||
|
"timeperiod-h" => {"CODE"=>"dpt7", "UNIT"=>"h"},
|
||||||
|
|
||||||
|
# 2-Octet unsigned Value (Temp / Light)
|
||||||
|
"dpt9" => {"CODE"=>"dpt9", "UNIT"=>""},
|
||||||
|
"tempsensor" => {"CODE"=>"dpt9", "UNIT"=>"<22>C"},
|
||||||
|
"lightsensor" => {"CODE"=>"dpt9", "UNIT"=>"Lux"},
|
||||||
|
|
||||||
|
# Time of Day
|
||||||
|
"dpt10" => {"CODE"=>"dpt10", "UNIT"=>""},
|
||||||
|
"time" => {"CODE"=>"dpt10", "UNIT"=>""},
|
||||||
|
|
||||||
|
# Date
|
||||||
|
"dpt11" => {"CODE"=>"dpt11", "UNIT"=>""},
|
||||||
|
"date" => {"CODE"=>"dpt11", "UNIT"=>""},
|
||||||
|
|
||||||
|
# 4-Octet unsigned value (handled as dpt7)
|
||||||
|
"dpt12" => {"CODE"=>"dpt7", "UNIT"=>""},
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
sub
|
sub
|
||||||
EIB_Initialize($)
|
EIB_Initialize($)
|
||||||
{
|
{
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
$hash->{Match} = "^B.*";
|
$hash->{Match} = "^B.*";
|
||||||
|
$hash->{GetFn} = "EIB_Get";
|
||||||
$hash->{SetFn} = "EIB_Set";
|
$hash->{SetFn} = "EIB_Set";
|
||||||
$hash->{StateFn} = "EIB_SetState";
|
$hash->{StateFn} = "EIB_SetState";
|
||||||
$hash->{DefFn} = "EIB_Define";
|
$hash->{DefFn} = "EIB_Define";
|
||||||
@@ -50,7 +85,7 @@ EIB_Define($$)
|
|||||||
my ($hash, $def) = @_;
|
my ($hash, $def) = @_;
|
||||||
my @a = split("[ \t][ \t]*", $def);
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
|
|
||||||
my $u = "wrong syntax: define <name> EIB <group name>";
|
my $u = "wrong syntax: define <name> EIB <group name> [<read group names>*]";
|
||||||
|
|
||||||
return $u if(int(@a) < 3);
|
return $u if(int(@a) < 3);
|
||||||
return "Define $a[0]: wrong group name format: specify as 0-15/0-15/0-255 or as hex"
|
return "Define $a[0]: wrong group name format: specify as 0-15/0-15/0-255 or as hex"
|
||||||
@@ -65,8 +100,15 @@ EIB_Define($$)
|
|||||||
my $name = $a[0];
|
my $name = $a[0];
|
||||||
|
|
||||||
$hash->{CODE}{$ncode++} = $code;
|
$hash->{CODE}{$ncode++} = $code;
|
||||||
|
# add read group names
|
||||||
|
if(int(@a)>3)
|
||||||
|
{
|
||||||
|
for (my $count = 3; $count < int(@a); $count++)
|
||||||
|
{
|
||||||
|
$hash->{CODE}{$ncode++} = eib_name2hex(lc($a[$count]));;
|
||||||
|
}
|
||||||
|
}
|
||||||
$modules{EIB}{defptr}{$code}{$name} = $hash;
|
$modules{EIB}{defptr}{$code}{$name} = $hash;
|
||||||
|
|
||||||
AssignIoPort($hash);
|
AssignIoPort($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,12 +136,22 @@ sub
|
|||||||
EIB_SetState($$$$)
|
EIB_SetState($$$$)
|
||||||
{
|
{
|
||||||
my ($hash, $tim, $vt, $val) = @_;
|
my ($hash, $tim, $vt, $val) = @_;
|
||||||
|
Log(5,"EIB setState tim: $tim vt: $vt val: $val");
|
||||||
|
|
||||||
$val = $1 if($val =~ m/^(.*) \d+$/);
|
$val = $1 if($val =~ m/^(.*) \d+$/);
|
||||||
return "Undefined value $val" if(!defined($eib_c2b{$val}));
|
return "Undefined value $val" if(!defined($eib_c2b{$val}));
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
###################################
|
||||||
|
sub
|
||||||
|
EIB_Get($@)
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
IOWrite($hash, "B", "r" . $hash->{GROUP});
|
||||||
|
return "Current value for $hash->{NAME} ($hash->{GROUP}) requested.";
|
||||||
|
}
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
sub
|
sub
|
||||||
EIB_Set($@)
|
EIB_Set($@)
|
||||||
@@ -110,6 +162,7 @@ EIB_Set($@)
|
|||||||
|
|
||||||
return "no set value specified" if($na < 2 || $na > 3);
|
return "no set value specified" if($na < 2 || $na > 3);
|
||||||
return "Readonly value $a[1]" if(defined($readonly{$a[1]}));
|
return "Readonly value $a[1]" if(defined($readonly{$a[1]}));
|
||||||
|
return "No $a[1] for dummies" if(IsDummy($hash->{NAME}));
|
||||||
|
|
||||||
my $c = $eib_c2b{$a[1]};
|
my $c = $eib_c2b{$a[1]};
|
||||||
if(!defined($c)) {
|
if(!defined($c)) {
|
||||||
@@ -221,22 +274,149 @@ EIB_Parse($$)
|
|||||||
|
|
||||||
$lh->{CHANGED}[0] = $v;
|
$lh->{CHANGED}[0] = $v;
|
||||||
$lh->{STATE} = $v;
|
$lh->{STATE} = $v;
|
||||||
|
$lh->{RAWSTATE} = $v;
|
||||||
|
$lh->{LASTGROUP} = $dev;
|
||||||
$lh->{READINGS}{state}{TIME} = TimeNow();
|
$lh->{READINGS}{state}{TIME} = TimeNow();
|
||||||
$lh->{READINGS}{state}{VAL} = $v;
|
$lh->{READINGS}{state}{VAL} = $v;
|
||||||
Log GetLogLevel($n,2), "EIB $n $v";
|
Log GetLogLevel($n,2), "EIB $n $v";
|
||||||
|
|
||||||
|
# parse/translate by datapoint type
|
||||||
|
EIB_ParseByDatapointType($lh,$n,$v);
|
||||||
|
|
||||||
push(@list, $n);
|
push(@list, $n);
|
||||||
}
|
}
|
||||||
return @list;
|
return @list;
|
||||||
} else {
|
} else {
|
||||||
my $dev_name = eib_hex2name($dev);
|
|
||||||
Log(3, "EIB Unknown device $dev ($dev_name), Value $val, please define it");
|
# check if the code is within the read groups
|
||||||
return "UNDEFINED EIB_$dev EIB $dev";
|
my $found = 0;
|
||||||
|
foreach my $mod (keys %{$modules{EIB}{defptr}})
|
||||||
|
{
|
||||||
|
my $def = $modules{EIB}{defptr}{"$mod"};
|
||||||
|
if($def) {
|
||||||
|
my @list;
|
||||||
|
foreach my $n (keys %{ $def }) {
|
||||||
|
my $lh = $def->{$n};
|
||||||
|
foreach my $c (keys %{ $lh->{CODE} } )
|
||||||
|
{
|
||||||
|
$c = $lh->{CODE}{$c};
|
||||||
|
if($c eq $dev)
|
||||||
|
{
|
||||||
|
$n = $lh->{NAME}; # It may be renamed
|
||||||
|
|
||||||
|
return "" if(IsIgnored($n)); # Little strange.
|
||||||
|
|
||||||
|
$lh->{CHANGED}[0] = $v;
|
||||||
|
$lh->{STATE} = $v;
|
||||||
|
$lh->{RAWSTATE} = $v;
|
||||||
|
$lh->{LASTGROUP} = $dev;
|
||||||
|
$lh->{READINGS}{state}{TIME} = TimeNow();
|
||||||
|
$lh->{READINGS}{state}{VAL} = $v;
|
||||||
|
Log GetLogLevel($n,2), "EIB $n $v";
|
||||||
|
|
||||||
|
# parse/translate by datapoint type
|
||||||
|
EIB_ParseByDatapointType($lh,$n,$v);
|
||||||
|
|
||||||
|
push(@list, $n);
|
||||||
|
$found = 1;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
return @list if $found>0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($found==0)
|
||||||
|
{
|
||||||
|
my $dev_name = eib_hex2name($dev);
|
||||||
|
Log(3, "EIB Unknown device $dev ($dev_name), Value $val, please define it");
|
||||||
|
return "UNDEFINED EIB_$dev EIB $dev";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
EIB_ParseByDatapointType($$$)
|
||||||
|
{
|
||||||
|
my ($hash, $name, $value) = @_;
|
||||||
|
my $model = $attr{$name}{"model"};
|
||||||
|
|
||||||
|
# nothing to do if no model is given
|
||||||
|
return undef if(!defined($model));
|
||||||
|
|
||||||
|
my $dpt = $eib_dpttypes{"$model"};
|
||||||
|
|
||||||
|
Log(4,"EIB parse $value for $name model: $model dpt: $dpt");
|
||||||
|
return undef if(!defined($dpt));
|
||||||
|
|
||||||
|
my $code = $eib_dpttypes{"$model"}{"CODE"};
|
||||||
|
my $unit = $eib_dpttypes{"$model"}{"UNIT"};
|
||||||
|
my $transval = undef;
|
||||||
|
|
||||||
|
Log(4,"EIB parse $value for $name model: $model dpt: $code unit: $unit");
|
||||||
|
|
||||||
|
if ($code eq "dpt7")
|
||||||
|
{
|
||||||
|
my $fullval = hex($value);
|
||||||
|
$transval = $fullval;
|
||||||
|
|
||||||
|
Log(5,"EIB $code parse $value = $fullval translated: $transval");
|
||||||
|
|
||||||
|
} elsif($code eq "dpt9")
|
||||||
|
{
|
||||||
|
my $fullval = hex($value);
|
||||||
|
my $sign = 1;
|
||||||
|
$sign = -1 if(($fullval & 0x8000)>0);
|
||||||
|
my $exp = ($fullval & 0x7800)>>11;
|
||||||
|
my $mant = ($fullval & 0x07FF);
|
||||||
|
|
||||||
|
$transval = ($sign * $mant * (2**$exp))/100;
|
||||||
|
|
||||||
|
Log(5,"EIB $code parse $value = $fullval sign: $sign mant: $mant exp: $exp translated: $transval");
|
||||||
|
|
||||||
|
|
||||||
|
} elsif ($code eq "dpt10")
|
||||||
|
{
|
||||||
|
# Time
|
||||||
|
my $fullval = hex($value);
|
||||||
|
my $hours = ($fullval & 0x1F0000)>>16;
|
||||||
|
my $mins = ($fullval & 0x3F00)>>8;
|
||||||
|
my $secs = ($fullval & 0x3F);
|
||||||
|
$transval = sprintf("%02d:%02d:%02d",$hours,$mins,$secs);
|
||||||
|
|
||||||
|
Log(5,"EIB $code parse $value = $fullval hours: $hours mins: $mins secs: $secs translated: $transval");
|
||||||
|
|
||||||
|
} elsif ($code eq "dpt11")
|
||||||
|
{
|
||||||
|
# Date
|
||||||
|
my $fullval = hex($value);
|
||||||
|
my $day = ($fullval & 0x1F0000)>>16;
|
||||||
|
my $month = ($fullval & 0x0F00)>>8;
|
||||||
|
my $year = ($fullval & 0x7F);
|
||||||
|
#translate year (21st cent if <90 / else 20th century)
|
||||||
|
$year += 1900 if($year>=90);
|
||||||
|
$year += 2000 if($year<90);
|
||||||
|
$transval = sprintf("%02d.%02d.%04d",$day,$month,$year);
|
||||||
|
|
||||||
|
Log(5,"EIB $code parse $value = $fullval day: $day month: $month year: $year translated: $transval");
|
||||||
|
|
||||||
|
} elsif ($code eq "dptxx") {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# set state to translated value
|
||||||
|
if(defined($transval))
|
||||||
|
{
|
||||||
|
Log(4,"EIB $name translated to $transval");
|
||||||
|
$hash->{STATE} = "$transval $unit";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(4,"EIB $name model $model could not be translated.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
sub
|
sub
|
||||||
eib_hex2name($)
|
eib_hex2name($)
|
||||||
@@ -262,7 +442,7 @@ eib_name2hex($)
|
|||||||
$r = sprintf("%01x%01x%02x",$1,$2,$3);
|
$r = sprintf("%01x%01x%02x",$1,$2,$3);
|
||||||
}
|
}
|
||||||
elsif($v =~ /^([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,3})$/) {
|
elsif($v =~ /^([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,3})$/) {
|
||||||
$r = sprintf("%01x%021%02x",$1,$2,$3);
|
$r = sprintf("%01x%01x%02x",$1,$2,$3);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $r;
|
return $r;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# $Id: 10_EnOcean.pm 1130 2011-12-14 07:57:59Z rudolfkoenig $
|
# $Id$
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
@@ -65,10 +65,11 @@ EnOcean_Initialize($)
|
|||||||
$hash->{DefFn} = "EnOcean_Define";
|
$hash->{DefFn} = "EnOcean_Define";
|
||||||
$hash->{ParseFn} = "EnOcean_Parse";
|
$hash->{ParseFn} = "EnOcean_Parse";
|
||||||
$hash->{SetFn} = "EnOcean_Set";
|
$hash->{SetFn} = "EnOcean_Set";
|
||||||
|
$hash->{AttrFn} = "EnOcean_Attr";
|
||||||
$hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 " .
|
$hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 " .
|
||||||
"showtime:1,0 loglevel:0,1,2,3,4,5,6 model " .
|
"showtime:1,0 loglevel:0,1,2,3,4,5,6 model " .
|
||||||
"subType:switch,contact,sensor,windowHandle,SR04,MD15,".
|
"subType:switch,contact,sensor,windowHandle,SR04,MD15," .
|
||||||
"eltakoDimmer subId actualTemp";
|
"eltakoDimmer,eltakoRoll subId actualTemp, dimTime";
|
||||||
|
|
||||||
for(my $i=0; $i<@ptm200btn;$i++) {
|
for(my $i=0; $i<@ptm200btn;$i++) {
|
||||||
$ptm200btn{$ptm200btn[$i]} = "$i:30";
|
$ptm200btn{$ptm200btn[$i]} = "$i:30";
|
||||||
@@ -77,6 +78,27 @@ EnOcean_Initialize($)
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------
|
||||||
|
|
||||||
|
sub EnOcean_Attr($)
|
||||||
|
{
|
||||||
|
my @a = @_;
|
||||||
|
|
||||||
|
my $name= $a[1];
|
||||||
|
my $ll2 = GetLogLevel($name, 2);
|
||||||
|
|
||||||
|
if($a[2] eq "subType") {
|
||||||
|
Log $ll2, "EO_Attr subtype";
|
||||||
|
|
||||||
|
if($a[3] eq "eltakoDimmer") {
|
||||||
|
Log $ll2, "EO_Attr subtype dimmer";
|
||||||
|
$attr{$name}{eventMap}="B0:on B1:off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
sub
|
sub
|
||||||
EnOcean_Define($$)
|
EnOcean_Define($$)
|
||||||
@@ -142,6 +164,12 @@ EnOcean_Set($@)
|
|||||||
$hash->{READINGS}{$cmd}{VAL} = $arg;
|
$hash->{READINGS}{$cmd}{VAL} = $arg;
|
||||||
|
|
||||||
} elsif($st eq "eltakoDimmer") {
|
} elsif($st eq "eltakoDimmer") {
|
||||||
|
my $sendDimCmd=0;
|
||||||
|
my $time=AttrVal($name, "time", 0);
|
||||||
|
my $onoff=1;
|
||||||
|
my $dimVal=100;
|
||||||
|
$dimVal=$hash->{VALUE} if(defined $hash->{VALUE});
|
||||||
|
|
||||||
if($cmd eq "teach") {
|
if($cmd eq "teach") {
|
||||||
my $idSrc=EnOcean_GetMyDeviceId($hash);
|
my $idSrc=EnOcean_GetMyDeviceId($hash);
|
||||||
my $data=sprintf("A502000000%s00", $idSrc);
|
my $data=sprintf("A502000000%s00", $idSrc);
|
||||||
@@ -149,46 +177,65 @@ EnOcean_Set($@)
|
|||||||
IOWrite($hash, "000A0001", $data); # len:000a optlen:00 pakettype:1(radio)
|
IOWrite($hash, "000A0001", $data); # len:000a optlen:00 pakettype:1(radio)
|
||||||
|
|
||||||
} elsif($cmd eq "dimto") {
|
} elsif($cmd eq "dimto") {
|
||||||
return "Usage: $cmd percent [time 01-FF FF:slowest] [on/off]" if(@a<2);
|
return "Usage: $cmd percent" if(@a<2 or $a[1]>100);
|
||||||
my $time=0;
|
|
||||||
my $onoff=1;
|
|
||||||
# for eltako relative (0-100) (but not compliant to EEP because DB0.2 is 0)
|
# for eltako relative (0-100) (but not compliant to EEP because DB0.2 is 0)
|
||||||
my $dimVal=$a[1];
|
$dimVal=$a[1];
|
||||||
shift(@a);
|
shift(@a);
|
||||||
if(defined($a[1])) { $time=$a[1]; shift(@a); }
|
if(defined($a[1])) { $time=$a[1]; shift(@a); }
|
||||||
if(defined($a[1])) { $onoff=($a[1] eq "off") ? 0 : 1; shift(@a); }
|
if(defined($a[1])) { $onoff=($a[1] eq "off") ? 0 : 1; shift(@a); }
|
||||||
# EEP: A5/38/08 Central Command ->Typ 0x02: Dimming
|
$sendDimCmd=1;
|
||||||
my $idSrc=EnOcean_GetMyDeviceId($hash);
|
|
||||||
#my $data=sprintf("A502%02X%02X%02X%s00", $dimVal, $time, $onoff|0x08, $hash->{DEF});
|
} elsif($cmd eq "dimup") {
|
||||||
my $data=sprintf("A502%02X%02X%02X%s00", $dimVal, $time, $onoff|0x08, $idSrc);
|
return "Usage: $cmd percent" if(@a<2 or $a[1]>100);
|
||||||
IOWrite($hash, "000A0001", $data);
|
$dimVal+=$a[1];
|
||||||
Log $ll2, "$st.$cnd: " . $data;
|
Log $ll2, "$st.$cmd val:" . $hash->{VALUE} . " par:" . $a[1] . " val:" . $dimVal;
|
||||||
|
shift(@a);
|
||||||
|
$sendDimCmd=1;
|
||||||
|
|
||||||
|
} elsif($cmd eq "dimdown") {
|
||||||
|
return "Usage: $cmd percent" if(@a<2 or $a[1]>100);
|
||||||
|
$dimVal-=$a[1];
|
||||||
|
shift(@a);
|
||||||
|
$sendDimCmd=1;
|
||||||
|
|
||||||
|
} elsif($cmd eq "on" or $cmd eq "B0") {
|
||||||
|
$sendDimCmd=1;
|
||||||
|
|
||||||
|
} elsif($cmd eq "off" or $cmd eq "B1") {
|
||||||
|
$onoff=0;
|
||||||
|
$sendDimCmd=1;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return "Unknown argument $cmd, choose one of: teach, dimto"
|
return "Unknown argument $cmd, choose one of: teach, dimto, dimup, dimdown, on ,off";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if($sendDimCmd) {
|
||||||
|
if($dimVal > 100) { $dimVal=100; }
|
||||||
|
if($dimVal <= 0) { $dimVal=0; $onoff=0; }
|
||||||
|
# EEP: A5/38/08 Central Command ->Typ 0x02: Dimming
|
||||||
|
my $idSrc=EnOcean_GetMyDeviceId($hash);
|
||||||
|
my $data=sprintf("A502%02X%02X%02X%s00", $dimVal, $time, $onoff|0x08, $idSrc);
|
||||||
|
IOWrite($hash, "000A0001", $data);
|
||||||
|
Log $ll2, "$st.$cmd: " . $data;
|
||||||
|
}
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
|
} elsif($st eq "eltakoRoll") {
|
||||||
} elsif($st eq "eltakoRollCtrl") {
|
|
||||||
if($cmd eq "teach") {
|
if($cmd eq "teach") {
|
||||||
my $data=sprintf("A5FFF80D80%s00", $hash->{DEF});
|
my $data=sprintf("A5FFF80D80%s00", $hash->{DEF});
|
||||||
Log $ll2, "eltakoRollCtrl.Teach: " . $data;
|
Log $ll2, "eltakoRollCtrl.Teach: " . $data;
|
||||||
IOWrite($hash, "000A0001", $data); # len:000a optlen:00 pakettype:1(radio)
|
IOWrite($hash, "000A0001", $data); # len:000a optlen:00 pakettype:1(radio)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
my %eltakoRollCtrlCommands = ( down=>0x02, up=>0x01, stop=>0x00 );
|
my %eltakoRollCtrlCommands = ( down=>0x02, up=>0x01, stop=>0x00 );
|
||||||
my $usage = "Usage: (" . join("|", sort keys %eltakoRollCtrlCommands) . ") [time 0-255 sek]";
|
my $usage = "Usage: (" . join("|", sort keys %eltakoRollCtrlCommands) . ")";
|
||||||
my $rollcmd= $eltakoRollCtrlCommands{$cmd}
|
my $rollcmd= $eltakoRollCtrlCommands{$cmd};
|
||||||
return $usage if( (!defined($rollcmd)) or (@a<1) );
|
return $usage if(!defined($rollcmd));
|
||||||
my $time=0;
|
my $time=AttrVal($name, "time", 0);
|
||||||
if(defined($a[1])) { $time=$a[1]; } # time
|
|
||||||
shift(@a);
|
|
||||||
# EEP: A5/3F/7F Universal ???
|
# EEP: A5/3F/7F Universal ???
|
||||||
my $data=sprintf("A5%02X%02X%02X%02X%s00", 0, $time, $rollcmd, 0x08, $hash->{DEF});
|
my $idSrc=EnOcean_GetMyDeviceId($hash);
|
||||||
|
my $data=sprintf("A5%02X%02X%02X%02X%s00", 0, $time, $rollcmd, 0x08, $idSrc);
|
||||||
IOWrite($hash, "000A0001", $data);
|
IOWrite($hash, "000A0001", $data);
|
||||||
Log $ll2, "eltakoRollCtrl.$cmd" . $data;
|
Log $ll2, "eltakoRoll.$cmd" . $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
@@ -371,6 +418,17 @@ EnOcean_Parse($$)
|
|||||||
push @event, "3:actuatorStatus:".(($db_2 & 0x01) ? "obstructed" : "ok");
|
push @event, "3:actuatorStatus:".(($db_2 & 0x01) ? "obstructed" : "ok");
|
||||||
push @event, "3:measured-temp:". sprintf "%.1f", ($db_1*40/255);
|
push @event, "3:measured-temp:". sprintf "%.1f", ($db_1*40/255);
|
||||||
EnOcean_MD15Cmd($hash, $name, $db_1);
|
EnOcean_MD15Cmd($hash, $name, $db_1);
|
||||||
|
|
||||||
|
} elsif($st eq "PM101") {
|
||||||
|
####################################
|
||||||
|
# Ratio Presence Sensor Eagle PM101, code by aicgazi
|
||||||
|
####################################
|
||||||
|
my $lux = sprintf "%3d", $db_2;
|
||||||
|
# content of $db_2 is the illuminance where max value 0xFF stands for 1000 lx
|
||||||
|
$lux = sprintf "%04.2f", ( $lux * 1000 / 255 ) ;
|
||||||
|
push @event, "3:brightness:$lux";
|
||||||
|
push @event, "3:channel1:" . ($db_0 & 0x01 ? "off" : "on");
|
||||||
|
push @event, "3:channel2:" . ($db_0 & 0x02 ? "off" : "on");
|
||||||
|
|
||||||
} elsif($st eq "eltakoDimmer") {
|
} elsif($st eq "eltakoDimmer") {
|
||||||
# response command from (Eltako-)Actor ( Central-Command:A5/38/08 )
|
# response command from (Eltako-)Actor ( Central-Command:A5/38/08 )
|
||||||
@@ -415,10 +473,11 @@ EnOcean_Parse($$)
|
|||||||
if($vn eq "state") {
|
if($vn eq "state") {
|
||||||
$hash->{STATE} = $vv;
|
$hash->{STATE} = $vv;
|
||||||
push @changed, $vv;
|
push @changed, $vv;
|
||||||
|
} elsif($vn eq "value") {
|
||||||
|
$hash->{VALUE} = $vv if($vv>0);
|
||||||
|
push @changed, "$vn: $vv";
|
||||||
} else {
|
} else {
|
||||||
push @changed, "$vn: $vv";
|
push @changed, "$vn: $vv";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,6 +541,7 @@ sub EnOcean_GetMyDeviceId($)
|
|||||||
{
|
{
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $myId=0; # default: use Device-ID of EUL
|
my $myId=0; # default: use Device-ID of EUL
|
||||||
|
my $name = $hash->{NAME};
|
||||||
my $baseId=hex($hash->{IODev}{BASEID});
|
my $baseId=hex($hash->{IODev}{BASEID});
|
||||||
my $subId = AttrVal($name, "subId", "");
|
my $subId = AttrVal($name, "subId", "");
|
||||||
if(defined $baseId and defined $subId) {
|
if(defined $baseId and defined $subId) {
|
||||||
|
|||||||
290
FHEM/24_NetIO230B.pm
Normal file
290
FHEM/24_NetIO230B.pm
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
################################################################
|
||||||
|
# fhem-module for NetIO 230B Power Distribution Unit
|
||||||
|
#
|
||||||
|
# http://www.koukaam.se/showproduct.php?article_id=1502
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# There are 2 modes:
|
||||||
|
#
|
||||||
|
# (1) - define the IP, user and password directly in fhem's fhem.cfg (or UI).
|
||||||
|
#
|
||||||
|
# define NetIO1 <IP address> <socket number> [<user> <password>];
|
||||||
|
# e.g. define NetIO1 192.168.178.2 1 admin admin;
|
||||||
|
#
|
||||||
|
# if you omit the user credentials, the module will look for a configuration file,
|
||||||
|
# if no configuration file is found, it tries with 'admin', 'admin'
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# (2) - define your credentials using a config file.
|
||||||
|
#
|
||||||
|
# define NetIO1 <IP address> <socket number> [<path_to_configuration_file>];
|
||||||
|
# define NetIO1 192.168.178.2 1 /var/log/fhem/netio.conf);
|
||||||
|
#
|
||||||
|
# if you omit the configuration parameter, the module will look for a configuration
|
||||||
|
# file at: /var/log/fhem/netio.conf
|
||||||
|
#
|
||||||
|
# NetIO230B Configuration file format:
|
||||||
|
#
|
||||||
|
# %config= (
|
||||||
|
# host => "192.168.xx.xx",
|
||||||
|
# user => "anyusername_without_spaces",
|
||||||
|
# password => "anypassword_without_spaces"
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
################################################################
|
||||||
|
# created 2012 by Andy Fuchs
|
||||||
|
#---------
|
||||||
|
# Changes:
|
||||||
|
#---------
|
||||||
|
# 2012-02-03 0.1 initial realease
|
||||||
|
#
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
package main;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
use LWP::UserAgent;
|
||||||
|
use HTTP::Request;
|
||||||
|
|
||||||
|
use constant PARAM_NAME => 1;
|
||||||
|
use constant PARAM_HOST => 2;
|
||||||
|
use constant PARAM_SOCK => 3;
|
||||||
|
use constant PARAM_USER => 4;
|
||||||
|
use constant PARAM_PASS => 5;
|
||||||
|
use constant PARAM_FILE => 4;
|
||||||
|
|
||||||
|
use constant DEBUG => 1;
|
||||||
|
|
||||||
|
sub
|
||||||
|
NetIO230B_Initialize($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
$hash->{SetFn} = "NetIO230B_Set";
|
||||||
|
$hash->{GetFn} = "NetIO230B_Get";
|
||||||
|
$hash->{DefFn} = "NetIO230B_Define";
|
||||||
|
$hash->{AttrList} = "loglevel:0,1,2,3,4,5,6";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
###################################
|
||||||
|
sub
|
||||||
|
NetIO230B_Set($@)
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
|
||||||
|
return "no set value specified" if(int(@a) != 2);
|
||||||
|
return "Unknown argument $a[1], choose one of on off " if($a[1] eq "?");
|
||||||
|
|
||||||
|
my $state = $a[1]; #initialize state to the passed parameter
|
||||||
|
my $result = "command was not executed - $state is not 'on' or 'off'";
|
||||||
|
if ($state eq "on" || $state eq "off")
|
||||||
|
{
|
||||||
|
$hash->{STATE} = $state;
|
||||||
|
$state = int($state eq "on");
|
||||||
|
#prepare the sockets default parameters; 'u' means: don't touch
|
||||||
|
my @values=("u","u","u","u");
|
||||||
|
my @sockets = @{$hash->{SOCKETS}};
|
||||||
|
|
||||||
|
foreach (@sockets) {
|
||||||
|
$values[$_-1] = $state;
|
||||||
|
$hash->{READINGS}{"socket$_"}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{"socket$_"}{VAL} = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = NetIO230B_Request($hash, "set", join("",@values));
|
||||||
|
}
|
||||||
|
|
||||||
|
Log 3, "NetIO230B set @a => $result";
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
###################################
|
||||||
|
sub
|
||||||
|
NetIO230B_Get($@)
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
my $result = NetIO230B_Request($hash, "get");
|
||||||
|
Log 3, "NetIO230B get @a => $result";
|
||||||
|
|
||||||
|
return $hash->{STATE};
|
||||||
|
}
|
||||||
|
|
||||||
|
###################################
|
||||||
|
sub
|
||||||
|
NetIO230B_Request($@)
|
||||||
|
{
|
||||||
|
my ($hash, $cmd, $list) = @_;
|
||||||
|
my $URL='';
|
||||||
|
my $log='';
|
||||||
|
|
||||||
|
$URL="http://".$hash->{HOST}."/tgi/control.tgi?l=p:". $hash->{USER}.":".$hash->{PASS}."&p=";
|
||||||
|
if($cmd eq "set") {
|
||||||
|
$URL .= "$list";
|
||||||
|
} else {
|
||||||
|
$URL .= "l";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $agent = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1, timeout => 30);
|
||||||
|
my $header = HTTP::Request->new(GET => $URL);
|
||||||
|
my $request = HTTP::Request->new('GET', $URL, $header);
|
||||||
|
my $response = $agent->request($request);
|
||||||
|
|
||||||
|
$log.= "Can't get $URL -- ".$response->status_line
|
||||||
|
unless $response->is_success;
|
||||||
|
|
||||||
|
if($log ne "")
|
||||||
|
{
|
||||||
|
Log 3, "NetIO230B_Request: ".$log;
|
||||||
|
return("");
|
||||||
|
}
|
||||||
|
|
||||||
|
# read decoded content
|
||||||
|
my $buffer = $response->decoded_content;
|
||||||
|
|
||||||
|
# strip html tags
|
||||||
|
$buffer =~ s/<(?:[^>'"]*|(['"]).*?\1)*>//gs;
|
||||||
|
|
||||||
|
# strip leading whitespace
|
||||||
|
$buffer =~ s/^\s+//;
|
||||||
|
|
||||||
|
#strip trailing whitespace
|
||||||
|
$buffer =~ s/\s+$//;
|
||||||
|
|
||||||
|
return $buffer if ($cmd eq "set");
|
||||||
|
|
||||||
|
#+++todo
|
||||||
|
#555 FORBIDDEN
|
||||||
|
|
||||||
|
#split the result into an array
|
||||||
|
my @values=split(/ */,$buffer);
|
||||||
|
|
||||||
|
#save the values to the readings hash
|
||||||
|
my $state = "???";
|
||||||
|
my @sockets = @{$hash->{SOCKETS}};
|
||||||
|
foreach (@sockets) {
|
||||||
|
$hash->{READINGS}{"socket$_"}{TIME} = TimeNow();
|
||||||
|
$hash->{READINGS}{"socket$_"}{VAL} = $values[$_-1];
|
||||||
|
if ($state == "???") { #initialize state
|
||||||
|
$state = $values[$_-1];
|
||||||
|
} else {
|
||||||
|
$state = "???" if ($values[$_-1] != $state); #if states are mixed show ???
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash->{STATE} = $state;
|
||||||
|
|
||||||
|
# debug output
|
||||||
|
#my %k = %{$hash->{READINGS}};
|
||||||
|
#foreach my $r (sort keys %k) {
|
||||||
|
# Log 1, "$r S: $k{$r}{VAL} T: $k{$r}{TIME}";
|
||||||
|
#}
|
||||||
|
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
### _Define routing is called when fhem starts -> 'reloading' of the module does not call the define routine!!
|
||||||
|
###
|
||||||
|
sub
|
||||||
|
NetIO230B_Define($$)
|
||||||
|
{
|
||||||
|
my ($hash, $def) = @_;
|
||||||
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
|
my $paramCount = int(@a);
|
||||||
|
|
||||||
|
Log 3, "Wrong syntax: use 'define <name> NetIO230B <ip-address> [<socket_number> <username> <password>]' or 'define <name> NetIO230B <ip-address> [<socket_number> <configfilename>]'" if(int(@a) < 4); #5 = mit user/pass #4 = mit config
|
||||||
|
|
||||||
|
#provide some default settings
|
||||||
|
$hash->{CONFIGFILEPATH} = "/var/log/fhem/netio.conf"; #default file path is /var/log/fhem/netio.conf
|
||||||
|
$hash->{USER} = "admin";
|
||||||
|
$hash->{PASS} = "admin";
|
||||||
|
@{$hash->{SOCKETS}} = (1,2,3,4); #default to all sockets
|
||||||
|
|
||||||
|
#mandatory parameter: 'HOST'
|
||||||
|
$hash->{HOST} = $a[PARAM_HOST]; #can be overridden, if using a config file
|
||||||
|
|
||||||
|
#mandatory parameter: 'SOCKET #'; negative numbers are ignored
|
||||||
|
my $buf = $a[PARAM_SOCK];
|
||||||
|
if (($buf =~ m/^\d+$/) && ($buf >=0)) { #make sure input value is a positive number
|
||||||
|
|
||||||
|
if ($buf == 0) #input socket '0' is used as 'all'
|
||||||
|
{
|
||||||
|
@{$hash->{SOCKETS}} = (1,2,3,4); #use this number as 'array of socket-numbers' to operate on
|
||||||
|
|
||||||
|
} elsif ($buf <= 4) #input socket is a single number <=4
|
||||||
|
{
|
||||||
|
@{$hash->{SOCKETS}} = ($buf); #use this number as 'array of socket-numbers' to operate on
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
@{$hash->{SOCKETS}} = split("",$buf); #convert the input values to an array of sockets to operate on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#optional parameter: 'CONFIGFILE_NAME_or_PATH'
|
||||||
|
if ($paramCount == 5) #seems a config file is passed
|
||||||
|
{
|
||||||
|
$hash->{CONFIGFILEPATH} = $a[PARAM_FILE] if defined($a[PARAM_FILE]);;
|
||||||
|
}
|
||||||
|
|
||||||
|
#optional parameters: 'USER and PASS'
|
||||||
|
if ($paramCount != 6)
|
||||||
|
{
|
||||||
|
my %config = NetIO230B_GetConfiguration($hash);
|
||||||
|
if (%config) {
|
||||||
|
$hash->{HOST} = $config{host} if (defined($config{host}));
|
||||||
|
$hash->{USER} = $config{user} if (defined($config{user}));
|
||||||
|
$hash->{PASS} = $config{password} if (defined($config{password}));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Log 3, "NetIO230B: Configuration could not be read. Trying default values...\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
#in any other case
|
||||||
|
$hash->{USER} = $a[PARAM_USER] if defined($a[PARAM_USER]);
|
||||||
|
$hash->{PASS} = $a[PARAM_PASS] if defined($a[PARAM_PASS]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log 3, "NetIO230B: device opened at host: $hash->{HOST} => @a\n";
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
##########################################
|
||||||
|
#
|
||||||
|
# NetIO230B Configuration-Format:
|
||||||
|
#
|
||||||
|
# %config= (
|
||||||
|
# host => "192.168.xx.xx",
|
||||||
|
# user => "anyusername_without_spaces",
|
||||||
|
# password => "anypassword_without_spaces"
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
#
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
### _GetConfiguration reads a plain text file containing arbitrary information
|
||||||
|
sub
|
||||||
|
NetIO230B_GetConfiguration($)
|
||||||
|
{
|
||||||
|
my ($hash)= @_;
|
||||||
|
my $configfilename = $hash->{CONFIGFILEPATH};
|
||||||
|
|
||||||
|
if(!open(CONFIGFILE, $configfilename))
|
||||||
|
{
|
||||||
|
Log 3, "NetIO230B: Cannot open settings file '$configfilename'.";
|
||||||
|
return ();
|
||||||
|
}
|
||||||
|
my @configfile=<CONFIGFILE>;
|
||||||
|
close(CONFIGFILE);
|
||||||
|
|
||||||
|
my %config;
|
||||||
|
eval join("", @configfile);
|
||||||
|
|
||||||
|
return %config;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -119,6 +119,10 @@ watchdog_Trigger($)
|
|||||||
Log(3, "Watchdog $ntfy->{NAME} triggered");
|
Log(3, "Watchdog $ntfy->{NAME} triggered");
|
||||||
my $exec = SemicolonEscape($ntfy->{CMD});;
|
my $exec = SemicolonEscape($ntfy->{CMD});;
|
||||||
$ntfy->{STATE} = "triggered";
|
$ntfy->{STATE} = "triggered";
|
||||||
|
|
||||||
|
$ntfy->{READINGS}{Triggered}{TIME} = TimeNow();
|
||||||
|
$ntfy->{READINGS}{Triggered}{VAL} = $ntfy->{STATE};
|
||||||
|
|
||||||
my $ret = AnalyzeCommandChain(undef, $exec);
|
my $ret = AnalyzeCommandChain(undef, $exec);
|
||||||
Log 3, $ret if($ret);
|
Log 3, $ret if($ret);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -292,10 +292,10 @@ my @usbtable = (
|
|||||||
define => "CUL_PARAM CUL DEVICE\@9600 1PARAM34", },
|
define => "CUL_PARAM CUL DEVICE\@9600 1PARAM34", },
|
||||||
|
|
||||||
{ NAME => "TCM310",
|
{ NAME => "TCM310",
|
||||||
matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)", "ttyUSB(.*)"],
|
matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)", "ttyUSB(.*)", "ttyACM(.*)"],
|
||||||
DeviceName=> "DEVICE\@57600",
|
DeviceName=> "DEVICE\@57600",
|
||||||
request => pack("H*", "5500010005700838"), # get idbase
|
request => pack("H*", "5500010005700838"), # get idbase
|
||||||
response => "^\x00\xFF....",
|
response => "^\x55\x00\x05\x01",
|
||||||
define => "TCM310_PARAM TCM 310 DEVICE\@57600", },
|
define => "TCM310_PARAM TCM 310 DEVICE\@57600", },
|
||||||
|
|
||||||
{ NAME => "TCM120",
|
{ NAME => "TCM120",
|
||||||
@@ -336,19 +336,21 @@ CommandUsb($$)
|
|||||||
if($^O eq "linux") {
|
if($^O eq "linux") {
|
||||||
# One device at a time to avoid endless loop
|
# One device at a time to avoid endless loop
|
||||||
my $lsusb = `lsusb`;
|
my $lsusb = `lsusb`;
|
||||||
my $culType;
|
if($lsusb) {
|
||||||
$culType = "CUL_V4" if($lsusb =~ m/VID=03eb.PID=2ff0/s); # FritzBox
|
my $culType;
|
||||||
$culType = "CUL_V3" if($lsusb =~ m/VID=03eb.PID=2ff4/s); # FritzBox
|
$culType = "CUL_V4" if($lsusb =~ m/VID=03eb.PID=2ff0/s); # FritzBox
|
||||||
$culType = "CUL_V2" if($lsusb =~ m/VID=03eb.PID=2ffa/s); # FritzBox
|
$culType = "CUL_V3" if($lsusb =~ m/VID=03eb.PID=2ff4/s); # FritzBox
|
||||||
$culType = "CUL_V4" if($lsusb =~ m/03eb:2ff0/);
|
$culType = "CUL_V2" if($lsusb =~ m/VID=03eb.PID=2ffa/s); # FritzBox
|
||||||
$culType = "CUL_V3" if($lsusb =~ m/03eb:2ff4/);
|
$culType = "CUL_V4" if($lsusb =~ m/03eb:2ff0/);
|
||||||
$culType = "CUL_V2" if($lsusb =~ m/03eb:2ffa/);
|
$culType = "CUL_V3" if($lsusb =~ m/03eb:2ff4/);
|
||||||
if($culType) {
|
$culType = "CUL_V2" if($lsusb =~ m/03eb:2ffa/);
|
||||||
$msg = "$culType: flash it with: CULflash none $culType";
|
if($culType) {
|
||||||
Log 4, $msg; $ret .= $msg . "\n";
|
$msg = "$culType: flash it with: CULflash none $culType";
|
||||||
if(!$scan) {
|
Log 4, $msg; $ret .= $msg . "\n";
|
||||||
CommandCULflash(undef, "none $culType");
|
if(!$scan) {
|
||||||
sleep(4); # Leave time for linux to load th drivers
|
CommandCULflash(undef, "none $culType");
|
||||||
|
sleep(4); # Leave time for linux to load th drivers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -362,7 +364,7 @@ CommandUsb($$)
|
|||||||
my $PARAM = $1;
|
my $PARAM = $1;
|
||||||
$PARAM =~ s/[^A-Za-z0-9]//g;
|
$PARAM =~ s/[^A-Za-z0-9]//g;
|
||||||
my $name = $thash->{NAME};
|
my $name = $thash->{NAME};
|
||||||
$msg = "$dev: checking if it is a $name";
|
$msg = "### $dev: checking if it is a $name";
|
||||||
Log 4, $msg; $ret .= $msg . "\n";
|
Log 4, $msg; $ret .= $msg . "\n";
|
||||||
|
|
||||||
# Check if it already used
|
# Check if it already used
|
||||||
@@ -370,7 +372,7 @@ CommandUsb($$)
|
|||||||
if($defs{$d}{DeviceName} &&
|
if($defs{$d}{DeviceName} &&
|
||||||
$defs{$d}{DeviceName} =~ m/$dev/ &&
|
$defs{$d}{DeviceName} =~ m/$dev/ &&
|
||||||
$defs{$d}{FD}) {
|
$defs{$d}{FD}) {
|
||||||
$msg = "$dev: already used by the $d fhem device";
|
$msg = "already used by the $d fhem device";
|
||||||
Log 4, $msg; $ret .= $msg . "\n";
|
Log 4, $msg; $ret .= $msg . "\n";
|
||||||
goto NEXTDEVICE;
|
goto NEXTDEVICE;
|
||||||
}
|
}
|
||||||
@@ -382,22 +384,21 @@ CommandUsb($$)
|
|||||||
my $hash = { NAME=>$name, DeviceName=>$dname };
|
my $hash = { NAME=>$name, DeviceName=>$dname };
|
||||||
DevIo_OpenDev($hash, 0, 0);
|
DevIo_OpenDev($hash, 0, 0);
|
||||||
if(!defined($hash->{USBDev})) {
|
if(!defined($hash->{USBDev})) {
|
||||||
$msg = "$dev: Cannot open the device, check the log";
|
DevIo_CloseDev($hash); # remove the ReadyFn loop
|
||||||
|
$msg = "cannot open the device";
|
||||||
Log 4, $msg; $ret .= $msg . "\n";
|
Log 4, $msg; $ret .= $msg . "\n";
|
||||||
goto NEXTDEVICE;
|
goto NEXTDEVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Clear the USB buffer
|
# Clear the USB buffer
|
||||||
if($thash->{flush}) {
|
DevIo_SimpleWrite($hash, $thash->{flush}, 0) if($thash->{flush});
|
||||||
DevIo_SimpleWrite($hash, $thash->{flush}, 0);
|
DevIo_TimeoutRead($hash, 0.1);
|
||||||
DevIo_TimeoutRead($hash, 0.1);
|
|
||||||
}
|
|
||||||
DevIo_SimpleWrite($hash, $thash->{request}, 0);
|
DevIo_SimpleWrite($hash, $thash->{request}, 0);
|
||||||
my $answer = DevIo_TimeoutRead($hash, 0.1);
|
my $answer = DevIo_TimeoutRead($hash, 0.1);
|
||||||
DevIo_CloseDev($hash);
|
DevIo_CloseDev($hash);
|
||||||
|
|
||||||
if($answer !~ m/$thash->{response}/) {
|
if($answer !~ m/$thash->{response}/) {
|
||||||
$msg = "$dev: got wrong answer for a $name";
|
$msg = "got wrong answer for a $name";
|
||||||
Log 4, $msg; $ret .= $msg . "\n";
|
Log 4, $msg; $ret .= $msg . "\n";
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
@@ -405,7 +406,7 @@ CommandUsb($$)
|
|||||||
my $define = $thash->{define};
|
my $define = $thash->{define};
|
||||||
$define =~ s/PARAM/$PARAM/g;
|
$define =~ s/PARAM/$PARAM/g;
|
||||||
$define =~ s,DEVICE,$dir/$dev,g;
|
$define =~ s,DEVICE,$dir/$dev,g;
|
||||||
$msg = "$dev: create as a fhem device with: define $define";
|
$msg = "create as a fhem device with: define $define";
|
||||||
Log 4, $msg; $ret .= $msg . "\n";
|
Log 4, $msg; $ret .= $msg . "\n";
|
||||||
|
|
||||||
if(!$scan) {
|
if(!$scan) {
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ updatefhem_Initialize($$)
|
|||||||
$cmds{CULflash} = \%chash;
|
$cmds{CULflash} = \%chash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub
|
sub
|
||||||
CommandUpdatefhem($$)
|
CommandUpdatefhem($$)
|
||||||
@@ -37,42 +36,18 @@ CommandUpdatefhem($$)
|
|||||||
my $ret = "";
|
my $ret = "";
|
||||||
my $moddir = (-d "FHEM.X" ? "FHEM.X" : "$attr{global}{modpath}/FHEM");
|
my $moddir = (-d "FHEM.X" ? "FHEM.X" : "$attr{global}{modpath}/FHEM");
|
||||||
|
|
||||||
## backup by RueBe
|
## backup by RueBe, simplified by rudi
|
||||||
my @commandchain = split(/ +/,$param);
|
my @args = split(/ +/,$param);
|
||||||
|
|
||||||
# Check if the first parameter is "backup"
|
# Check if the first parameter is "backup"
|
||||||
if($param) {
|
if(@args && uc($args[0]) eq "BACKUP") {
|
||||||
my @commandchain = split(/ +/,$param);
|
my $bdir = AttrVal("global", "backupdir", "$moddir.backup");
|
||||||
if(uc($commandchain[0]) eq "BACKUP") {
|
my $dateTime = TimeNow();
|
||||||
my $backupdir = AttrVal("global", "backupdir", "/tmp/FHEM_Backup");
|
$dateTime =~ s/ /_/g;
|
||||||
# create the backupfolder
|
my $ret = `(mkdir -p $bdir && tar cf - $moddir | gzip > $bdir/FHEM.$dateTime.tgz) 2>&1`;
|
||||||
if(!-d $backupdir) {
|
return $ret if($ret);
|
||||||
if(!mkdir($backupdir)) {
|
shift @args;
|
||||||
return "Can't create backup folder $!";
|
$param = join("", @args);
|
||||||
}
|
|
||||||
}
|
|
||||||
# full backup, for compatibility, we use the native copy unction, not
|
|
||||||
# dircopy from File::Copy::Recursive
|
|
||||||
if($commandchain[1] eq "") {
|
|
||||||
opendir(IMD, $moddir) || return "Cannot open fhem-module directory";
|
|
||||||
my @files= readdir(IMD);
|
|
||||||
closedir(IMD);
|
|
||||||
my $f;
|
|
||||||
|
|
||||||
foreach $f (@files) {
|
|
||||||
unless ( ($f eq ".") || ($f eq "..") ) {
|
|
||||||
my $ret = copy("$moddir/$f", "$backupdir/$f");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$param = "";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
# one file backup
|
|
||||||
copy("$moddir/$commandchain[1]", "$backupdir/$commandchain[1]");
|
|
||||||
# recreate $param for further use
|
|
||||||
$param = $commandchain[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Read in the OLD filetimes.txt
|
# Read in the OLD filetimes.txt
|
||||||
@@ -226,6 +201,8 @@ GetHttpFile($$)
|
|||||||
my $req = "GET $filename HTTP/1.0\r\nHost: $host\r\n\r\n\r\n";
|
my $req = "GET $filename HTTP/1.0\r\nHost: $host\r\n\r\n\r\n";
|
||||||
syswrite $conn, $req;
|
syswrite $conn, $req;
|
||||||
my ($buf, $ret);
|
my ($buf, $ret);
|
||||||
|
|
||||||
|
# Note: should add a timeout
|
||||||
while(sysread($conn,$buf,65536) > 0) {
|
while(sysread($conn,$buf,65536) > 0) {
|
||||||
$ret .= $buf;
|
$ret .= $buf;
|
||||||
}
|
}
|
||||||
|
|||||||
5
HISTORY
5
HISTORY
@@ -485,3 +485,8 @@
|
|||||||
- Thu Dec 01 2011 (Martin F.)
|
- Thu Dec 01 2011 (Martin F.)
|
||||||
- Move JsonList from contrib to main modules. Jsonlist output is optimized
|
- Move JsonList from contrib to main modules. Jsonlist output is optimized
|
||||||
and now be more structured.
|
and now be more structured.
|
||||||
|
|
||||||
|
- Sun Jan 29 2012 (Maz Rashid)
|
||||||
|
- Improving 10_EIB.pm by introducing Get and interpreting received value according
|
||||||
|
to the selected model (based on datapoint types.)
|
||||||
|
- Introduced documentation for TUL / EIB modules.
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
#
|
#
|
||||||
# where <key> is one of currentPower, totalEnergy, totalEnergyDay,
|
# where <key> is one of currentPower, totalEnergy, totalEnergyDay,
|
||||||
# totalEnergyMonth, totalEnergyYear, UDC, IDC, UDCB, IDCB, UDCC, IDCC,
|
# totalEnergyMonth, totalEnergyYear, UDC, IDC, UDCB, IDCB, UDCC, IDCC,
|
||||||
# gridVoltage, gridPower and temperature.
|
# gridVoltage, gridCurrent and temperature.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -61,15 +61,15 @@ use warnings;
|
|||||||
|
|
||||||
use IO::Socket::INET;
|
use IO::Socket::INET;
|
||||||
|
|
||||||
my @gets = ('totalEnergyDay', # kWh
|
my @gets = ('totalEnergyDay', # kWh
|
||||||
'totalEnergyMonth', # kWh
|
'totalEnergyMonth', # kWh
|
||||||
'totalEnergyYear', # kWh
|
'totalEnergyYear', # kWh
|
||||||
'totalEnergy', # kWh
|
'totalEnergy', # kWh
|
||||||
'currentPower', # W
|
'currentPower', # W
|
||||||
'UDC', 'IDC', 'UDCB', # V, A, V
|
'UDC', 'IDC', 'UDCB', # V, A, V
|
||||||
'IDCB', 'UDCC', 'IDCC', # A, V, A
|
'IDCB', 'UDCC', 'IDCC', # A, V, A
|
||||||
'gridVoltage', 'gridPower', # V, A
|
'gridVoltage', 'gridCurrent', # V, A
|
||||||
'temperature'); # <EFBFBD>C
|
'temperature'); # oC
|
||||||
|
|
||||||
sub
|
sub
|
||||||
SolarView_Initialize($)
|
SolarView_Initialize($)
|
||||||
@@ -100,10 +100,17 @@ SolarView_Define($$)
|
|||||||
$hash->{Interval} = (@args>=5) ? int($args[4]) : 300;
|
$hash->{Interval} = (@args>=5) ? int($args[4]) : 300;
|
||||||
$hash->{Timeout} = (@args>=6) ? int($args[5]) : 4;
|
$hash->{Timeout} = (@args>=6) ? int($args[5]) : 4;
|
||||||
|
|
||||||
$hash->{Invalid} = -1;
|
# config variables
|
||||||
$hash->{NightOff} = 1;
|
$hash->{Invalid} = -1; # default value for invalid readings
|
||||||
$hash->{Debounce} = 50;
|
$hash->{Sleep} = 0; # seconds to sleep before connect
|
||||||
$hash->{Sleep} = 0;
|
$hash->{Debounce} = 50; # minimum level for enabling debounce (0 to disable)
|
||||||
|
$hash->{Rereads} = 2; # number of retries when reading curPwr of 0
|
||||||
|
$hash->{NightOff} = 'yes'; # skip connection to SV at night?
|
||||||
|
$hash->{UseSVNight} = 'yes'; # use the on/off timings from SV (else: SUNRISE_EL)
|
||||||
|
$hash->{UseSVTime} = ''; # use the SV time as timestamp (else: TimeNow())
|
||||||
|
|
||||||
|
# internal variables
|
||||||
|
$hash->{Debounced} = 0;
|
||||||
|
|
||||||
$hash->{STATE} = 'Initializing';
|
$hash->{STATE} = 'Initializing';
|
||||||
|
|
||||||
@@ -135,22 +142,29 @@ SolarView_Update($)
|
|||||||
# if NightOff is set and there has been a successful
|
# if NightOff is set and there has been a successful
|
||||||
# reading before, then skip this update "at night"
|
# reading before, then skip this update "at night"
|
||||||
#
|
#
|
||||||
if ($hash->{NightOff} and $hash->{READINGS}{currentPower}{VAL} != $hash->{Invalid})
|
if ($hash->{NightOff} and SolarView_IsNight($hash) and
|
||||||
|
$hash->{READINGS}{currentPower}{VAL} != $hash->{Invalid})
|
||||||
{
|
{
|
||||||
my ($sec,$min,$hour) = localtime(time);
|
$hash->{STATE} = 'Pausing';
|
||||||
return undef if ($hour < 6 or $hour > 22);
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep($hash->{Sleep}) if $hash->{Sleep};
|
sleep($hash->{Sleep}) if $hash->{Sleep};
|
||||||
|
|
||||||
Log 4, "$hash->{NAME} tries to connect solarview at $hash->{Host}:$hash->{Port}";
|
Log 4, "$hash->{NAME} tries to contact solarview at $hash->{Host}:$hash->{Port}";
|
||||||
|
|
||||||
|
# save the previous value of currentPower for debouncing
|
||||||
|
my $cpVal = $hash->{READINGS}{currentPower}{VAL};
|
||||||
|
my $cpTime = $hash->{READINGS}{currentPower}{TIME};
|
||||||
|
|
||||||
my $success = 0;
|
my $success = 0;
|
||||||
|
my $rereads = $hash->{Rereads};
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
local $SIG{ALRM} = sub { die 'timeout'; };
|
local $SIG{ALRM} = sub { die 'timeout'; };
|
||||||
alarm $hash->{Timeout};
|
alarm $hash->{Timeout};
|
||||||
|
|
||||||
|
READ_SV:
|
||||||
my $socket = IO::Socket::INET->new(PeerAddr => $hash->{Host},
|
my $socket = IO::Socket::INET->new(PeerAddr => $hash->{Host},
|
||||||
PeerPort => $hash->{Port},
|
PeerPort => $hash->{Port},
|
||||||
Timeout => $hash->{Timeout});
|
Timeout => $hash->{Timeout});
|
||||||
@@ -162,17 +176,17 @@ SolarView_Update($)
|
|||||||
my $res = <$socket>;
|
my $res = <$socket>;
|
||||||
close($socket);
|
close($socket);
|
||||||
|
|
||||||
alarm 0;
|
|
||||||
|
|
||||||
if ($res and $res =~ /^\{(00,[\d\.,]+)\},/)
|
if ($res and $res =~ /^\{(00,[\d\.,]+)\},/)
|
||||||
{
|
{
|
||||||
my @vals = split(/,/, $1);
|
my @vals = split(/,/, $1);
|
||||||
|
|
||||||
my $tn = sprintf("%04d-%02d-%02d %02d:%02d:00",
|
my $timenow = TimeNow();
|
||||||
$vals[3], $vals[2], $vals[1], $vals[4], $vals[5]);
|
|
||||||
|
|
||||||
my $cpVal = $hash->{READINGS}{currentPower}{VAL};
|
if ($hash->{UseSVTime})
|
||||||
my $cpTime = $hash->{READINGS}{currentPower}{TIME};
|
{
|
||||||
|
$timenow = sprintf("%04d-%02d-%02d %02d:%02d:00",
|
||||||
|
$vals[3], $vals[2], $vals[1], $vals[4], $vals[5]);
|
||||||
|
}
|
||||||
|
|
||||||
for my $i (6..19)
|
for my $i (6..19)
|
||||||
{
|
{
|
||||||
@@ -181,19 +195,33 @@ SolarView_Update($)
|
|||||||
if (defined($vals[$i]))
|
if (defined($vals[$i]))
|
||||||
{
|
{
|
||||||
$hash->{READINGS}{$gets[$getIdx]}{VAL} = 0 + $vals[$i];
|
$hash->{READINGS}{$gets[$getIdx]}{VAL} = 0 + $vals[$i];
|
||||||
$hash->{READINGS}{$gets[$getIdx]}{TIME} = $tn;
|
$hash->{READINGS}{$gets[$getIdx]}{TIME} = $timenow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# if Debounce is enabled, then skip one drop of
|
if ($rereads and $hash->{READINGS}{currentPower}{VAL} == 0)
|
||||||
|
{
|
||||||
|
sleep(1);
|
||||||
|
$rereads = $rereads - 1;
|
||||||
|
goto READ_SV;
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm 0;
|
||||||
|
|
||||||
|
# if Debounce is enabled (>0), then skip one! drop of
|
||||||
# currentPower from 'greater than Debounce' to 'Zero'
|
# currentPower from 'greater than Debounce' to 'Zero'
|
||||||
#
|
#
|
||||||
if ($hash->{Debounce} > 0 and
|
if ($hash->{Debounce} > 0 and
|
||||||
$hash->{Debounce} < $cpVal and
|
$hash->{Debounce} < $cpVal and
|
||||||
$hash->{READINGS}{currentPower}{VAL} == 0)
|
$hash->{READINGS}{currentPower}{VAL} == 0 and
|
||||||
|
not $hash->{Debounced})
|
||||||
{
|
{
|
||||||
$hash->{READINGS}{currentPower}{VAL} = $cpVal;
|
$hash->{READINGS}{currentPower}{VAL} = $cpVal;
|
||||||
$hash->{READINGS}{currentPower}{TIME} = $cpTime;
|
$hash->{READINGS}{currentPower}{TIME} = $cpTime;
|
||||||
|
|
||||||
|
$hash->{Debounced} = 1;
|
||||||
|
} else {
|
||||||
|
$hash->{Debounced} = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$success = 1;
|
$success = 1;
|
||||||
@@ -248,5 +276,70 @@ SolarView_Undef($$)
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
SolarView_IsNight($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
my $isNight = 0;
|
||||||
|
my ($sec,$min,$hour,$mday,$mon) = localtime(time);
|
||||||
|
|
||||||
|
# reset totalEnergyX if needed
|
||||||
|
if ($hour == 0)
|
||||||
|
{
|
||||||
|
my $timenow = TimeNow();
|
||||||
|
|
||||||
|
$hash->{READINGS}{totalEnergyDay}{VAL} = 0;
|
||||||
|
$hash->{READINGS}{totalEnergyDay}{TIME} = $timenow;
|
||||||
|
#
|
||||||
|
if ($mday == 1)
|
||||||
|
{
|
||||||
|
$hash->{READINGS}{totalEnergyMonth}{VAL} = 0;
|
||||||
|
$hash->{READINGS}{totalEnergyMonth}{TIME} = $timenow;
|
||||||
|
#
|
||||||
|
if ($mon == 0)
|
||||||
|
{
|
||||||
|
$hash->{READINGS}{totalEnergyYear}{VAL} = 0;
|
||||||
|
$hash->{READINGS}{totalEnergyYear}{TIME} = $timenow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hash->{UseSVNight})
|
||||||
|
{
|
||||||
|
# These are the on/off timings from Solarview, see
|
||||||
|
# http://www.amhamberg.de/solarview-fb_Installieren.pdf
|
||||||
|
#
|
||||||
|
if ($mon == 0) { # Jan
|
||||||
|
$isNight = ($hour < 7 or $hour > 17);
|
||||||
|
} elsif ($mon == 1) { # Feb
|
||||||
|
$isNight = ($hour < 7 or $hour > 18);
|
||||||
|
} elsif ($mon == 2) { # Mar
|
||||||
|
$isNight = ($hour < 6 or $hour > 19);
|
||||||
|
} elsif ($mon == 3) { # Apr
|
||||||
|
$isNight = ($hour < 5 or $hour > 20);
|
||||||
|
} elsif ($mon == 4) { # May
|
||||||
|
$isNight = ($hour < 5 or $hour > 21);
|
||||||
|
} elsif ($mon == 5) { # Jun
|
||||||
|
$isNight = ($hour < 5 or $hour > 21);
|
||||||
|
} elsif ($mon == 6) { # Jul
|
||||||
|
$isNight = ($hour < 5 or $hour > 21);
|
||||||
|
} elsif ($mon == 7) { # Aug
|
||||||
|
$isNight = ($hour < 5 or $hour > 21);
|
||||||
|
} elsif ($mon == 8) { # Sep
|
||||||
|
$isNight = ($hour < 6 or $hour > 20);
|
||||||
|
} elsif ($mon == 9) { # Oct
|
||||||
|
$isNight = ($hour < 7 or $hour > 19);
|
||||||
|
} elsif ($mon == 10) { # Nov
|
||||||
|
$isNight = ($hour < 7 or $hour > 17);
|
||||||
|
} elsif ($mon == 11) { # Dec
|
||||||
|
$isNight = ($hour < 8 or $hour > 16);
|
||||||
|
}
|
||||||
|
} else { # we use SUNRISE_EL
|
||||||
|
$isNight = not isday();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isNight;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
<a href="#ECMD">ECMD</a>
|
<a href="#ECMD">ECMD</a>
|
||||||
<a href="#ECMDDevice">ECMDDevice</a>
|
<a href="#ECMDDevice">ECMDDevice</a>
|
||||||
<a href="#DS18S20">DS18S20</a>
|
<a href="#DS18S20">DS18S20</a>
|
||||||
|
<a href="#EIB">EIB</a>
|
||||||
<a href="#EnOcean">EnOcean</a>
|
<a href="#EnOcean">EnOcean</a>
|
||||||
<a href="#EM">EM</a>
|
<a href="#EM">EM</a>
|
||||||
<a href="#EMEM">EMEM</a>
|
<a href="#EMEM">EMEM</a>
|
||||||
@@ -104,6 +105,7 @@
|
|||||||
<a href="#M232">M232</a>
|
<a href="#M232">M232</a>
|
||||||
<a href="#M232Counter">M232Counter</a>
|
<a href="#M232Counter">M232Counter</a>
|
||||||
<a href="#M232Voltage">M232Voltage</a>
|
<a href="#M232Voltage">M232Voltage</a>
|
||||||
|
<a href="#NetIO230B">NetIO230B</a>
|
||||||
<a href="#OREGON">OREGON</a>
|
<a href="#OREGON">OREGON</a>
|
||||||
<a href="#OWFS">OWFS</a>
|
<a href="#OWFS">OWFS</a>
|
||||||
<a href="#OWTEMP">OWTEMP</a>
|
<a href="#OWTEMP">OWTEMP</a>
|
||||||
@@ -115,6 +117,7 @@
|
|||||||
<a href="#SIS_PMS">SIS_PMS</a>
|
<a href="#SIS_PMS">SIS_PMS</a>
|
||||||
<a href="#TCM">TCM</a>
|
<a href="#TCM">TCM</a>
|
||||||
<a href="#TellStick">TellStick</a>
|
<a href="#TellStick">TellStick</a>
|
||||||
|
<a href="#TUL">TUL</a>
|
||||||
<a href="#USF1000">USF1000</a>
|
<a href="#USF1000">USF1000</a>
|
||||||
<a href="#USBWX">USBWX</a>
|
<a href="#USBWX">USBWX</a>
|
||||||
<a href="#VantagePro2">VantagePro2</a>
|
<a href="#VantagePro2">VantagePro2</a>
|
||||||
@@ -709,24 +712,23 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
will be necessary to apply the changes.
|
will be necessary to apply the changes.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
If backup is specified, then the old files are saved before overwriting
|
If backup is specified, then the complete FHEM directory (containing the
|
||||||
them. They are copied to the folder given in global <backupdir> or as
|
modules and .gplot files) will be saved into a .tar.gz file with a
|
||||||
default to /tmp/FHEM_Backup. Please check if the fhem user has the rights
|
timestamp in the <a href="#modpath">modpath</a>/FHEM.backup directory or to
|
||||||
to create a folder for backup.
|
a directory specified by the <a href="#backupdir">backupdir</a> global
|
||||||
|
attribute. Note: tar and gzip must be installed to use this feature.
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<b>Attributes</b> <ul>
|
<b>Attributes</b> <ul>
|
||||||
<a name="backupdir"></a>
|
<a name="backupdir"></a>
|
||||||
<li>backupdir<br>
|
<li>backupdir<br>
|
||||||
A folder where updatefhem can store all files from <a
|
A folder where updatefhem will store the compressed backup file.
|
||||||
href="#modpath">modpath</a> before executing the update. Please check if
|
Note: this is a global attribute.<br>Example:
|
||||||
the fhem user has the rights to create this folder.
|
<ul>
|
||||||
|
attr global backupdir /Volumes/BigHD<br>
|
||||||
|
</ul>
|
||||||
</li><br>
|
</li><br>
|
||||||
Note: this is a global attribute, e.g.<br>
|
|
||||||
<ul>
|
|
||||||
attr global backup /Volumes/BigHD<br>
|
|
||||||
</ul>
|
|
||||||
</ul><br>
|
</ul><br>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
@@ -1097,13 +1099,13 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
This attribute is DEPRECATED, use <a href="#notify">notify</a>, with
|
This attribute is DEPRECATED, use <a href="#notify">notify</a>, with
|
||||||
the INITIALIZED event to execute commands after initialization.
|
the INITIALIZED event to execute commands after initialization.
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
<a name="logfile"></a>
|
<a name="logfile"></a>
|
||||||
<li>logfile<br>
|
<li>logfile<br>
|
||||||
Specify the logfile to write. You can use "-" for
|
Specify the logfile to write. You can use "-" for
|
||||||
stdout, in this case the server won't background itself.<br>
|
stdout, in this case the server won't background itself.<br>
|
||||||
The logfile name can also take wildcards for easier logfile rotation,
|
The logfile name can also take wildcards for easier logfile rotation,
|
||||||
see the <a href="#FileLog">FileLog</a> section. Just apply the
|
see the <a href="#FileLog">FileLog</a> section. Just apply the
|
||||||
<code>archivecmd / archivedir / nrarchive</code> attributes to the
|
<code>archivecmd / archivedir / nrarchive</code> attributes to the
|
||||||
<code>global</code> device as you would do for a FileLog device.<br>
|
<code>global</code> device as you would do for a FileLog device.<br>
|
||||||
You can access the current name of the logfile with
|
You can access the current name of the logfile with
|
||||||
@@ -2263,7 +2265,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
Note: this module may require the Device::SerialPort or Win32::SerialPort
|
Note: this module may require the Device::SerialPort or Win32::SerialPort
|
||||||
module if you attach the device via USB and the OS sets strange default
|
module if you attach the device via USB and the OS sets strange default
|
||||||
parameters for serial devices.
|
parameters for serial devices.
|
||||||
|
|
||||||
|
|
||||||
</td><td>
|
</td><td>
|
||||||
<img src="ccc.jpg"/>
|
<img src="ccc.jpg"/>
|
||||||
@@ -2625,8 +2627,8 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
<ul>
|
<ul>
|
||||||
<a name="irLearnForSec"></a>
|
<a name="irLearnForSec"></a>
|
||||||
<li>irLearnForSec<br>
|
<li>irLearnForSec<br>
|
||||||
Sets the CUL_IR device in an IR-Code Learning mode for the given seconds. Any received IR-Code will
|
Sets the CUL_IR device in an IR-Code Learning mode for the given seconds. Any received IR-Code will
|
||||||
be stored as a Button attribute for this devices. The name of these attributes is dependent on the two
|
be stored as a Button attribute for this devices. The name of these attributes is dependent on the two
|
||||||
attributes <a href="#CUL_IRattr">learncount</a> and <a href="#CUL_IRattr">learnprefix</a>.<br>
|
attributes <a href="#CUL_IRattr">learncount</a> and <a href="#CUL_IRattr">learnprefix</a>.<br>
|
||||||
Attention: Before learning IR-Codes the CUL_IR device needs to be set in IR-Receiving mode
|
Attention: Before learning IR-Codes the CUL_IR device needs to be set in IR-Receiving mode
|
||||||
by modifying the <a href="#irReceive">irReceive</a> attribute.
|
by modifying the <a href="#irReceive">irReceive</a> attribute.
|
||||||
@@ -2647,8 +2649,8 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
Example: <br>
|
Example: <br>
|
||||||
<code>set IR-Dev irSend 0A07070F0F02<br>
|
<code>set IR-Dev irSend 0A07070F0F02<br>
|
||||||
set IR-Dev irSend I0A07070F0F00 </code>
|
set IR-Dev irSend I0A07070F0F00 </code>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a name="CUL_IRget"></a>
|
<a name="CUL_IRget"></a>
|
||||||
@@ -2669,11 +2671,11 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
Switching off the reception of IR signals. This is the default.
|
Switching off the reception of IR signals. This is the default.
|
||||||
|
|
||||||
<li>ON<br>
|
<li>ON<br>
|
||||||
Switching on the reception of IR signals. This is WITHOUT filtering repetitions. This is
|
Switching on the reception of IR signals. This is WITHOUT filtering repetitions. This is
|
||||||
not recommended as many remote controls do repeat their signals.
|
not recommended as many remote controls do repeat their signals.
|
||||||
|
|
||||||
<li>ON_NR<br>
|
<li>ON_NR<br>
|
||||||
Switching on the reception of IR signals with filtering of repetitions. This is
|
Switching on the reception of IR signals with filtering of repetitions. This is
|
||||||
the recommended modus operandi.
|
the recommended modus operandi.
|
||||||
</ul>
|
</ul>
|
||||||
</li><br>
|
</li><br>
|
||||||
@@ -2684,7 +2686,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
<pre>
|
<pre>
|
||||||
Button<learnprefix><learncount>
|
Button<learnprefix><learncount>
|
||||||
</pre>
|
</pre>
|
||||||
When the CUL_IR device is set into <a href="#irLearnForSec">learning mode</a> it will generate a
|
When the CUL_IR device is set into <a href="#irLearnForSec">learning mode</a> it will generate a
|
||||||
new button-attribute for each new IR-Code received.This is done according to the following syntax:<br>
|
new button-attribute for each new IR-Code received.This is done according to the following syntax:<br>
|
||||||
<pre>
|
<pre>
|
||||||
<Button-Attribute-Name> <IR-Code></pre>
|
<Button-Attribute-Name> <IR-Code></pre>
|
||||||
@@ -2692,7 +2694,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
<pre>
|
<pre>
|
||||||
Button001 I02029A000000
|
Button001 I02029A000000
|
||||||
Button002 I02029A000001</pre>
|
Button002 I02029A000001</pre>
|
||||||
To make sure that something happens when this IR-code is received later on one has to modify the attribute
|
To make sure that something happens when this IR-code is received later on one has to modify the attribute
|
||||||
and to add commands as attribute values.
|
and to add commands as attribute values.
|
||||||
Examples:
|
Examples:
|
||||||
<pre>
|
<pre>
|
||||||
@@ -2726,7 +2728,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
Button<learnprefix><learncount> </pre>
|
Button<learnprefix><learncount> </pre>
|
||||||
If learnprefix is empty the button-attribute-name only contains the term
|
If learnprefix is empty the button-attribute-name only contains the term
|
||||||
"Button" and the actual number of <a href="#learncount">learncount</a>.
|
"Button" and the actual number of <a href="#learncount">learncount</a>.
|
||||||
</li><br>
|
</li><br>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -2947,7 +2949,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
party-temp <tmp><br>
|
party-temp <tmp><br>
|
||||||
desired-temp <tmp><br>
|
desired-temp <tmp><br>
|
||||||
Set different temperatures. Temp must be between 6 and 30
|
Set different temperatures. Temp must be between 6 and 30
|
||||||
Celsius, and precision is half a degree.
|
Celsius, and precision is half a degree.</li>
|
||||||
<li>tempListSat HH:MM temp ... 24:00 temp<br>
|
<li>tempListSat HH:MM temp ... 24:00 temp<br>
|
||||||
tempListSun HH:MM temp ... 24:00 temp<br>
|
tempListSun HH:MM temp ... 24:00 temp<br>
|
||||||
tempListMon HH:MM temp ... 24:00 temp<br>
|
tempListMon HH:MM temp ... 24:00 temp<br>
|
||||||
@@ -2959,6 +2961,13 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
specified for each week day, the resolution is 10 Minutes. The
|
specified for each week day, the resolution is 10 Minutes. The
|
||||||
last time spec must always be 24:00.<br>
|
last time spec must always be 24:00.<br>
|
||||||
Example: set th tempListSat 06:00 19 23:00 22.5 24:00 19<br>
|
Example: set th tempListSat 06:00 19 23:00 22.5 24:00 19<br>
|
||||||
|
Meaning: until 6:00 temperature shall be 19, from then until 23:00 temperature shall be
|
||||||
|
22.5, thereafter until midnight, 19 degrees celsius is desired.</li>
|
||||||
|
<li>displayMode [temp-only|temp-hum]<br>
|
||||||
|
displayTemp [actual|setpoint]<br>
|
||||||
|
displayTempUnit [celsius|fahrenheit]<br>
|
||||||
|
controlMode [manual|auto|central|party]<br>
|
||||||
|
decalcDay <day></li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
@@ -3210,12 +3219,124 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
<a name="EIB"></a>
|
||||||
|
<h3>EIB / KNX</h3>
|
||||||
|
<ul>
|
||||||
|
EIB/KNX is a standard for building automation / home automation.
|
||||||
|
It is mainly based on a twisted pair wiring, but also other mediums (ip, wireless) are specified.
|
||||||
|
|
||||||
|
While the module <a href="#TUL">TUL</a> represents the connection to the EIB network,
|
||||||
|
the EIB modules represent individual EIB devices. This module provides a basic set of operations (on, off, on-till, etc.)
|
||||||
|
to switch on/off EIB devices. Sophisticated setups can be achieved by combining a number of
|
||||||
|
EIB module instances or by sending raw hex values to the network (set <devname> raw <hexval>).
|
||||||
|
|
||||||
|
EIB/KNX defines a series of Datapoint Type as standard data types used
|
||||||
|
to allow general interpretation of values of devices manufactured by diferent companies.
|
||||||
|
This datatypes are used to interpret the status of a device, so the state in FHEM will then
|
||||||
|
show the correct value.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<a name="EIBdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> EIB <main group> [<additional group> ..]</code>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
Define an EIB device, connected via a <a href="#TUL">TUL</a>. The
|
||||||
|
<group> parameters are either a group name notation (0-15/0-15/0-255) or the hex representation of the value (0-f0-f0-ff).
|
||||||
|
The <main group> is used for sending of commands to the EIB network.
|
||||||
|
The state of the instance will be updated when a new state is received from the network for any of the given groups.
|
||||||
|
This is usefull for example for toggle switches where a on command is send to one group and the real state (on or off) is
|
||||||
|
responded back on a second group.
|
||||||
|
|
||||||
|
For actors and sensors the
|
||||||
|
<a href="#autocreate">autocreate</a> module may help.<br>
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<ul>
|
||||||
|
<code>define lamp1 EIB 0/10/12</code><br>
|
||||||
|
<code>define lamp1 EIB 0/10/12 0/0/5</code><br>
|
||||||
|
<code>define lamp1 EIB 0A0C</code><br>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="EIBset"></a>
|
||||||
|
<b>Set</b>
|
||||||
|
<ul>
|
||||||
|
<code>set <name> <value> [<time>]</code><br>
|
||||||
|
where value one of:
|
||||||
|
<li><b>on</b> switch on device
|
||||||
|
<li><b>off</b> switch off device
|
||||||
|
<li><b>on-for-timer</b> <secs> switch on the device for the given time. After the specified seconds a switch off command is sent.
|
||||||
|
<li><b>on-till</b> <time spec> switches the device on. The device will be switched off at the given time.
|
||||||
|
<li><b>value</b> <hexvalue> sends the given value as raw data to the device.
|
||||||
|
|
||||||
|
<br>Example:
|
||||||
|
<ul><code>
|
||||||
|
set lamp1 on<br>
|
||||||
|
set lamp1 off<br>
|
||||||
|
set lamp1 on-for-timer 10<br>
|
||||||
|
set lamp1 on-till 13:15:00<br>
|
||||||
|
set lamp1 value 234578<br>
|
||||||
|
</code></ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="EIBattr"></a>
|
||||||
|
<b>Attributes</b>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#eventMap">eventMap</a></li>
|
||||||
|
<li><a href="#webCmd">webCmd</a></li>
|
||||||
|
<li><a href="#IODev">IODev</a></li>
|
||||||
|
<li><a href="#loglevel">loglevel</a></li>
|
||||||
|
<li><a href="#do_not_notify">do_not_notify</a></li>
|
||||||
|
<li><a href="#ignore">ignore</a></li>
|
||||||
|
<li><a href="#dummy">dummy</a></li>
|
||||||
|
<li><a href="#showtime">showtime</a></li>
|
||||||
|
<li><a href="#model">model</a>
|
||||||
|
set the model according to the datapoint types defined by the (<a href="http://www.sti.uniurb.it/romanell/110504-Lez10a-KNX-Datapoint%20Types%20v1.5.00%20AS.pdf" target="_blank">EIB / KNX specifications</a>).<br>
|
||||||
|
The device state in FHEM is interpreted and shown according to the specification.
|
||||||
|
<ul>
|
||||||
|
<li>dpt5</li>
|
||||||
|
<li>percent</li>
|
||||||
|
<li>dpt7</li>
|
||||||
|
<li>length-mm</li>
|
||||||
|
<li>current-mA</li>
|
||||||
|
<li>brightness</li>
|
||||||
|
<li>timeperiod-ms</li>
|
||||||
|
<li>timeperiod-min</li>
|
||||||
|
<li>timeperiod-h</li>
|
||||||
|
<li>dpt9</li>
|
||||||
|
<li>tempsensor</li>
|
||||||
|
<li>lightsensor</li>
|
||||||
|
<li>dpt10</li>
|
||||||
|
<li>time</li>
|
||||||
|
<li>dpt11</li>
|
||||||
|
<li>date</li>
|
||||||
|
<li>dpt12</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
<a name="EnOcean"></a>
|
<a name="EnOcean"></a>
|
||||||
<h3>EnOcean</h3>
|
<h3>EnOcean</h3>
|
||||||
<ul>
|
<ul>
|
||||||
Devices sold by numerous hardware verndors (e.g. Eltako, Peha, etc), using
|
Devices sold by numerous hardware vendors (e.g. Eltako, Peha, etc), using
|
||||||
the RF Protocol provided by the EnOcean Alliance.
|
the RF Protocol provided by the EnOcean Alliance.
|
||||||
|
<br>
|
||||||
|
To send commands to an Enocean-actuator the <a href="#TCM">TCM</a> can either use the
|
||||||
|
unique Chip-ID (then you can control only one actuator, but nobody else
|
||||||
|
can send commands to your device from a normal enocean-module). Or you can set/use the
|
||||||
|
Base-ID and define a Sub-ID for every device to control (then up to 128 devices
|
||||||
|
can be controlled, but anyone take over your devices simply by sniffing and copying the base-id).
|
||||||
|
<br>
|
||||||
|
To use Sub-IDs set the attribute <code>subId</code> to different values (0-127) for all your devices.
|
||||||
<br><br>
|
<br><br>
|
||||||
<a name="EnOceandefine"></a>
|
<a name="EnOceandefine"></a>
|
||||||
<b>Define</b>
|
<b>Define</b>
|
||||||
@@ -3250,6 +3371,31 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
Do not regulate the MD15.</li>
|
Do not regulate the MD15.</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
|
|
||||||
|
<li>Eltako-Dimmer-Switch (FUD12NPN, FUD61NP, FUD61NPN). Set subtype: <code>attr mydimmer subType eltakoDimmer</code>
|
||||||
|
<br>
|
||||||
|
Commands:
|
||||||
|
<ul>
|
||||||
|
<li>dimto <value></li>
|
||||||
|
<li>dimup <value></li>
|
||||||
|
<li>dimdown <value></li>
|
||||||
|
<li>on</li>
|
||||||
|
<li>off</li>
|
||||||
|
<li>teach</li>
|
||||||
|
</ul>
|
||||||
|
Attributes:
|
||||||
|
<ul>
|
||||||
|
<li>dimTime <value><br>. Set Dimm-velocity (0-255) 0: fast</li>
|
||||||
|
</ul></li>
|
||||||
|
|
||||||
|
<li>Eltako-Roller-Shutter (FSB12, FSB61). Set subtype: <code>attr myroll subType eltakoRoll</code>
|
||||||
|
<br>
|
||||||
|
Commands:
|
||||||
|
<ul>
|
||||||
|
<li>up</li>
|
||||||
|
<li>down</li>
|
||||||
|
<li>stop</li>
|
||||||
|
<li>teach</li>
|
||||||
|
</ul></li>
|
||||||
|
|
||||||
<li>all other:
|
<li>all other:
|
||||||
<ul>
|
<ul>
|
||||||
@@ -3357,7 +3503,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
subType must be MD15. This is done if the device was created by
|
subType must be MD15. This is done if the device was created by
|
||||||
autocreate.<br>
|
autocreate.<br>
|
||||||
<ul>
|
<ul>
|
||||||
<li>$actuator %
|
<li>$actuator %
|
||||||
<li>currentValue: $actuator
|
<li>currentValue: $actuator
|
||||||
<li>serviceOn: [yes|no]
|
<li>serviceOn: [yes|no]
|
||||||
<li>energyInput: [enabled|disabled]
|
<li>energyInput: [enabled|disabled]
|
||||||
@@ -3369,7 +3515,12 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
<li>actuator: [ok|obstructed]
|
<li>actuator: [ok|obstructed]
|
||||||
<li>temperature: $tmp
|
<li>temperature: $tmp
|
||||||
</ul>
|
</ul>
|
||||||
|
<li>Ratio Presence Sensor Eagle PM101 (set subType to PM101)<br>
|
||||||
|
<ul>
|
||||||
|
<li>brightness: $lux
|
||||||
|
<li>channel1: [on|off]
|
||||||
|
<li>channel2: [on|off]
|
||||||
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -3661,7 +3812,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
||||||
<a name="KM271events"></a>
|
<a name="KM271events"></a>
|
||||||
<b>Generated events:</b>
|
<b>Generated events:</b>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -3892,9 +4043,9 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
<code>define <name> WOL <MAC> <IP>
|
<code>define <name> WOL <MAC> <IP>
|
||||||
<unitcode></code>
|
<unitcode></code>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
Defines a WOL device via its MAC and IP address.<br><br>
|
Defines a WOL device via its MAC and IP address.<br><br>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
<ul>
|
<ul>
|
||||||
<code>define computer1 WOL 72:11:AC:4D:37:13 192.168.0.24</code><br>
|
<code>define computer1 WOL 72:11:AC:4D:37:13 192.168.0.24</code><br>
|
||||||
@@ -3905,7 +4056,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
<li>For other computers the WOL implementation of <a href="http://search.cpan.org/~clintdw/Net-Wake-0.02/lib/Net/Wake.pm">Net::Wake</a> is used</li>
|
<li>For other computers the WOL implementation of <a href="http://search.cpan.org/~clintdw/Net-Wake-0.02/lib/Net/Wake.pm">Net::Wake</a> is used</li>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a name="WOLset"></a>
|
<a name="WOLset"></a>
|
||||||
<b>Set </b>
|
<b>Set </b>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -3916,7 +4067,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
refresh # checks whether the computer is currently running
|
refresh # checks whether the computer is currently running
|
||||||
on # sends a magic packet to the defined MAC address
|
on # sends a magic packet to the defined MAC address
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
<ul>
|
<ul>
|
||||||
<code>set computer1 on</code><br>
|
<code>set computer1 on</code><br>
|
||||||
@@ -4170,7 +4321,7 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
The optional parameter <code>interval</code> is the time between subsequent updates
|
The optional parameter <code>interval</code> is the time between subsequent updates
|
||||||
in seconds. It defaults to 3600 (1 hour).<br><br>
|
in seconds. It defaults to 3600 (1 hour).<br><br>
|
||||||
|
|
||||||
The optional language parameter may be one of <code>en</code>, <code>de</code>, <code>fr</code>,
|
The optional language parameter may be one of <code>en</code>, <code>de</code>, <code>fr</code>,
|
||||||
<code>es</code>. It determines the natural language in which the forecast information appears.
|
<code>es</code>. It determines the natural language in which the forecast information appears.
|
||||||
It defaults to en. If you want to set the language you also have to set the interval.<br><br>
|
It defaults to en. If you want to set the language you also have to set the interval.<br><br>
|
||||||
|
|
||||||
@@ -4629,8 +4780,8 @@ Attributes:<br>
|
|||||||
<ul>
|
<ul>
|
||||||
The InterTechno 433MHZ protocol is used by a wide range of devices, which are either of
|
The InterTechno 433MHZ protocol is used by a wide range of devices, which are either of
|
||||||
the sender/sensor category or the receiver/actuator category. As we right now are only
|
the sender/sensor category or the receiver/actuator category. As we right now are only
|
||||||
able to SEND InterTechno commands, but CAN'T receive them, this module at the moment
|
able to SEND InterTechno commands, but CAN'T receive them, this module at the moment
|
||||||
supports just switches devices like switches, dimmers, etc. through an an
|
supports just switches devices like switches, dimmers, etc. through an an
|
||||||
<a href="#CUL">CUL</a> device, so this must be defined first.
|
<a href="#CUL">CUL</a> device, so this must be defined first.
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
@@ -4642,7 +4793,7 @@ Attributes:<br>
|
|||||||
[<dimup-code>] [<dimdown-code>] </code>
|
[<dimup-code>] [<dimdown-code>] </code>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
The value of housecode is a 10-digit InterTechno Code, consisting of 0/1/F as it is
|
The value of housecode is a 10-digit InterTechno Code, consisting of 0/1/F as it is
|
||||||
defined as a tri-state protocol. These digits depend on your device you are using.
|
defined as a tri-state protocol. These digits depend on your device you are using.
|
||||||
<br>
|
<br>
|
||||||
Bit 11/12 are used for switching/dimming. As different manufacturers are using
|
Bit 11/12 are used for switching/dimming. As different manufacturers are using
|
||||||
@@ -4653,13 +4804,13 @@ Attributes:<br>
|
|||||||
<ul>
|
<ul>
|
||||||
<li><code><housecode></code> is a 10 digit tri-state number (0/1/F) depending on
|
<li><code><housecode></code> is a 10 digit tri-state number (0/1/F) depending on
|
||||||
your device setting (see list below).</li>
|
your device setting (see list below).</li>
|
||||||
<li><code><on-code></code> is a 2 digit tri-state number for switching your device on;
|
<li><code><on-code></code> is a 2 digit tri-state number for switching your device on;
|
||||||
It is appended to the housecode to build the 12-digits IT-Message.</li>
|
It is appended to the housecode to build the 12-digits IT-Message.</li>
|
||||||
<li><code><off-code></code> is a 2 digit tri-state number for switching your device off;
|
<li><code><off-code></code> is a 2 digit tri-state number for switching your device off;
|
||||||
It is appended to the housecode to build the 12-digits IT-Message.</li>
|
It is appended to the housecode to build the 12-digits IT-Message.</li>
|
||||||
<li>The optional <code><dimup-code></code> is a 2 digit tri-state number for dimming your device up;
|
<li>The optional <code><dimup-code></code> is a 2 digit tri-state number for dimming your device up;
|
||||||
It is appended to the housecode to build the 12-digits IT-Message.</li>
|
It is appended to the housecode to build the 12-digits IT-Message.</li>
|
||||||
<li>The optional <code><dimdown-code></code> is a 2 digit tri-state number for dimming your device down;
|
<li>The optional <code><dimdown-code></code> is a 2 digit tri-state number for dimming your device down;
|
||||||
It is appended to the housecode to build the 12-digits IT-Message.</li>
|
It is appended to the housecode to build the 12-digits IT-Message.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
@@ -4684,7 +4835,7 @@ Attributes:<br>
|
|||||||
dimdown
|
dimdown
|
||||||
dimup
|
dimup
|
||||||
off
|
off
|
||||||
on
|
on
|
||||||
on-till # Special, see the note
|
on-till # Special, see the note
|
||||||
</pre>
|
</pre>
|
||||||
Examples:
|
Examples:
|
||||||
@@ -5017,10 +5168,10 @@ Attributes:<br>
|
|||||||
observe the log file.</li>
|
observe the log file.</li>
|
||||||
</ul><br><br>
|
</ul><br><br>
|
||||||
|
|
||||||
Neither apply the rules outlined in the <a href="#perl">documentation of perl specials</a>
|
Neither apply the rules outlined in the <a href="#perl">documentation of perl specials</a>
|
||||||
for the <code><perl command></code> in the postprocessor definitions nor can it contain macros.
|
for the <code><perl command></code> in the postprocessor definitions nor can it contain macros.
|
||||||
This is to avoid undesired side effects from e.g. doubling of semicolons.<br><br>
|
This is to avoid undesired side effects from e.g. doubling of semicolons.<br><br>
|
||||||
|
|
||||||
The <code>perl command</code> acts on <code>$_</code>. The result of the perl command is the
|
The <code>perl command</code> acts on <code>$_</code>. The result of the perl command is the
|
||||||
final result of the get or set command.
|
final result of the get or set command.
|
||||||
</ul>
|
</ul>
|
||||||
@@ -6387,6 +6538,103 @@ Terminating
|
|||||||
<li><a href="#loglevel">loglevel</a></li><br>
|
<li><a href="#loglevel">loglevel</a></li><br>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="NetIO230B"></a>
|
||||||
|
<h3>NetIO230B</h3>
|
||||||
|
<ul>
|
||||||
|
<p>
|
||||||
|
fhem-module for NetIO 230B Power Distribution Unit (see: <a
|
||||||
|
href="http://www.koukaam.se/showproduct.php?article_id=1502">NetIO 230B
|
||||||
|
(koukaam.se)</a>)
|
||||||
|
</p>
|
||||||
|
Note: this module needs the HTTP::Request and LWP::UserAgent perl modules.
|
||||||
|
<br />
|
||||||
|
Please also note: the PDU must use firmware 3.1 or later and set to unencrypted mode.
|
||||||
|
<br /><br />
|
||||||
|
<a name="NETIO230Bdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><code>define <name> NetIO230B <ip-address> <socket number(s)
|
||||||
|
> [<user name> <password>]</code></li>
|
||||||
|
|
||||||
|
<li><code>define <name> NetIO230B <ip-address> <socket number(s)
|
||||||
|
> [<config file path>]</code></li>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Defines a switching device, where sockets can be switched
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>separately (just use 0-4 as socket number)</li>
|
||||||
|
<li>all together (use 1234 as socket number)</li>
|
||||||
|
<li>in arbitrary groups (e.g 13 switches socket 1 and 3, 42
|
||||||
|
switches socket 2 and 4, etc...), invalid numbers are
|
||||||
|
ignored</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
User name and password are optional. When no user name or
|
||||||
|
password is passed, the module looks for a configfile at
|
||||||
|
'/var/log/fhem/netio.conf'. If no config file is found, it
|
||||||
|
uses 'admin/admin' as user/pass, since this is the default
|
||||||
|
configuration for the device.
|
||||||
|
<p>
|
||||||
|
Alternatively you can pass a path to a configfile instead of
|
||||||
|
the user/pass combo. (e.g. /var/tmp/tmp.conf)
|
||||||
|
Configfile-Format:<br />
|
||||||
|
<ul>
|
||||||
|
<code>
|
||||||
|
%config= (<br />
|
||||||
|
host => "192.168.61.40",<br />
|
||||||
|
user => "admin",<br />
|
||||||
|
password => "admin"<br />
|
||||||
|
);</code>
|
||||||
|
<br /><br /><small>(All settings optional)</small>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>Examples:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>define Socket3 NetIO230B 192.168.178.10 3</code></li>
|
||||||
|
<li><code>define Socket1_and_4 NetIO230B 192.168.178.10 14</code></li>
|
||||||
|
<li><code>define coffeemaker NetIO230B 192.168.178.10 1 username secretpassword</code></li>
|
||||||
|
<li><code>define coffeemaker_and_light NetIO230B 192.168.178.10 23 /var/log/kitchen.conf</code></li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="NETIO230Bget"></a>
|
||||||
|
<b>Get </b>
|
||||||
|
<ul>
|
||||||
|
<code>get <name> state</code>
|
||||||
|
<br><br>
|
||||||
|
returns the state of the socket(s)<br>
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<ul>
|
||||||
|
<code>get coffeemaker_and_light</code> => <code>on or off</code><br>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a name="NETIO230Bset"></a>
|
||||||
|
<b>Set </b>
|
||||||
|
<ul>
|
||||||
|
<code>set <name> <value></code>
|
||||||
|
<br><br>
|
||||||
|
where <code>value</code> is one of:<br>
|
||||||
|
<pre>
|
||||||
|
on
|
||||||
|
off
|
||||||
|
</pre>
|
||||||
|
Examples:
|
||||||
|
<ul>
|
||||||
|
<code>set coffeemaker_and_light on</code><br>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<a name="TellStick"></a>
|
<a name="TellStick"></a>
|
||||||
<h3>TellStick</h3>
|
<h3>TellStick</h3>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -6690,6 +6938,92 @@ href="http://www.elv.de/output/controller.aspx?cid=74&detail=10&detail2=29870">U
|
|||||||
<br>
|
<br>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<a name="TUL"></a>
|
||||||
|
<h3>TUL</h3>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><td>
|
||||||
|
The TUL module is the representation of a EIB / KNX connector in FHEM.
|
||||||
|
<a href="#EIB">EIB</a> instances represent the EIB / KNX devices and will need a TUL as IODev to communicate with the EIB / KNX network.<br>
|
||||||
|
The TUL module is designed to connect to EIB network either using EIBD or the <a href="http://busware.de/tiki-index.php?page=TUL" target="_blank">TUL usb stick</a> created by busware.de
|
||||||
|
|
||||||
|
Note: this module may require the Device::SerialPort or Win32::SerialPort
|
||||||
|
module if you attach the device via USB and the OS sets strange default
|
||||||
|
parameters for serial devices.
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
<img src="http://busware.de/show_image.php?id=269" width="100%" height="100%"/>
|
||||||
|
</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<a name="TULdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> TUL <device> <physical address></code> <br>
|
||||||
|
<br>
|
||||||
|
TUL usb stick / TPUART serial devices:<br><ul>
|
||||||
|
<device> specifies the serial port to communicate with the TUL.
|
||||||
|
The name of the serial-device depends on your distribution, under
|
||||||
|
linux the cdc_acm kernel module is responsible, and usually a
|
||||||
|
/dev/ttyACM0 device will be created. If your distribution does not have a
|
||||||
|
cdc_acm module, you can force usbserial to handle the TUL by the
|
||||||
|
following command:<ul>modprobe usbserial vendor=0x03eb
|
||||||
|
product=0x204b</ul>In this case the device is most probably
|
||||||
|
/dev/ttyUSB0.<br><br>
|
||||||
|
|
||||||
|
You can also specify a baudrate if the device name contains the @
|
||||||
|
character, e.g.: /dev/ttyACM0@19200<br><br>
|
||||||
|
Note: For TUL usb stick the baudrate 19200 is needed and this is the default
|
||||||
|
when no baudrate is given.
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
Example:<br>
|
||||||
|
<code>define tul TUL tul:/dev/ttyACM0 1.1.249</code>
|
||||||
|
</ul>
|
||||||
|
EIBD:<br><ul>
|
||||||
|
<device> specifies the host:port of the eibd device. E.g.
|
||||||
|
eibd:192.168.0.244:2323. When using the standard port, the port can be omitted.
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
Example:<br>
|
||||||
|
<code>define tul TUL eibd:localhost 1.1.249</code>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
If the device is called none, then no device will be opened, so you
|
||||||
|
can experiment without hardware attached.<br>
|
||||||
|
|
||||||
|
The physical address is used as the source address of telegrams sent to EIB network.
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="TULset"></a>
|
||||||
|
<b>Set </b>
|
||||||
|
<ul>
|
||||||
|
<li>raw<br>
|
||||||
|
Issue a TUL raw telegram message
|
||||||
|
</li><br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a name="TULget"></a>
|
||||||
|
<b>Get</b>
|
||||||
|
<ul>
|
||||||
|
<li>raw<br>
|
||||||
|
sends a read telegram
|
||||||
|
</li><br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a name="TULattr"></a>
|
||||||
|
<b>Attributes</b>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#do_not_notify">do_not_notify</a></li><br>
|
||||||
|
<li><a href="#attrdummy">dummy</a></li><br>
|
||||||
|
<li><a href="#showtime">showtime</a></li><br>
|
||||||
|
<li><a href="#loglevel">loglevel</a></li><br>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<a name="weblink"></a>
|
<a name="weblink"></a>
|
||||||
<h3>weblink</h3>
|
<h3>weblink</h3>
|
||||||
@@ -6961,7 +7295,7 @@ href="http://www.elv.de/output/controller.aspx?cid=74&detail=10&detail2=29870">U
|
|||||||
devices (i.e. tablets)<br>
|
devices (i.e. tablets)<br>
|
||||||
Note: The default configuration installed with make install-pgm2
|
Note: The default configuration installed with make install-pgm2
|
||||||
installs 2 FHEMWEB instances: port 8083 for desktop browsers and
|
installs 2 FHEMWEB instances: port 8083 for desktop browsers and
|
||||||
port 8084 for smallscreen browsers, both using SVG rendering.
|
port 8084 for smallscreen browsers, both using SVG rendering.
|
||||||
On Android SVG is supported by Opera/Firefox.<br>
|
On Android SVG is supported by Opera/Firefox.<br>
|
||||||
|
|
||||||
WebApp suppport if specifying one of the above options: After viewing
|
WebApp suppport if specifying one of the above options: After viewing
|
||||||
@@ -7966,7 +8300,7 @@ href="http://www.elv.de/output/controller.aspx?cid=74&detail=10&detail2=29870">U
|
|||||||
will be replaced with the name of the old logfile.<br>
|
will be replaced with the name of the old logfile.<br>
|
||||||
|
|
||||||
If this attribute is not set, but nrarchive and/or archivecmd are set,
|
If this attribute is not set, but nrarchive and/or archivecmd are set,
|
||||||
then nrarchive logfiles are kept while older ones are moved to
|
then nrarchive logfiles are kept while older ones are moved to
|
||||||
archivedir (or deleted if archivedir is not set).
|
archivedir (or deleted if archivedir is not set).
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
@@ -8457,7 +8791,7 @@ isday</pre>
|
|||||||
<br><br>
|
<br><br>
|
||||||
<li>OldValue(<devicename>)
|
<li>OldValue(<devicename>)
|
||||||
<li>OldTimestamp(<devicename>)<br>
|
<li>OldTimestamp(<devicename>)<br>
|
||||||
returns the old value/timestamp of the device.
|
returns the old value/timestamp of the device.
|
||||||
<br><br>
|
<br><br>
|
||||||
<li>
|
<li>
|
||||||
ReadingsVal(<devicename>,<reading>,<defaultvalue>)<br>
|
ReadingsVal(<devicename>,<reading>,<defaultvalue>)<br>
|
||||||
@@ -8581,7 +8915,7 @@ The .gnuplot file consists of 3 parts:
|
|||||||
plots of the lineytype "lines" will have an additional starting and
|
plots of the lineytype "lines" will have an additional starting and
|
||||||
ending segment, so that filling is done correctly.<br>
|
ending segment, so that filling is done correctly.<br>
|
||||||
See the SVG spec for details of this CSS file.
|
See the SVG spec for details of this CSS file.
|
||||||
Note: if you plan to use this attribute, you have to specify it for all
|
Note: if you plan to use this attribute, you have to specify it for all
|
||||||
the lines (attribute-blocks) in the plot command.
|
the lines (attribute-blocks) in the plot command.
|
||||||
</li>
|
</li>
|
||||||
<li>lw <linewidth><br>
|
<li>lw <linewidth><br>
|
||||||
|
|||||||
77
fhem.pl
77
fhem.pl
@@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# Copyright notice
|
# Copyright notice
|
||||||
#
|
#
|
||||||
# (c) 2005-20011
|
# (c) 2005-20012
|
||||||
# Copyright: Rudolf Koenig (r dot koenig at koeniglich dot de)
|
# Copyright: Rudolf Koenig (r dot koenig at koeniglich dot de)
|
||||||
# All rights reserved
|
# All rights reserved
|
||||||
#
|
#
|
||||||
@@ -157,8 +157,10 @@ use vars qw($reread_active);
|
|||||||
my $AttrList = "room comment alias";
|
my $AttrList = "room comment alias";
|
||||||
|
|
||||||
my $server; # Server socket
|
my $server; # Server socket
|
||||||
|
my %comments; # Comments from the include files
|
||||||
my $ipv6; # Using IPV6
|
my $ipv6; # Using IPV6
|
||||||
my $currlogfile; # logfile, without wildcards
|
my $currlogfile; # logfile, without wildcards
|
||||||
|
my $currcfgfile=""; # current config/include file
|
||||||
my $logopened = 0; # logfile opened or using stdout
|
my $logopened = 0; # logfile opened or using stdout
|
||||||
my %client; # Client array
|
my %client; # Client array
|
||||||
my $rcvdquit; # Used for quit handling in init files
|
my $rcvdquit; # Used for quit handling in init files
|
||||||
@@ -306,7 +308,7 @@ setGlobalAttrBeforeFork();
|
|||||||
|
|
||||||
if($^O =~ m/Win/ && !$attr{global}{nofork}) {
|
if($^O =~ m/Win/ && !$attr{global}{nofork}) {
|
||||||
Log 1, "Forcing 'attr global nofork' on WINDOWS";
|
Log 1, "Forcing 'attr global nofork' on WINDOWS";
|
||||||
Log 1, "set it in the config file to avoud this message";
|
Log 1, "set it in the config file to avoid this message";
|
||||||
$attr{global}{nofork}=1;
|
$attr{global}{nofork}=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +660,20 @@ AnalyzeCommandChain($$)
|
|||||||
my ($c, $cmd) = @_;
|
my ($c, $cmd) = @_;
|
||||||
my @ret;
|
my @ret;
|
||||||
|
|
||||||
|
if($cmd =~ m/^[ \t]*(#.*)?$/) { # Save comments
|
||||||
|
if(!$init_done) {
|
||||||
|
if($currcfgfile ne AttrVal("global", "statefile", "")) {
|
||||||
|
my $nr = $devcount++;
|
||||||
|
$comments{$nr}{TEXT} = $cmd;
|
||||||
|
$comments{$nr}{CFGFN} = $currcfgfile
|
||||||
|
if($currcfgfile ne AttrVal("global", "configfile", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
$cmd =~ s/#.*$//s;
|
$cmd =~ s/#.*$//s;
|
||||||
|
|
||||||
$cmd =~ s/;;/SeMiCoLoN/g;
|
$cmd =~ s/;;/SeMiCoLoN/g;
|
||||||
foreach my $subcmd (split(";", $cmd)) {
|
foreach my $subcmd (split(";", $cmd)) {
|
||||||
$subcmd =~ s/SeMiCoLoN/;/g;
|
$subcmd =~ s/SeMiCoLoN/;/g;
|
||||||
@@ -834,11 +849,23 @@ CommandInclude($$)
|
|||||||
my ($cl, $arg) = @_;
|
my ($cl, $arg) = @_;
|
||||||
my $fh;
|
my $fh;
|
||||||
my @ret;
|
my @ret;
|
||||||
|
my $oldcfgfile;
|
||||||
|
|
||||||
if(!open($fh, $arg)) {
|
if(!open($fh, $arg)) {
|
||||||
return "Can't open $arg: $!";
|
return "Can't open $arg: $!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!$init_done &&
|
||||||
|
$arg ne AttrVal("global", "statefile", "") &&
|
||||||
|
$arg ne AttrVal("global", "configfile", "")) {
|
||||||
|
my $nr = $devcount++;
|
||||||
|
$comments{$nr}{TEXT} = "include $arg";
|
||||||
|
$comments{$nr}{CFGFN} = $currcfgfile
|
||||||
|
if($currcfgfile ne AttrVal("global", "configfile", ""));
|
||||||
|
}
|
||||||
|
$oldcfgfile = $currcfgfile;
|
||||||
|
$currcfgfile = $arg;
|
||||||
|
|
||||||
my $bigcmd = "";
|
my $bigcmd = "";
|
||||||
$rcvdquit = 0;
|
$rcvdquit = 0;
|
||||||
while(my $l = <$fh>) {
|
while(my $l = <$fh>) {
|
||||||
@@ -854,6 +881,7 @@ CommandInclude($$)
|
|||||||
last if($rcvdquit);
|
last if($rcvdquit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
$currcfgfile = $oldcfgfile;
|
||||||
close($fh);
|
close($fh);
|
||||||
return join("\n", @ret) if(@ret);
|
return join("\n", @ret) if(@ret);
|
||||||
return undef;
|
return undef;
|
||||||
@@ -1012,31 +1040,58 @@ CommandSave($$)
|
|||||||
if(!open(SFH, ">$param")) {
|
if(!open(SFH, ">$param")) {
|
||||||
return "Cannot open $param: $!";
|
return "Cannot open $param: $!";
|
||||||
}
|
}
|
||||||
|
my %fh = ("configfile" => *SFH);
|
||||||
|
|
||||||
foreach my $d (sort { $defs{$a}{NR} <=> $defs{$b}{NR} } keys %defs) {
|
my %devByNr;
|
||||||
next if($defs{$d}{TEMPORARY} || # e.g. WEBPGM connections
|
map { $devByNr{$defs{$_}{NR}} = $_ } keys %defs;
|
||||||
$defs{$d}{VOLATILE}); # e.g at, will be saved to the statefile
|
|
||||||
|
for(my $i = 0; $i < $devcount; $i++) {
|
||||||
|
|
||||||
|
my ($h, $d);
|
||||||
|
if($comments{$i}) {
|
||||||
|
$h = $comments{$i};
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$d = $devByNr{$i};
|
||||||
|
next if(!defined($d) ||
|
||||||
|
$defs{$d}{TEMPORARY} || # e.g. WEBPGM connections
|
||||||
|
$defs{$d}{VOLATILE}); # e.g at, will be saved to the statefile
|
||||||
|
$h = $defs{$d};
|
||||||
|
}
|
||||||
|
|
||||||
|
my $cfgfile = $h->{CFGFN} ? $h->{CFGFN} : "configfile";
|
||||||
|
my $fh = $fh{$cfgfile};
|
||||||
|
if(!$fh) {
|
||||||
|
return "Can't open $cfgfile: $!" if(!(open($fh, ">$cfgfile")));
|
||||||
|
$fh{$cfgfile} = $fh;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!defined($d)) {
|
||||||
|
print $fh $h->{TEXT},"\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
if($d ne "global") {
|
if($d ne "global") {
|
||||||
if($defs{$d}{DEF}) {
|
if($defs{$d}{DEF}) {
|
||||||
my $def = $defs{$d}{DEF};
|
my $def = $defs{$d}{DEF};
|
||||||
$def =~ s/;/;;/g;
|
$def =~ s/;/;;/g;
|
||||||
print SFH "\ndefine $d $defs{$d}{TYPE} $def\n";
|
print $fh "define $d $defs{$d}{TYPE} $def\n";
|
||||||
} else {
|
} else {
|
||||||
print SFH "\ndefine $d $defs{$d}{TYPE}\n";
|
print $fh "define $d $defs{$d}{TYPE}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach my $a (sort keys %{$attr{$d}}) {
|
foreach my $a (sort keys %{$attr{$d}}) {
|
||||||
next if($d eq "global" &&
|
next if($d eq "global" &&
|
||||||
($a eq "configfile" || $a eq "version"));
|
($a eq "configfile" || $a eq "version"));
|
||||||
print SFH "attr $d $a $attr{$d}{$a}\n";
|
print $fh "attr $d $a $attr{$d}{$a}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print SFH "include $attr{global}{lastinclude}\n"
|
print SFH "include $attr{global}{lastinclude}\n"
|
||||||
if($attr{global}{lastinclude});
|
if($attr{global}{lastinclude});
|
||||||
|
|
||||||
|
foreach my $fh (values %fh) {
|
||||||
close(SFH);
|
close($fh);
|
||||||
|
}
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1193,6 +1248,8 @@ CommandDefine($$)
|
|||||||
$hash{STATE} = "???";
|
$hash{STATE} = "???";
|
||||||
$hash{DEF} = $a[2] if(int(@a) > 2);
|
$hash{DEF} = $a[2] if(int(@a) > 2);
|
||||||
$hash{NR} = $devcount++;
|
$hash{NR} = $devcount++;
|
||||||
|
$hash{CFGFN} = $currcfgfile
|
||||||
|
if($currcfgfile ne AttrVal("global", "configfile", ""));
|
||||||
|
|
||||||
# If the device wants to issue initialization gets/sets, then it needs to be
|
# If the device wants to issue initialization gets/sets, then it needs to be
|
||||||
# in the global hash.
|
# in the global hash.
|
||||||
|
|||||||
23
test/fhem-eib.cfg
Normal file
23
test/fhem-eib.cfg
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
attr global logfile -
|
||||||
|
attr global modpath .
|
||||||
|
attr global port 7072 global
|
||||||
|
attr global statefile test/fhem-eib.save
|
||||||
|
attr global verbose 5
|
||||||
|
|
||||||
|
define web FHEMWEB 8083 global
|
||||||
|
attr web fwmodpath webfrontend/pgm2
|
||||||
|
|
||||||
|
define tul TUL eibd:marvin 1.1.249
|
||||||
|
|
||||||
|
define Lampe1 EIB 0/0/1
|
||||||
|
define Lampe2 EIB 0/0/2 0/0/3
|
||||||
|
|
||||||
|
define LightSens EIB 0/0/250
|
||||||
|
attr LightSens dummy 1
|
||||||
|
attr LightSens model lightsensor
|
||||||
|
#attr LightSens model date
|
||||||
|
|
||||||
|
attr Lampe1 webCmd on:off:on-for-timer 10
|
||||||
|
|
||||||
|
get Lampe1 value
|
||||||
|
get Lampe2 value
|
||||||
@@ -417,6 +417,7 @@ FW_AnswerCall($)
|
|||||||
|
|
||||||
if($FW_inform) { # Longpoll header
|
if($FW_inform) { # Longpoll header
|
||||||
$defs{$FW_cname}{inform} = $FW_room;
|
$defs{$FW_cname}{inform} = $FW_room;
|
||||||
|
# NTFY_ORDER is larger than the normal order (50-)
|
||||||
$defs{$FW_cname}{NTFY_ORDER} = $FW_cname; # else notifyfn won't be called
|
$defs{$FW_cname}{NTFY_ORDER} = $FW_cname; # else notifyfn won't be called
|
||||||
my $c = $defs{$FW_cname}{CD};
|
my $c = $defs{$FW_cname}{CD};
|
||||||
print $c "HTTP/1.1 200 OK\r\n",
|
print $c "HTTP/1.1 200 OK\r\n",
|
||||||
@@ -1524,8 +1525,9 @@ FW_style($$)
|
|||||||
binmode (FH);
|
binmode (FH);
|
||||||
print FH $FW_data;
|
print FH $FW_data;
|
||||||
close(FH);
|
close(FH);
|
||||||
FW_style("style list", "Saved the file $fName");
|
my $ret = FW_fC("rereadcfg") if($fName eq $attr{global}{configfile});
|
||||||
FW_fC("rereadcfg") if($fName eq $attr{global}{configfile});
|
$ret = ($ret ? "<h3>ERROR:</h3><b>$ret</b>" : "Saved the file $fName");
|
||||||
|
FW_style("style list", $ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1814,6 +1816,7 @@ FW_Notify($$)
|
|||||||
my ($allSet, $cmdlist, $txt) = FW_devState($dn, "");
|
my ($allSet, $cmdlist, $txt) = FW_devState($dn, "");
|
||||||
($FW_wname, $FW_ME, $FW_longpoll, $FW_ss, $FW_tp) = @old;
|
($FW_wname, $FW_ME, $FW_longpoll, $FW_ss, $FW_tp) = @old;
|
||||||
|
|
||||||
|
# Collect multiple changes (e.g. from noties) into one message
|
||||||
$ntfy->{INFORMBUF} = "" if(!defined($ntfy->{INFORMBUF}));
|
$ntfy->{INFORMBUF} = "" if(!defined($ntfy->{INFORMBUF}));
|
||||||
$ntfy->{INFORMBUF} .= "$dn;$dev->{STATE};$txt\n";
|
$ntfy->{INFORMBUF} .= "$dn;$dev->{STATE};$txt\n";
|
||||||
RemoveInternalTimer($ln);
|
RemoveInternalTimer($ln);
|
||||||
@@ -1827,6 +1830,7 @@ FW_FlushInform($)
|
|||||||
{
|
{
|
||||||
my ($name) = @_;
|
my ($name) = @_;
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
|
return if(!$hash);
|
||||||
my $c = $hash->{CD};
|
my $c = $hash->{CD};
|
||||||
print $c $hash->{INFORMBUF};
|
print $c $hash->{INFORMBUF};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user