mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-04 22:19:38 +00:00
MAXLAN: support ondemand mode
git-svn-id: https://svn.fhem.de/fhem/trunk@2255 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
ac9c934bc1
commit
d1631c6de3
@ -10,8 +10,8 @@ use POSIX;
|
|||||||
|
|
||||||
sub MAXLAN_Parse($$);
|
sub MAXLAN_Parse($$);
|
||||||
sub MAXLAN_Read($);
|
sub MAXLAN_Read($);
|
||||||
sub MAXLAN_Write($$);
|
sub MAXLAN_Write(@);
|
||||||
sub MAXLAN_ReadAnswer($);
|
sub MAXLAN_ReadSingleResponse($$);
|
||||||
sub MAXLAN_SimpleWrite(@);
|
sub MAXLAN_SimpleWrite(@);
|
||||||
sub MAXLAN_Poll($);
|
sub MAXLAN_Poll($);
|
||||||
sub MAXLAN_SendDeviceCmd($$);
|
sub MAXLAN_SendDeviceCmd($$);
|
||||||
@ -29,8 +29,7 @@ my %device_types = (
|
|||||||
|
|
||||||
my @boost_durations = (0, 5, 10, 15, 20, 25, 30, 60);
|
my @boost_durations = (0, 5, 10, 15, 20, 25, 30, 60);
|
||||||
|
|
||||||
#Time after which we reconnect after a failed connection attempt
|
my $reconnect_interval = 2; #seconds
|
||||||
my $reconnect_interval = 5; #seconds
|
|
||||||
|
|
||||||
#the time it takes after sending one command till we see its effect in the L: response
|
#the time it takes after sending one command till we see its effect in the L: response
|
||||||
my $roundtriptime = 3; #seconds
|
my $roundtriptime = 3; #seconds
|
||||||
@ -49,7 +48,6 @@ MAXLAN_Initialize($)
|
|||||||
|
|
||||||
# Provider
|
# Provider
|
||||||
$hash->{ReadFn} = "MAXLAN_Read";
|
$hash->{ReadFn} = "MAXLAN_Read";
|
||||||
$hash->{WriteFn} = "MAXLAN_Write";
|
|
||||||
$hash->{SetFn} = "MAXLAN_Set";
|
$hash->{SetFn} = "MAXLAN_Set";
|
||||||
$hash->{Clients} = ":MAX:";
|
$hash->{Clients} = ":MAX:";
|
||||||
my %mc = (
|
my %mc = (
|
||||||
@ -71,15 +69,15 @@ MAXLAN_Define($$)
|
|||||||
my ($hash, $def) = @_;
|
my ($hash, $def) = @_;
|
||||||
my @a = split("[ \t][ \t]*", $def);
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
|
|
||||||
if(@a < 3 or @a > 4) {
|
if(@a < 3) {
|
||||||
my $msg = "wrong syntax: define <name> MAXLAN ip[:port] [pollintervall]";
|
my $msg = "wrong syntax: define <name> MAXLAN ip[:port] [pollintervall [ondemand]]";
|
||||||
Log 2, $msg;
|
Log 2, $msg;
|
||||||
return $msg;
|
return $msg;
|
||||||
}
|
}
|
||||||
DevIo_CloseDev($hash);
|
|
||||||
|
|
||||||
my $name = $a[0];
|
my $name = shift @a;
|
||||||
my $dev = $a[2];
|
shift @a;
|
||||||
|
my $dev = shift @a;
|
||||||
$dev .= ":62910" if($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/);
|
$dev .= ":62910" if($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/);
|
||||||
|
|
||||||
if($dev eq "none") {
|
if($dev eq "none") {
|
||||||
@ -87,37 +85,86 @@ MAXLAN_Define($$)
|
|||||||
$attr{$name}{dummy} = 1;
|
$attr{$name}{dummy} = 1;
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
$hash->{INTERVAL} = $defaultPollInterval;
|
||||||
|
$hash->{persistent} = 1;
|
||||||
|
if(@a) {
|
||||||
|
$hash->{INTERVAL} = shift @a;
|
||||||
|
while(@a) {
|
||||||
|
my $arg = shift @a;
|
||||||
|
if($arg eq "ondemand") {
|
||||||
|
$hash->{persistent} = 0;
|
||||||
|
} else {
|
||||||
|
my $msg = "unknown argument $arg";
|
||||||
|
Log 1, $msg;
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash->{cubeTimeDifference} = 99999;
|
||||||
|
$hash->{pairmode} = 0;
|
||||||
$hash->{PARTIAL} = "";
|
$hash->{PARTIAL} = "";
|
||||||
$hash->{DeviceName} = $dev;
|
$hash->{DeviceName} = $dev;
|
||||||
$hash->{INTERVAL} = @a > 3 ? $a[3] : $defaultPollInterval;
|
|
||||||
#This interface is shared with 14_CUL_MAX.pm
|
#This interface is shared with 14_CUL_MAX.pm
|
||||||
$hash->{SendDeviceCmd} = \&MAXLAN_SendDeviceCmd;
|
$hash->{SendDeviceCmd} = \&MAXLAN_SendDeviceCmd;
|
||||||
$hash->{RemoveDevice} = \&MAXLAN_RemoveDevice;
|
$hash->{RemoveDevice} = \&MAXLAN_RemoveDevice;
|
||||||
|
|
||||||
|
#Wait until all device definitions have been loaded
|
||||||
MAXLAN_Connect($hash);
|
InternalTimer(gettimeofday()+1, "MAXLAN_Poll", $hash, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
MAXLAN_IsConnected($)
|
||||||
|
{
|
||||||
|
return exists($_[0]->{FD});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#Disconnects from the Cube. It is safe to call this when already disconnected.
|
||||||
|
sub
|
||||||
|
MAXLAN_Disconnect($)
|
||||||
|
{
|
||||||
|
my $hash = shift;
|
||||||
|
Log 5, "MAXLAN_Disconnect";
|
||||||
|
#All operations here are no-op if already disconnected
|
||||||
|
DevIo_CloseDev($hash);
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
#Connects to the Cube. If already connected, disconnects first.
|
||||||
sub
|
sub
|
||||||
MAXLAN_Connect($)
|
MAXLAN_Connect($)
|
||||||
{
|
{
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
|
|
||||||
#Close connection (if there is a previous one)
|
return if(MAXLAN_IsConnected($hash));
|
||||||
DevIo_CloseDev($hash);
|
|
||||||
|
|
||||||
RemoveInternalTimer($hash);
|
|
||||||
|
|
||||||
$hash->{gothello} = 0;
|
|
||||||
|
|
||||||
delete($hash->{NEXT_OPEN}); #work around the connection rate limiter in DevIo
|
delete($hash->{NEXT_OPEN}); #work around the connection rate limiter in DevIo
|
||||||
|
my $ret = DevIo_OpenDev($hash, 0, "");
|
||||||
my $ret = DevIo_OpenDev($hash, 0, "MAXLAN_DoInit");
|
if(!MAXLAN_IsConnected($hash)) {
|
||||||
if($hash->{STATE} ne "opened"){
|
my $msg = "MAXLAN_Connect: Could not connect";
|
||||||
Log 3, "Scheduling reconnect attempt in $reconnect_interval seconds";
|
Log 2, $msg;
|
||||||
InternalTimer(gettimeofday()+$reconnect_interval, "MAXLAN_Connect", $hash, 0);
|
return $msg;
|
||||||
}
|
}
|
||||||
return $ret;
|
|
||||||
|
#Read initial configuration data
|
||||||
|
MAXLAN_ExpectAnswer($hash,"H:");
|
||||||
|
MAXLAN_ExpectAnswer($hash,"M:");
|
||||||
|
my $rmsg;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
#Receive one "C:" per device
|
||||||
|
$rmsg = MAXLAN_ReadSingleResponse($hash, 1);
|
||||||
|
MAXLAN_Parse($hash, $rmsg);
|
||||||
|
} until($rmsg =~ m/^L:/);
|
||||||
|
#At the end, the cube sends a "L:"
|
||||||
|
|
||||||
|
#Handle deferred setting of time
|
||||||
|
if(AttrVal($hash->{NAME},"set-clock-on-init","1") && $hash->{cubeTimeDifference} > 1) {
|
||||||
|
MAXLAN_Set($hash,$hash->{NAME},"clock");
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -126,9 +173,8 @@ sub
|
|||||||
MAXLAN_Undef($$)
|
MAXLAN_Undef($$)
|
||||||
{
|
{
|
||||||
my ($hash, $arg) = @_;
|
my ($hash, $arg) = @_;
|
||||||
RemoveInternalTimer($hash);
|
#MAXLAN_Write($hash,"q:"); #unnecessary
|
||||||
MAXLAN_Write($hash,"q:");
|
MAXLAN_Disconnect($hash);
|
||||||
DevIo_CloseDev($hash);
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,11 +188,11 @@ MAXLAN_Set($@)
|
|||||||
|
|
||||||
if($setting eq "pairmode"){
|
if($setting eq "pairmode"){
|
||||||
if(@args > 0 and $args[0] eq "cancel") {
|
if(@args > 0 and $args[0] eq "cancel") {
|
||||||
MAXLAN_Write($hash,"x:");
|
MAXLAN_Write($hash,"x:", "N:");
|
||||||
return MAXLAN_ExpectAnswer($hash,"N:");
|
|
||||||
} else {
|
} else {
|
||||||
my $duration = 60;
|
my $duration = 60;
|
||||||
$duration = $args[0] if(@args > 0);
|
$duration = $args[0] if(@args > 0);
|
||||||
|
$hash->{pairmode} = 1;
|
||||||
MAXLAN_Write($hash,"n:".sprintf("%04x",$duration));
|
MAXLAN_Write($hash,"n:".sprintf("%04x",$duration));
|
||||||
$hash->{STATE} = "pairing";
|
$hash->{STATE} = "pairing";
|
||||||
}
|
}
|
||||||
@ -154,13 +200,7 @@ MAXLAN_Set($@)
|
|||||||
}elsif($setting eq "raw"){
|
}elsif($setting eq "raw"){
|
||||||
MAXLAN_Write($hash,$args[0]);
|
MAXLAN_Write($hash,$args[0]);
|
||||||
|
|
||||||
}elsif($setting eq "clock"){
|
}elsif($setting eq "clock") {
|
||||||
if(!exists($hash->{rfaddr})){
|
|
||||||
Log 5, "Defering the setting of time until after hello";
|
|
||||||
$hash->{setTimeOnHello} = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#This encodes the winter/summer timezones, its meaning is not entirely clear
|
#This encodes the winter/summer timezones, its meaning is not entirely clear
|
||||||
my $timezones = "Q0VUAAAKAAMAAA4QQ0VTVAADAAIAABwg";
|
my $timezones = "Q0VUAAAKAAMAAA4QQ0VTVAADAAIAABwg";
|
||||||
|
|
||||||
@ -168,19 +208,16 @@ MAXLAN_Set($@)
|
|||||||
#time format the cube uses. Something based on ntp I guess. Maybe this only works in GMT+1?
|
#time format the cube uses. Something based on ntp I guess. Maybe this only works in GMT+1?
|
||||||
my $time = time()-946684774;
|
my $time = time()-946684774;
|
||||||
my $rmsg = "v:".$timezones.",".sprintf("%08x",$time);
|
my $rmsg = "v:".$timezones.",".sprintf("%08x",$time);
|
||||||
MAXLAN_Write($hash,$rmsg);
|
my $ret = MAXLAN_Write($hash,$rmsg, "A:");
|
||||||
my $answer = MAXLAN_ReadAnswer($hash);
|
Dispatch($hash, "MAX,CubeClockState,$hash->{rfaddr},1", {RAWMSG => $rmsg}) if(!$ret);
|
||||||
if($answer ne "A:"){
|
return $ret;
|
||||||
Log 1, "Failed to set clock, answer was $answer, expected A:";
|
|
||||||
}else{
|
|
||||||
Dispatch($hash, "MAX,CubeClockState,$hash->{rfaddr},1", {RAWMSG => $rmsg});
|
|
||||||
}
|
|
||||||
|
|
||||||
}elsif($setting eq "factoryReset") {
|
}elsif($setting eq "factoryReset") {
|
||||||
MAXLAN_RequestReset($hash);
|
MAXLAN_RequestReset($hash);
|
||||||
|
|
||||||
}elsif($setting eq "reconnect") {
|
}elsif($setting eq "reconnect") {
|
||||||
MAXLAN_Connect($hash);
|
MAXLAN_Disconnect($hash);
|
||||||
|
MAXLAN_Connect($hash) if($hash->{persistent});
|
||||||
}else{
|
}else{
|
||||||
return "Unknown argument $setting, choose one of pairmode raw clock factoryReset reconnect";
|
return "Unknown argument $setting, choose one of pairmode raw clock factoryReset reconnect";
|
||||||
}
|
}
|
||||||
@ -191,8 +228,8 @@ sub
|
|||||||
MAXLAN_ExpectAnswer($$)
|
MAXLAN_ExpectAnswer($$)
|
||||||
{
|
{
|
||||||
my ($hash,$expectedanswer) = @_;
|
my ($hash,$expectedanswer) = @_;
|
||||||
my $rmsg = MAXLAN_ReadAnswer($hash);
|
my $rmsg = MAXLAN_ReadSingleResponse($hash, 1);
|
||||||
return "Error while receiving" if(!defined($rmsg)); #error is already logged in MAXLAN_ReadAnswer
|
return "Error while receiving" if(!defined($rmsg)); #error is already logged in MAXLAN_ReadSingleResponse
|
||||||
|
|
||||||
my $ret = undef;
|
my $ret = undef;
|
||||||
if($rmsg !~ m/^$expectedanswer/) {
|
if($rmsg !~ m/^$expectedanswer/) {
|
||||||
@ -206,18 +243,19 @@ MAXLAN_ExpectAnswer($$)
|
|||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub
|
sub
|
||||||
MAXLAN_ReadAnswer($)
|
MAXLAN_ReadSingleResponse($$)
|
||||||
{
|
{
|
||||||
my ($hash) = @_;
|
my ($hash,$waitForResponse) = @_;
|
||||||
|
|
||||||
#Read until we have a complete line
|
#Read until we have a complete line
|
||||||
until($hash->{PARTIAL} =~ m/\n/) {
|
until($hash->{PARTIAL} =~ m/\n/) {
|
||||||
my $buf = DevIo_SimpleRead($hash);
|
my $buf = DevIo_SimpleRead($hash);
|
||||||
if(!defined($buf)){
|
if(!defined($buf)){
|
||||||
Log 1, "MAXLAN_ReadAnswer: error during read";
|
Log 1, "MAXLAN_ReadSingleResponse: error during read";
|
||||||
return undef; #error occured
|
return undef; #error occured
|
||||||
}
|
}
|
||||||
$hash->{PARTIAL} .= $buf;
|
$hash->{PARTIAL} .= $buf;
|
||||||
|
last if(!$waitForResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $rmsg;
|
my $rmsg;
|
||||||
@ -229,12 +267,18 @@ MAXLAN_ReadAnswer($)
|
|||||||
my %lhash;
|
my %lhash;
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
|
#Sends given msg and checks for/parses the answer
|
||||||
sub
|
sub
|
||||||
MAXLAN_Write($$)
|
MAXLAN_Write(@)
|
||||||
{
|
{
|
||||||
my ($hash,$msg) = @_;
|
my ($hash,$msg,$expectedAnswer) = @_;
|
||||||
|
my $ret = undef;
|
||||||
|
|
||||||
|
MAXLAN_Connect($hash); #It's a no-op if already connected
|
||||||
MAXLAN_SimpleWrite($hash, $msg);
|
MAXLAN_SimpleWrite($hash, $msg);
|
||||||
|
$ret = MAXLAN_ExpectAnswer($hash, $expectedAnswer) if($expectedAnswer);
|
||||||
|
MAXLAN_Disconnect($hash) if(!$hash->{persistent} && !$hash->{pairmode});
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
@ -244,18 +288,11 @@ MAXLAN_Read($)
|
|||||||
{
|
{
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
my $buf = DevIo_SimpleRead($hash);
|
while(1) {
|
||||||
return "" if(!defined($buf));
|
my $rmsg = MAXLAN_ReadSingleResponse($hash, 0);
|
||||||
my $name = $hash->{NAME};
|
last if(!$rmsg);
|
||||||
|
Log 2, "Unsolicated response from Cube: $rmsg";
|
||||||
$hash->{PARTIAL} .= $buf;
|
MAXLAN_Parse($hash, $rmsg);
|
||||||
|
|
||||||
#while we have a complete line
|
|
||||||
while($hash->{PARTIAL} =~ m/\n/) {
|
|
||||||
my $rmsg;
|
|
||||||
($rmsg,$hash->{PARTIAL}) = split("\n", $hash->{PARTIAL}, 2);
|
|
||||||
$rmsg =~ s/\r//;#remove \r
|
|
||||||
MAXLAN_Parse($hash, $rmsg) if($rmsg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,26 +346,8 @@ MAXLAN_SendMetadata($)
|
|||||||
for(my $i=0;$i < $numpackages; $i++) {
|
for(my $i=0;$i < $numpackages; $i++) {
|
||||||
my $package = substr($metadata,$i*$blocksize,$blocksize);
|
my $package = substr($metadata,$i*$blocksize,$blocksize);
|
||||||
|
|
||||||
MAXLAN_Write($hash,"m:".sprintf("%02d",$i).",".$package);
|
return MAXLAN_Write($hash,"m:".sprintf("%02d",$i).",".$package, "A:");
|
||||||
my $answer = MAXLAN_ReadAnswer($hash);
|
|
||||||
if($answer ne "A:"){
|
|
||||||
Log 1, "SendMetadata got response $answer, expected 'A:'";
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub
|
|
||||||
MAXLAN_FinishConnect($)
|
|
||||||
{
|
|
||||||
my ($hash) = @_;
|
|
||||||
#Handle deferred setting of time (L: is the last response after connection before the cube starts to idle)
|
|
||||||
if(defined($hash->{setTimeOnHello})) {
|
|
||||||
MAXLAN_Set($hash,$hash->{NAME},"clock");
|
|
||||||
delete $hash->{setTimeOnHello};
|
|
||||||
}
|
|
||||||
#Enable polling timer
|
|
||||||
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "MAXLAN_Poll", $hash, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
@ -375,6 +394,7 @@ MAXLAN_Parse($$)
|
|||||||
+ $cubedatetime->{minute} - $min);
|
+ $cubedatetime->{minute} - $min);
|
||||||
Log 3, "Cube thinks it is $cubedatetime->{day}.$cubedatetime->{month}.$cubedatetime->{year} $cubedatetime->{hour}:$cubedatetime->{minute}";
|
Log 3, "Cube thinks it is $cubedatetime->{day}.$cubedatetime->{month}.$cubedatetime->{year} $cubedatetime->{hour}:$cubedatetime->{minute}";
|
||||||
Log 3, "Time difference is $difference minutes";
|
Log 3, "Time difference is $difference minutes";
|
||||||
|
$hash->{cubeTimeDifference} = $difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatch($hash, "MAX,define,$hash->{rfaddr},Cube,$hash->{serial},0,1", {RAWMSG => $rmsg});
|
Dispatch($hash, "MAX,define,$hash->{rfaddr},Cube,$hash->{serial},0,1", {RAWMSG => $rmsg});
|
||||||
@ -424,6 +444,7 @@ MAXLAN_Parse($$)
|
|||||||
$hash->{devices}[-1]->{serial} = $groupsdevices[$i+2];
|
$hash->{devices}[-1]->{serial} = $groupsdevices[$i+2];
|
||||||
$hash->{devices}[-1]->{name} = $groupsdevices[$i+3];
|
$hash->{devices}[-1]->{name} = $groupsdevices[$i+3];
|
||||||
$hash->{devices}[-1]->{groupid} = $groupsdevices[$i+4];
|
$hash->{devices}[-1]->{groupid} = $groupsdevices[$i+4];
|
||||||
|
#Dispatch($hash, "MAX,define,$hash->{devices}[-1]->{addr},$device_types{$hash->{devices}[-1]->{type}},$hash->{devices}[-1]->{serial},$hash->{devices}[-1]->{groupid},1", {RAWMSG => $rmsg});
|
||||||
}
|
}
|
||||||
|
|
||||||
#Log $ll5, "Got Metadata, hash: ".Dumper($hash);
|
#Log $ll5, "Got Metadata, hash: ".Dumper($hash);
|
||||||
@ -525,11 +546,6 @@ MAXLAN_Parse($$)
|
|||||||
$bindata=substr($bindata,$len+1); #+1 because the len field is not counted
|
$bindata=substr($bindata,$len+1); #+1 because the len field is not counted
|
||||||
} # while(length($bindata))
|
} # while(length($bindata))
|
||||||
|
|
||||||
if(!$hash->{gothello}) {
|
|
||||||
# "L:..." is the last response after connection before the cube starts to idle
|
|
||||||
$hash->{gothello} = 1;
|
|
||||||
MAXLAN_FinishConnect($hash);
|
|
||||||
}
|
|
||||||
}elsif($cmd eq "N"){#New device paired
|
}elsif($cmd eq "N"){#New device paired
|
||||||
if(@args==0){
|
if(@args==0){
|
||||||
$hash->{STATE} = "initalized"; #pairing ended
|
$hash->{STATE} = "initalized"; #pairing ended
|
||||||
@ -539,20 +555,20 @@ MAXLAN_Parse($$)
|
|||||||
Log 2, "Paired new device, type $device_types{$type}, addr $addr, serial $serial";
|
Log 2, "Paired new device, type $device_types{$type}, addr $addr, serial $serial";
|
||||||
Dispatch($hash, "MAX,define,$addr,$device_types{$type},$serial,0,1", {RAWMSG => $rmsg});
|
Dispatch($hash, "MAX,define,$addr,$device_types{$type},$serial,0,1", {RAWMSG => $rmsg});
|
||||||
|
|
||||||
|
$hash->{pairmode} = 0;
|
||||||
#After a device has been paired, it automatically appears in the "L" and "C" commands,
|
#After a device has been paired, it automatically appears in the "L" and "C" commands,
|
||||||
MAXLAN_RequestConfiguration($hash,$addr);
|
MAXLAN_RequestConfiguration($hash,$addr);
|
||||||
} elsif($cmd eq "A"){#Acknowledged
|
} elsif($cmd eq "A"){#Acknowledged
|
||||||
Log 3, "Got stray Acknowledged from cube, this should be read by MAXLAN_ReadAnswer";
|
|
||||||
|
|
||||||
} elsif($cmd eq "S"){#Response to s:
|
} elsif($cmd eq "S"){#Response to s:
|
||||||
my $dutycycle = hex($args[0]); #number of command send over the air
|
$hash->{dutycycle} = hex($args[0]); #number of command send over the air
|
||||||
my $discarded = $args[1];
|
my $discarded = $args[1];
|
||||||
my $freememoryslot = $args[2];
|
$hash->{freememoryslot} = $args[2];
|
||||||
Log 5, "dutycyle $dutycycle, freememoryslot $freememoryslot";
|
Log 5, "dutycyle $hash->{dutycycle}, freememoryslot $hash->{freememoryslot}";
|
||||||
|
|
||||||
Log 3, "1% rule: we sent too much, cmd is now in queue" if($dutycycle == 100 && $freememoryslot > 0);
|
Log 3, "1% rule: we sent too much, cmd is now in queue" if($hash->{dutycycle} == 100 && $hash->{freememoryslot} > 0);
|
||||||
Log 3, "1% rule: we sent too much, queue is full, cmd discarded" if($dutycycle == 100 && $freememoryslot == 0);
|
Log 2, "1% rule: we sent too much, queue is full" if($hash->{dutycycle} == 100 && $hash->{freememoryslot} == 0);
|
||||||
Log 3, "Command was discarded" if($discarded);
|
Log 2, "Command was discarded" if($discarded);
|
||||||
return "Command was discarded" if($discarded);
|
return "Command was discarded" if($discarded);
|
||||||
} else {
|
} else {
|
||||||
Log $ll5, "$name Unknown command $cmd";
|
Log $ll5, "$name Unknown command $cmd";
|
||||||
@ -577,7 +593,7 @@ MAXLAN_SimpleWrite(@)
|
|||||||
#TODO: none of those conditions detect if the connection is actually lost!
|
#TODO: none of those conditions detect if the connection is actually lost!
|
||||||
if(!$hash->{TCPDev} || !defined($ret) || !$hash->{TCPDev}->connected) {
|
if(!$hash->{TCPDev} || !defined($ret) || !$hash->{TCPDev}->connected) {
|
||||||
Log GetLogLevel($name,1), 'MAXLAN_SimpleWrite failed';
|
Log GetLogLevel($name,1), 'MAXLAN_SimpleWrite failed';
|
||||||
MAXLAN_Connect($hash);
|
MAXLAN_Disconnect($hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,7 +602,6 @@ sub
|
|||||||
MAXLAN_DoInit($)
|
MAXLAN_DoInit($)
|
||||||
{
|
{
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
$hash->{gothello} = 0;
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,8 +609,7 @@ sub
|
|||||||
MAXLAN_RequestList($)
|
MAXLAN_RequestList($)
|
||||||
{
|
{
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
MAXLAN_Write($hash, "l:");
|
return MAXLAN_Write($hash, "l:", "L:");
|
||||||
return MAXLAN_ExpectAnswer($hash, "L:");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
@ -604,21 +618,32 @@ MAXLAN_Poll($)
|
|||||||
{
|
{
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
|
|
||||||
return if(!$hash->{FD});
|
if(MAXLAN_IsConnected($hash)) {
|
||||||
|
my $ret = MAXLAN_RequestList($hash);
|
||||||
if(!defined(MAXLAN_RequestList($hash))) {
|
Log 1, "MAXLAN_Poll: Did not get any answer" if($ret);
|
||||||
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "MAXLAN_Poll", $hash, 0);
|
|
||||||
} else {
|
} else {
|
||||||
Log 1, "MAXLAN_Poll: Did not get any answer";
|
#Connecting gives us a RequestList for free
|
||||||
|
my $ret = MAXLAN_Connect($hash);
|
||||||
|
if($ret) {
|
||||||
|
#Connecting failed
|
||||||
|
InternalTimer(gettimeofday()+$reconnect_interval, "MAXLAN_Poll", $hash, 0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$hash->{persistent} && !$hash->{pairmode}) {
|
||||||
|
MAXLAN_Disconnect($hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "MAXLAN_Poll", $hash, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#This only works for a device that got just paired
|
||||||
sub
|
sub
|
||||||
MAXLAN_RequestConfiguration($$)
|
MAXLAN_RequestConfiguration($$)
|
||||||
{
|
{
|
||||||
my ($hash,$addr) = @_;
|
my ($hash,$addr) = @_;
|
||||||
MAXLAN_Write($hash,"c:$addr");
|
return MAXLAN_Write($hash,"c:$addr", "C:");
|
||||||
MAXLAN_ExpectAnswer($hash, "C:");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Sends command to a device and waits for acknowledgment
|
#Sends command to a device and waits for acknowledgment
|
||||||
@ -626,19 +651,21 @@ sub
|
|||||||
MAXLAN_SendDeviceCmd($$)
|
MAXLAN_SendDeviceCmd($$)
|
||||||
{
|
{
|
||||||
my ($hash,$payload) = @_;
|
my ($hash,$payload) = @_;
|
||||||
MAXLAN_Write($hash,"s:".encode_base64($payload,""));
|
my $ret = MAXLAN_Write($hash,"s:".encode_base64($payload,""), "S:");
|
||||||
|
#Reschedule a poll in the near future after the cube will
|
||||||
|
#have gotten an answer
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
InternalTimer(gettimeofday()+$roundtriptime, "MAXLAN_Poll", $hash, 0);
|
InternalTimer(gettimeofday()+$roundtriptime, "MAXLAN_Poll", $hash, 0);
|
||||||
return MAXLAN_ExpectAnswer($hash, "S:");
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#Resets the cube, i.e. does a factory reset. All pairings will be lost.
|
#Resets the cube, i.e. do a factory reset. All pairings will be lost from the cube
|
||||||
|
#(but you will have to manually reset each individual device.
|
||||||
sub
|
sub
|
||||||
MAXLAN_RequestReset($)
|
MAXLAN_RequestReset($)
|
||||||
{
|
{
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
MAXLAN_Write($hash,"a:");
|
return MAXLAN_Write($hash,"a:", "A:");
|
||||||
MAXLAN_ExpectAnswer($hash, "A:");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Remove the device from the cube, i.e. deletes the pairing
|
#Remove the device from the cube, i.e. deletes the pairing
|
||||||
@ -646,8 +673,7 @@ sub
|
|||||||
MAXLAN_RemoveDevice($$)
|
MAXLAN_RemoveDevice($$)
|
||||||
{
|
{
|
||||||
my ($hash,$addr) = @_;
|
my ($hash,$addr) = @_;
|
||||||
MAXLAN_Write($hash,"t:1,1,".encode_base64(pack("H6",$addr),""));
|
return MAXLAN_Write($hash,"t:1,1,".encode_base64(pack("H6",$addr),""), "A:");
|
||||||
MAXLAN_ExpectAnswer($hash, "A:");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
@ -662,20 +688,22 @@ MAXLAN_RemoveDevice($$)
|
|||||||
The MAXLAN is the fhem module for the eQ-3 MAX! Cube LAN Gateway.
|
The MAXLAN is the fhem module for the eQ-3 MAX! Cube LAN Gateway.
|
||||||
<br><br>
|
<br><br>
|
||||||
The fhem module makes the MAX! "bus" accessible to fhem, automatically detecting paired MAX! devices. (The devices themselves are handled by the <a href="#MAX">MAX</a> module).<br>
|
The fhem module makes the MAX! "bus" accessible to fhem, automatically detecting paired MAX! devices. (The devices themselves are handled by the <a href="#MAX">MAX</a> module).<br>
|
||||||
The MAXLAN module keeps a persistant connection to the cube. The cube only allows one connection at a time, so neither the Max! Software or the
|
The MAXLAN module keeps a persistent connection to the cube. The cube only allows one connection at a time, so neither the Max! Software or the
|
||||||
Max! internet portal can be used at the same time.
|
Max! internet portal can be used at the same time.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<a name="MAXLANdefine"></a>
|
<a name="MAXLANdefine"></a>
|
||||||
<b>Define</b>
|
<b>Define</b>
|
||||||
<ul>
|
<ul>
|
||||||
<code>define <name> MAXLAN <ip-address>[:port] [<pollintervall>]</code><br>
|
<code>define <name> MAXLAN <ip-address>[:port] [<pollintervall> [ondemand]]</code><br>
|
||||||
<br>
|
<br>
|
||||||
port is 62910 by default. (If your Cube listens on port 80, you have to update the firmware with
|
port is 62910 by default. (If your Cube listens on port 80, you have to update the firmware with
|
||||||
the official MAX! software).
|
the official MAX! software).
|
||||||
If the ip-address is called none, then no device will be opened, so you
|
If the ip-address is called none, then no device will be opened, so you
|
||||||
can experiment without hardware attached.<br>
|
can experiment without hardware attached.<br>
|
||||||
The optional parameter <pollintervall> defines the time in seconds between each polling of data from the cube.<br>
|
The optional parameter <pollintervall> defines the time in seconds between each polling of data from the cube.<br>
|
||||||
|
You may provide the option <code>ondemand</code> forcing the MAXLAN module to tear-down the connection as often as possible
|
||||||
|
thus making the cube usable by other applications or the web portal.
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@ -689,7 +717,7 @@ Setting pairmode to "cancel" puts the cube out of pairing mode.</li>
|
|||||||
Sends the raw <data> to the cube.</li>
|
Sends the raw <data> to the cube.</li>
|
||||||
<li>clock<br>
|
<li>clock<br>
|
||||||
Sets the internal clock in the cube to the current system time of fhem's machine. You can add<br>
|
Sets the internal clock in the cube to the current system time of fhem's machine. You can add<br>
|
||||||
<code>set ml clock</code><br>
|
<code>attr ml set-clock-on-init</code><br>
|
||||||
to your fhem.cfg to do this automatically on startup.</li>
|
to your fhem.cfg to do this automatically on startup.</li>
|
||||||
<li>factorReset<br>
|
<li>factorReset<br>
|
||||||
Reset the cube to factory defaults.</li>
|
Reset the cube to factory defaults.</li>
|
||||||
@ -710,6 +738,8 @@ Setting pairmode to "cancel" puts the cube out of pairing mode.</li>
|
|||||||
<a name="MAXLANattr"></a>
|
<a name="MAXLANattr"></a>
|
||||||
<b>Attributes</b>
|
<b>Attributes</b>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>set-clock-on-init<br>
|
||||||
|
(Default: 1). Automatically call "set clock" after connecting to the cube.
|
||||||
<li><a href="#do_not_notify">do_not_notify</a></li><br>
|
<li><a href="#do_not_notify">do_not_notify</a></li><br>
|
||||||
<li><a href="#attrdummy">dummy</a></li><br>
|
<li><a href="#attrdummy">dummy</a></li><br>
|
||||||
<li><a href="#loglevel">loglevel</a></li><br>
|
<li><a href="#loglevel">loglevel</a></li><br>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user