MAXLAN: support ondemand mode

git-svn-id: https://svn.fhem.de/fhem/trunk@2255 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
mgehre 2012-12-02 23:28:00 +00:00
parent ac9c934bc1
commit d1631c6de3

View File

@ -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 &lt;name&gt; MAXLAN &lt;ip-address&gt;[:port] [&lt;pollintervall&gt;]</code><br> <code>define &lt;name&gt; MAXLAN &lt;ip-address&gt;[:port] [&lt;pollintervall&gt; [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 &lt;pollintervall&gt; defines the time in seconds between each polling of data from the cube.<br> The optional parameter &lt;pollintervall&gt; 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 &lt;data&gt; to the cube.</li> Sends the raw &lt;data&gt; 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>