mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-03 16:56:54 +00:00
38_CO20: identify devices by id / serial number
git-svn-id: https://svn.fhem.de/fhem/trunk@13992 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
4c0f7b6449
commit
771abe0589
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
# Do not insert empty lines here, update check depends on it.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- update: 38_CO20: identify devices by id / serial number
|
||||||
- update: 38_netatmo: dynamic update intervals for devices
|
- update: 38_netatmo: dynamic update intervals for devices
|
||||||
- update: 98_weekprofile: update reading profile_count after save profiles
|
- update: 98_weekprofile: update reading profile_count after save profiles
|
||||||
- feature: 98_weekprofile: new attribute widgetTranslations for translations
|
- feature: 98_weekprofile: new attribute widgetTranslations for translations
|
||||||
|
@ -27,8 +27,8 @@ CO20_Initialize($)
|
|||||||
$hash->{SetFn} = "CO20_Set";
|
$hash->{SetFn} = "CO20_Set";
|
||||||
$hash->{GetFn} = "CO20_Get";
|
$hash->{GetFn} = "CO20_Get";
|
||||||
$hash->{AttrFn} = "CO20_Attr";
|
$hash->{AttrFn} = "CO20_Attr";
|
||||||
$hash->{AttrList} = "disable:1 ".
|
$hash->{AttrList} = "disable:1,0 ".
|
||||||
"advanced:1 ".
|
"advanced:1,0 ".
|
||||||
"interval ".
|
"interval ".
|
||||||
"retries ".
|
"retries ".
|
||||||
"timeout ".
|
"timeout ".
|
||||||
@ -49,18 +49,35 @@ CO20_Define($$)
|
|||||||
delete $hash->{ID};
|
delete $hash->{ID};
|
||||||
|
|
||||||
my $name = $a[0];
|
my $name = $a[0];
|
||||||
|
#$hash->{ID} = undef;
|
||||||
|
$hash->{SERIALNUMBER} = undef;
|
||||||
|
$hash->{helper}{defined} = "none";
|
||||||
|
|
||||||
$hash->{tag} = undef;
|
if( defined($a[2]))
|
||||||
$hash->{ID} = $a[2] if( defined($a[2]));
|
{
|
||||||
|
if($a[2] =~ m/(\d.*):(\d.*)/)
|
||||||
|
{
|
||||||
|
$hash->{ID} = $a[2];
|
||||||
|
$hash->{helper}{defined} = "id";
|
||||||
|
}
|
||||||
|
elsif($a[2] =~ m/(\d.*)/)
|
||||||
|
{
|
||||||
|
$hash->{SERIALNUMBER} = $a[2];
|
||||||
|
$hash->{helper}{defined} = "serial";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$hash->{NAME} = $name;
|
$hash->{NAME} = $name;
|
||||||
|
|
||||||
$hash->{fail} = 0;
|
$hash->{FAIL} = 0;
|
||||||
$hash->{seq2} = 0x67;
|
$hash->{helper}{seq2} = 0x67;
|
||||||
$hash->{seq4} = 0x0001;
|
$hash->{helper}{seq4} = 0x0001;
|
||||||
|
|
||||||
$hash->{NOTIFYDEV} = "global";
|
$hash->{NOTIFYDEV} = "global";
|
||||||
|
|
||||||
|
$hash->{helper}{retries} = AttrVal($name,"retries",3);
|
||||||
|
$hash->{helper}{timeout} = AttrVal($name,"timeout",1000);
|
||||||
|
|
||||||
if( $init_done ) {
|
if( $init_done ) {
|
||||||
CO20_Disconnect($hash);
|
CO20_Disconnect($hash);
|
||||||
CO20_Connect($hash);
|
CO20_Connect($hash);
|
||||||
@ -148,30 +165,98 @@ CO20_Connect($)
|
|||||||
|
|
||||||
return undef if( AttrVal($name, "disable", 0 ) == 1 );
|
return undef if( AttrVal($name, "disable", 0 ) == 1 );
|
||||||
|
|
||||||
$hash->{USB} = Device::USB->new() if( !$hash->{USB} );
|
Log3 $name, 5, "$name: start CO20 connect";
|
||||||
|
|
||||||
if( $hash->{ID} && $hash->{ID} =~ m/(\d.*):(\d.*)/ ) {
|
delete $hash->{DEV};
|
||||||
|
Log3 $name, 5, "$name: delete CO20 dev";
|
||||||
|
|
||||||
|
$hash->{USB} = Device::USB->new() if( !$hash->{USB} );
|
||||||
|
Log3 $name, 3, "$name: CO20 USB connect";
|
||||||
|
|
||||||
|
if( $hash->{helper}{defined} eq "id" && $hash->{ID} && $hash->{ID} =~ m/(\d.*):(\d.*)/ ) {
|
||||||
my $dirname = $1;
|
my $dirname = $1;
|
||||||
my $filename = $2;
|
my $filename = $2;
|
||||||
delete $hash->{DEV};
|
foreach my $bus ($hash->{USB}->list_busses())
|
||||||
foreach my $bus ($hash->{USB}->list_busses()) {
|
{
|
||||||
next if( $bus->{dirname} != $dirname );
|
next if( $bus->{dirname} != $dirname );
|
||||||
|
|
||||||
foreach my $device (@{$bus->{devices}}) {
|
foreach my $device (@{$bus->{devices}}) {
|
||||||
next if( $device->idVendor() != $VENDOR );
|
next if( $device->idVendor() != $VENDOR );
|
||||||
next if( $device->idProduct() != $PRODUCT );
|
next if( $device->idProduct() != $PRODUCT );
|
||||||
next if( $device->{filename} != $filename );
|
next if( $device->{filename} != $filename );
|
||||||
|
Log3 $name, 5, "$name: found CO20 device with id";
|
||||||
$hash->{DEV} = $device;
|
$hash->{DEV} = $device;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
last if( $hash->{DEV} );
|
last if( $hash->{DEV} );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
elsif( $hash->{helper}{defined} eq "serial" && !$hash->{DEV} && $hash->{SERIALNUMBER} )
|
||||||
|
{
|
||||||
|
foreach my $bus ($hash->{USB}->list_busses())
|
||||||
|
{
|
||||||
|
foreach my $device (@{$bus->{devices}}) {
|
||||||
|
next if( $device->idVendor() != $VENDOR );
|
||||||
|
next if( $device->idProduct() != $PRODUCT );
|
||||||
|
$hash->{DEV} = $device;
|
||||||
|
$hash->{DEV}->open();
|
||||||
|
$hash->{manufacturer} = $hash->{DEV}->manufacturer();
|
||||||
|
$hash->{product} = $hash->{DEV}->product();
|
||||||
|
$hash->{DEV}->detach_kernel_driver_np(0) if( $hash->{DEV}->get_driver_np(0) );
|
||||||
|
my $ret = $hash->{DEV}->claim_interface( 0 );
|
||||||
|
if( $ret == -16 ) {
|
||||||
|
Log3 $name, 2, "$name: USB timeout for CO20 device on identify";
|
||||||
|
return;
|
||||||
|
} elsif( $ret != 0 ) {
|
||||||
|
Log3 $name, 2, "$name: failed to claim CO20 device on identify";
|
||||||
|
CO20_Disconnect($hash);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log3 $name, 5, "$name: claimed CO20 device on identify";
|
||||||
|
my $buf;
|
||||||
|
$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, 1000);
|
||||||
|
Log3 $name, 5, "$name: read CO20 device on identify";
|
||||||
|
my $currentid = CO20_identify($hash);
|
||||||
|
Log3 $name, 2, "$name: found CO20 device with id $currentid while looking for ".$hash->{SERIALNUMBER};
|
||||||
|
last if($currentid eq $hash->{SERIALNUMBER});
|
||||||
|
$hash->{DEV}->release_interface(0);
|
||||||
|
Log3 $name, 5, "$name: released interface on identify";
|
||||||
|
|
||||||
} else {
|
delete $hash->{DEV};
|
||||||
|
delete $hash->{manufacturer};
|
||||||
|
delete $hash->{product};
|
||||||
|
}
|
||||||
|
last if( $hash->{DEV} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log3 $name, 5, "$name: searching CO20 device on identify";
|
||||||
$hash->{DEV} = $hash->{USB}->find_device( $VENDOR, $PRODUCT );
|
$hash->{DEV} = $hash->{USB}->find_device( $VENDOR, $PRODUCT );
|
||||||
|
Log3 $name, 5, "$name: found CO20 device on identify";
|
||||||
}
|
}
|
||||||
|
|
||||||
if( $hash->{DEV} ) {
|
if( !$hash->{DEV} ) {
|
||||||
|
Log3 $name, 2, "$name: failed to find CO20 device";
|
||||||
|
CO20_Disconnect($hash);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log3 $name, 5, "$name: found one CO20 device on identify";
|
||||||
|
if( !$hash->{ID} ) {
|
||||||
|
foreach my $bus ($hash->{USB}->list_busses()) {
|
||||||
|
foreach my $device (@{$bus->{devices}}) {
|
||||||
|
next if( $device->idVendor() != $VENDOR );
|
||||||
|
next if( $device->idProduct() != $PRODUCT );
|
||||||
|
next if( $device->{filename} != $hash->{DEV}->{filename} );
|
||||||
|
$hash->{ID} = $bus->{dirname} . ":" . $device->{filename};
|
||||||
|
last if( $hash->{ID} );
|
||||||
|
}
|
||||||
|
last if( $hash->{ID} );
|
||||||
|
}}
|
||||||
|
|
||||||
|
#
|
||||||
$hash->{STATE} = "found";
|
$hash->{STATE} = "found";
|
||||||
Log3 $name, 3, "$name: CO20 device found";
|
Log3 $name, 3, "$name: CO20 device found";
|
||||||
|
|
||||||
@ -179,6 +264,7 @@ CO20_Connect($)
|
|||||||
|
|
||||||
$hash->{manufacturer} = $hash->{DEV}->manufacturer();
|
$hash->{manufacturer} = $hash->{DEV}->manufacturer();
|
||||||
$hash->{product} = $hash->{DEV}->product();
|
$hash->{product} = $hash->{DEV}->product();
|
||||||
|
$hash->{SERIAL} = $hash->{DEV}->serial_number() if($hash->{DEV}->serial_number() ne "?");
|
||||||
|
|
||||||
if( $hash->{manufacturer} && $hash->{product} ) {
|
if( $hash->{manufacturer} && $hash->{product} ) {
|
||||||
$hash->{DEV}->detach_kernel_driver_np(0) if( $hash->{DEV}->get_driver_np(0) );
|
$hash->{DEV}->detach_kernel_driver_np(0) if( $hash->{DEV}->get_driver_np(0) );
|
||||||
@ -197,13 +283,12 @@ CO20_Connect($)
|
|||||||
Log3 $name, 3, "$name: CO20 device opened";
|
Log3 $name, 3, "$name: CO20 device opened";
|
||||||
|
|
||||||
$hash->{INTERVAL} = AttrVal($name, "interval", 300);
|
$hash->{INTERVAL} = AttrVal($name, "interval", 300);
|
||||||
$hash->{retries} = AttrVal($name,"retries",3);
|
|
||||||
$hash->{timeout} = AttrVal($name,"timeout",1000);
|
|
||||||
|
|
||||||
|
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
InternalTimer(gettimeofday()+10, "CO20_poll", $hash, 0);
|
InternalTimer(gettimeofday()+10, "CO20_poll", $hash, 0);
|
||||||
|
|
||||||
|
Log3 $name, 5, "$name: polling CO20 device on identify";
|
||||||
|
|
||||||
my $buf;
|
my $buf;
|
||||||
$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, 1000);
|
$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, 1000);
|
||||||
|
|
||||||
@ -211,9 +296,8 @@ CO20_Connect($)
|
|||||||
Log3 $name, 3, "$name: failed to open CO20 device";
|
Log3 $name, 3, "$name: failed to open CO20 device";
|
||||||
CO20_Disconnect($hash);
|
CO20_Disconnect($hash);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log3 $name, 3, "$name: failed to find CO20 device";
|
|
||||||
}
|
}
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
@ -224,22 +308,35 @@ CO20_Disconnect($)
|
|||||||
|
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
return if( !$hash->{USB} );
|
|
||||||
|
if( !$hash->{USB} )
|
||||||
|
{
|
||||||
|
$hash->{STATE} = "disconnected";
|
||||||
if( $hash->{manufacturer} && $hash->{product} ) {
|
if( $hash->{manufacturer} && $hash->{product} ) {
|
||||||
$hash->{DEV}->release_interface(0);
|
Log3 $name, 5, "$name: disconnected release";
|
||||||
|
$hash->{DEV}->release_interface(0) if($hash->{DEV});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $hash->{manufacturer} && $hash->{product} ) {
|
||||||
|
Log3 $name, 5, "$name: disconnect release";
|
||||||
|
$hash->{DEV}->release_interface(0) if($hash->{DEV});
|
||||||
}
|
}
|
||||||
|
|
||||||
delete( $hash->{USB} );
|
delete( $hash->{USB} ) if($hash->{USB});
|
||||||
delete( $hash->{DEV} );
|
delete( $hash->{DEV} ) if($hash->{DEV});
|
||||||
delete( $hash->{manufacturer} );
|
delete( $hash->{manufacturer} );
|
||||||
delete( $hash->{product} );
|
delete( $hash->{product} );
|
||||||
|
|
||||||
delete( $hash->{BLOCKED} );
|
delete( $hash->{BLOCKED} );
|
||||||
delete $hash->{FIRMWARE};
|
delete $hash->{FIRMWARE};
|
||||||
CO20_SetStickData($hash,"X");
|
|
||||||
|
|
||||||
$hash->{STATE} = "disconnected";
|
$hash->{STATE} = "disconnected";
|
||||||
Log3 $name, 3, "$name: disconnected";
|
Log3 $name, 3, "$name: disconnected";
|
||||||
|
CO20_SetStickData($hash,"X");
|
||||||
|
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
@ -248,7 +345,7 @@ CO20_Undefine($$)
|
|||||||
my ($hash, $arg) = @_;
|
my ($hash, $arg) = @_;
|
||||||
|
|
||||||
CO20_Disconnect($hash);
|
CO20_Disconnect($hash);
|
||||||
$hash->{fail} = 0;
|
$hash->{FAIL} = 0;
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@ -257,7 +354,7 @@ sub
|
|||||||
CO20_identify($)
|
CO20_identify($)
|
||||||
{
|
{
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
CO20_dataread($hash,"stickdata");
|
CO20_dataread($hash,"stickdata",1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
@ -277,44 +374,46 @@ CO20_poll($)
|
|||||||
|
|
||||||
if( $hash->{manufacturer} && $hash->{product} ) {
|
if( $hash->{manufacturer} && $hash->{product} ) {
|
||||||
|
|
||||||
my $buf = "@".sprintf("%c",$hash->{seq2})."TRF?\n@@@@@@@@@";
|
my $buf = "@".sprintf("%c",$hash->{helper}{seq2})."TRF?\n@@@@@@@@@";
|
||||||
|
|
||||||
Log3 $name, 5, "$name: sent $buf / ".ord(substr($buf,0,1));
|
Log3 $name, 5, "$name: sent $buf / ".ord(substr($buf,0,1));
|
||||||
|
|
||||||
my $ret = $hash->{DEV}->interrupt_write(0x00000002, $buf, 0x0000010, $hash->{timeout});
|
my $ret = $hash->{DEV}->interrupt_write(0x00000002, $buf, 0x0000010, $hash->{helper}{timeout});
|
||||||
if( $ret != 16 ) {
|
if( $ret != 16 ) {
|
||||||
my $ret2 = $hash->{DEV}->interrupt_write(0x00000002, "@@@@@@@@@@@@@@@@", 0x0000010, $hash->{timeout});
|
$hash->{STATE} = "error";
|
||||||
$hash->{fail} = $hash->{fail}+1;
|
my $ret2 = $hash->{DEV}->interrupt_write(0x00000002, "@@@@@@@@@@@@@@@@", 0x0000010, $hash->{helper}{timeout});
|
||||||
Log3 $name, 4, "$name: write error $ret/$ret2 ($hash->{fail})";
|
$hash->{FAIL} = $hash->{FAIL}+1;
|
||||||
|
Log3 $name, 3, "$name: write error $ret/$ret2 ($hash->{FAIL})";
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
InternalTimer(gettimeofday()+30, "CO20_poll", $hash, 1);
|
InternalTimer(gettimeofday()+30, "CO20_poll", $hash, 1);
|
||||||
if($hash->{fail} >= $hash->{retries}) {
|
if($hash->{FAIL} >= $hash->{helper}{retries}) {
|
||||||
$hash->{fail} = 0;
|
$hash->{FAIL} = 0;
|
||||||
CO20_Disconnect($hash);
|
CO20_Disconnect($hash);
|
||||||
$hash->{RECONNECT} = 1;
|
$hash->{RECONNECT} = 1;
|
||||||
CO20_Connect($hash);
|
CO20_Connect($hash);
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
if ($hash->{seq2} < 0xFF){ $hash->{seq2}++} else {$hash->{seq2} = 0x67};
|
if ($hash->{helper}{seq2} < 0xFF){ $hash->{helper}{seq2}++} else {$hash->{helper}{seq2} = 0x67};
|
||||||
|
|
||||||
my $data="";
|
my $data="";
|
||||||
for( $a = 1; $a <= 3; $a = $a + 1 ) {
|
for( $a = 1; $a <= 3; $a = $a + 1 ) {
|
||||||
$ret=$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, $hash->{timeout});
|
$ret=$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, $hash->{helper}{timeout});
|
||||||
if( $ret != 16 and $ret != 0 ) {
|
if( $ret != 16 and $ret != 0 ) {
|
||||||
Log3 $name, 4, "$name: read error $ret";
|
Log3 $name, 4, "$name: read error $ret";
|
||||||
}
|
}
|
||||||
$data.=$buf;
|
$data.=$buf;
|
||||||
}
|
}
|
||||||
Log3 $name, 4, "$name got $data / ".length($data)." / ".ord(substr($data,0,1));
|
Log3 $name, 4, "$name got ".unpack('H*', $data)." / ".length($data)." / ".ord(substr($data,0,1));
|
||||||
|
|
||||||
if( $ret != 16 and $ret != 0 and length($data) < 16 ) {
|
if( $ret != 16 and $ret != 0 and length($data) < 16 ) {
|
||||||
$hash->{fail} = $hash->{fail}+1;
|
$hash->{STATE} = "error";
|
||||||
|
$hash->{FAIL} = $hash->{FAIL}+1;
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
InternalTimer(gettimeofday()+30, "CO20_poll", $hash, 1);
|
InternalTimer(gettimeofday()+30, "CO20_poll", $hash, 1);
|
||||||
Log3 $name, 4, "$name: readloop error $ret ($hash->{fail})";
|
Log3 $name, 4, "$name: readloop error $ret ($hash->{FAIL})";
|
||||||
if($hash->{fail} >= $hash->{retries}) {
|
if($hash->{FAIL} >= $hash->{helper}{retries}) {
|
||||||
$hash->{fail} = 0;
|
$hash->{FAIL} = 0;
|
||||||
CO20_Disconnect($hash);
|
CO20_Disconnect($hash);
|
||||||
$hash->{RECONNECT} = 1;
|
$hash->{RECONNECT} = 1;
|
||||||
CO20_Connect($hash);
|
CO20_Connect($hash);
|
||||||
@ -327,7 +426,7 @@ CO20_poll($)
|
|||||||
|
|
||||||
$data = "@".$data if(ord(substr($data,0,1)) > 64);
|
$data = "@".$data if(ord(substr($data,0,1)) > 64);
|
||||||
|
|
||||||
$hash->{fail} = 0;
|
$hash->{FAIL} = 0;
|
||||||
my $voc = ord(substr($data,3,1))*256 + ord(substr($data,2,1));
|
my $voc = ord(substr($data,3,1))*256 + ord(substr($data,2,1));
|
||||||
my $dbg = ord(substr($data,5,1))*256 + ord(substr($data,4,1));
|
my $dbg = ord(substr($data,5,1))*256 + ord(substr($data,4,1));
|
||||||
my $pwm = ord(substr($data,7,1))*256 + ord(substr($data,6,1));
|
my $pwm = ord(substr($data,7,1))*256 + ord(substr($data,6,1));
|
||||||
@ -347,10 +446,11 @@ CO20_poll($)
|
|||||||
# Log3 $name, 5, "$name: read 1 success\n$bufdec";
|
# Log3 $name, 5, "$name: read 1 success\n$bufdec";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$hash->{fail} = $hash->{fail}+1;
|
$hash->{STATE} = "error";
|
||||||
Log3 $name, 2, "$name: read failed $ret ($hash->{fail})";
|
$hash->{FAIL} = $hash->{FAIL}+1;
|
||||||
if($hash->{fail} >= $hash->{retries}) {
|
Log3 $name, 2, "$name: read failed $ret ($hash->{FAIL})";
|
||||||
$hash->{fail} = 0;
|
if($hash->{FAIL} >= $hash->{helper}{retries}) {
|
||||||
|
$hash->{FAIL} = 0;
|
||||||
CO20_Disconnect($hash);
|
CO20_Disconnect($hash);
|
||||||
$hash->{RECONNECT} = 1;
|
$hash->{RECONNECT} = 1;
|
||||||
CO20_Connect($hash);
|
CO20_Connect($hash);
|
||||||
@ -360,7 +460,7 @@ CO20_poll($)
|
|||||||
$hash->{LAST_POLL} = FmtDateTime( gettimeofday() );
|
$hash->{LAST_POLL} = FmtDateTime( gettimeofday() );
|
||||||
} else {
|
} else {
|
||||||
Log3 $name, 2, "$name: no device";
|
Log3 $name, 2, "$name: no device";
|
||||||
$hash->{fail} = 0;
|
$hash->{FAIL} = 0;
|
||||||
CO20_Disconnect($hash);
|
CO20_Disconnect($hash);
|
||||||
$hash->{RECONNECT} = 1;
|
$hash->{RECONNECT} = 1;
|
||||||
CO20_Connect($hash);
|
CO20_Connect($hash);
|
||||||
@ -369,11 +469,16 @@ CO20_poll($)
|
|||||||
|
|
||||||
|
|
||||||
sub
|
sub
|
||||||
CO20_dataread($$)
|
CO20_dataread($$;$)
|
||||||
{
|
{
|
||||||
my ($hash, $readingstype) = @_;
|
my ($hash, $readingstype, $identify) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
if(!defined($hash->{DEV}))
|
||||||
|
{
|
||||||
|
Log3 $name, 1, "$name: no device";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
my $reqstr = "";
|
my $reqstr = "";
|
||||||
my $retcount = 16;
|
my $retcount = 16;
|
||||||
@ -395,12 +500,12 @@ CO20_dataread($$)
|
|||||||
|
|
||||||
if( $hash->{manufacturer} && $hash->{product} ) {
|
if( $hash->{manufacturer} && $hash->{product} ) {
|
||||||
|
|
||||||
my $seq = sprintf("%04X",$hash->{seq4});
|
my $seq = sprintf("%04X",$hash->{helper}{seq4});
|
||||||
my $seqstr = sprintf("%c",hex substr($seq,2,2)).sprintf("%c",hex substr($seq,0,2));
|
my $seqstr = sprintf("%c",hex substr($seq,2,2)).sprintf("%c",hex substr($seq,0,2));
|
||||||
$hash->{seq4} = ($hash->{seq4} +1) & 0xFFFF;
|
$hash->{helper}{seq4} = ($hash->{helper}{seq4} +1) & 0xFFFF;
|
||||||
|
|
||||||
my $buf = substr("@".$seq.$reqstr."\n@@@@@@@@@@@@@@@@",0,16);
|
my $buf = substr("@".$seq.$reqstr."\n@@@@@@@@@@@@@@@@",0,16);
|
||||||
my $ret = $hash->{DEV}->interrupt_write(0x00000002, $buf, 0x0000010, $hash->{timeout});
|
my $ret = $hash->{DEV}->interrupt_write(0x00000002, $buf, 0x0000010, $hash->{helper}{timeout}) if(defined($hash->{DEV}));
|
||||||
Log3 $name, 4, "getdata write $ret" if($ret != 16);
|
Log3 $name, 4, "getdata write $ret" if($ret != 16);
|
||||||
|
|
||||||
|
|
||||||
@ -408,7 +513,7 @@ CO20_dataread($$)
|
|||||||
my $intdata = "";
|
my $intdata = "";
|
||||||
if($ret == 16) {
|
if($ret == 16) {
|
||||||
for( $a = 1; $a <= $retcount; $a = $a + 1 ){
|
for( $a = 1; $a <= $retcount; $a = $a + 1 ){
|
||||||
$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, $hash->{timeout});
|
$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, $hash->{helper}{timeout});
|
||||||
$data.=$buf;
|
$data.=$buf;
|
||||||
Log3 $name, 4, "getdata read $ret" if($ret != 16);
|
Log3 $name, 4, "getdata read $ret" if($ret != 16);
|
||||||
$intdata = ord(substr($buf,0,1))." ".ord(substr($buf,1,1))." ".ord(substr($buf,2,1))." ".ord(substr($buf,3,1))." ".ord(substr($buf,4,1))." ".ord(substr($buf,5,1))." ".ord(substr($buf,6,1))." ".ord(substr($buf,7,1))." ".ord(substr($buf,8,1))." ".ord(substr($buf,9,1))." ".ord(substr($buf,10,1))." ".ord(substr($buf,11,1))." ".ord(substr($buf,12,1))." ".ord(substr($buf,13,1))." ".ord(substr($buf,14,1))." ".ord(substr($buf,15,1)) if(length($buf) > 15);
|
$intdata = ord(substr($buf,0,1))." ".ord(substr($buf,1,1))." ".ord(substr($buf,2,1))." ".ord(substr($buf,3,1))." ".ord(substr($buf,4,1))." ".ord(substr($buf,5,1))." ".ord(substr($buf,6,1))." ".ord(substr($buf,7,1))." ".ord(substr($buf,8,1))." ".ord(substr($buf,9,1))." ".ord(substr($buf,10,1))." ".ord(substr($buf,11,1))." ".ord(substr($buf,12,1))." ".ord(substr($buf,13,1))." ".ord(substr($buf,14,1))." ".ord(substr($buf,15,1)) if(length($buf) > 15);
|
||||||
@ -423,10 +528,14 @@ CO20_dataread($$)
|
|||||||
} elsif ($readingstype eq "flagdata") {
|
} elsif ($readingstype eq "flagdata") {
|
||||||
CO20_SetStickData($hash,$data);
|
CO20_SetStickData($hash,$data);
|
||||||
} elsif ($readingstype eq "stickdata") {
|
} elsif ($readingstype eq "stickdata") {
|
||||||
if ($data =~ /\bStick\b(.*?)\bMCU\b/) {
|
if ($data =~ /\b;\b(.*?)\b \$;;MCU\b/) {
|
||||||
$hash->{FIRMWARE} = $1;
|
my $fwstr = $1;
|
||||||
|
$fwstr =~ s/;C;/, Firmware: /g;
|
||||||
|
$fwstr =~ s/\$//g;
|
||||||
|
$hash->{FIRMWARE} = $fwstr;
|
||||||
}
|
}
|
||||||
if ($data =~ /\bS\/N:\b(.*?)\b;bI\b/) {
|
if ($data =~ /\bS\/N:\b(.*?)\b;bI\b/) {
|
||||||
|
return $1 if($identify);
|
||||||
$hash->{SERIALNUMBER} = $1;
|
$hash->{SERIALNUMBER} = $1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -498,6 +607,10 @@ CO20_dataset($$$)
|
|||||||
$reqstr = "FLAGSET;RESET BASELINE="; # 0180
|
$reqstr = "FLAGSET;RESET BASELINE="; # 0180
|
||||||
} elsif($cmd eq "reset_device") {
|
} elsif($cmd eq "reset_device") {
|
||||||
$reqstr = "*RST";
|
$reqstr = "*RST";
|
||||||
|
} elsif($cmd eq "reconnect") {
|
||||||
|
CO20_Disconnect($hash);
|
||||||
|
CO20_Connect($hash);
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
@ -505,8 +618,8 @@ CO20_dataset($$$)
|
|||||||
|
|
||||||
if( $hash->{manufacturer} && $hash->{product} ) {
|
if( $hash->{manufacturer} && $hash->{product} ) {
|
||||||
|
|
||||||
my $seq = sprintf("%04X",$hash->{seq4});
|
my $seq = sprintf("%04X",$hash->{helper}{seq4});
|
||||||
$hash->{seq4} = ($hash->{seq4} +1) & 0xFFFF;
|
$hash->{helper}{seq4} = ($hash->{helper}{seq4} +1) & 0xFFFF;
|
||||||
|
|
||||||
my $buf = "@".$seq.$reqstr;
|
my $buf = "@".$seq.$reqstr;
|
||||||
if($cmd ne "reset_device") {
|
if($cmd ne "reset_device") {
|
||||||
@ -528,23 +641,23 @@ CO20_dataset($$$)
|
|||||||
$buf .= "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
|
$buf .= "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
|
||||||
|
|
||||||
|
|
||||||
my $ret = $hash->{DEV}->interrupt_write(0x00000002, substr($buf,0,16), 0x0000010, $hash->{timeout});
|
my $ret = $hash->{DEV}->interrupt_write(0x00000002, substr($buf,0,16), 0x0000010, $hash->{helper}{timeout});
|
||||||
Log3 $name, 4, "setdata write $ret" if($ret != 16);
|
Log3 $name, 4, "setdata write $ret" if($ret != 16);
|
||||||
|
|
||||||
|
|
||||||
if($ret == 16 and ($buflen > 16 or $cmd eq "reset_device")) {
|
if($ret == 16 and ($buflen > 16 or $cmd eq "reset_device")) {
|
||||||
$ret = $hash->{DEV}->interrupt_write(0x00000002, substr($buf,16,16), 0x0000010, $hash->{timeout});
|
$ret = $hash->{DEV}->interrupt_write(0x00000002, substr($buf,16,16), 0x0000010, $hash->{helper}{timeout});
|
||||||
Log3 $name, 4, "setdata write $ret" if($ret != 16);
|
Log3 $name, 4, "setdata write $ret" if($ret != 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($ret == 16 and $buflen > 32) {
|
if($ret == 16 and $buflen > 32) {
|
||||||
$ret = $hash->{DEV}->interrupt_write(0x00000002, substr($buf,32,16), 0x0000010, $hash->{timeout});
|
$ret = $hash->{DEV}->interrupt_write(0x00000002, substr($buf,32,16), 0x0000010, $hash->{helper}{timeout});
|
||||||
Log3 $name, 4, "setdata write $ret" if($ret != 16);
|
Log3 $name, 4, "setdata write $ret" if($ret != 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if($ret == 16 and $buflen > 15) {
|
if($ret == 16 and $buflen > 15) {
|
||||||
$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, $hash->{timeout});
|
$hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, $hash->{helper}{timeout});
|
||||||
$buflen = length($buf);
|
$buflen = length($buf);
|
||||||
Log3 $name, 5, "getdata read $ret";
|
Log3 $name, 5, "getdata read $ret";
|
||||||
if($buflen > 15)
|
if($buflen > 15)
|
||||||
@ -601,7 +714,7 @@ CO20_Set($$$$)
|
|||||||
my ($hash, $name, $cmd, $val) = @_;
|
my ($hash, $name, $cmd, $val) = @_;
|
||||||
|
|
||||||
my $list = "";
|
my $list = "";
|
||||||
$list = "knob_CO2/VOC_level_warn1 knob_CO2/VOC_level_warn2 knob_Reg_Set knob_Reg_P knob_Reg_I knob_Reg_D knob_LogInterval knob_ui16StartupBits recalibrate_heater:noArg reset_baseline:noArg reset_device:noArg" if( AttrVal($name, "advanced", 0 ) == 1 );
|
$list = "knob_CO2/VOC_level_warn1 knob_CO2/VOC_level_warn2 knob_Reg_Set knob_Reg_P knob_Reg_I knob_Reg_D knob_LogInterval knob_ui16StartupBits recalibrate_heater:noArg reset_baseline:noArg reset_device:noArg reconnect:noArg" if( AttrVal($name, "advanced", 0 ) == 1 );
|
||||||
if (index($list, $cmd) != -1) {
|
if (index($list, $cmd) != -1) {
|
||||||
$hash->{BLOCKED} = 1;
|
$hash->{BLOCKED} = 1;
|
||||||
CO20_dataset($hash,$cmd,$val);
|
CO20_dataset($hash,$cmd,$val);
|
||||||
@ -617,6 +730,7 @@ CO20_Attr($$$)
|
|||||||
{
|
{
|
||||||
my ($cmd, $name, $attrName, $attrVal) = @_;
|
my ($cmd, $name, $attrName, $attrVal) = @_;
|
||||||
|
|
||||||
|
return undef if(!defined($defs{$name}));
|
||||||
my $orig = $attrVal;
|
my $orig = $attrVal;
|
||||||
$attrVal = int($attrVal) if($attrName eq "interval" || $attrName eq "retries" || $attrName eq "timeout");
|
$attrVal = int($attrVal) if($attrName eq "interval" || $attrName eq "retries" || $attrName eq "timeout");
|
||||||
$attrVal = 10 if($attrName eq "interval" && $attrVal < 10 && $attrVal != 0);
|
$attrVal = 10 if($attrName eq "interval" && $attrVal < 10 && $attrVal != 0);
|
||||||
@ -640,10 +754,10 @@ CO20_Attr($$$)
|
|||||||
CO20_poll($hash) if( $init_done );
|
CO20_poll($hash) if( $init_done );
|
||||||
} elsif( $attrName eq "retries" ) {
|
} elsif( $attrName eq "retries" ) {
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
$hash->{retries} = $attrVal;
|
$hash->{helper}{retries} = $attrVal;
|
||||||
} elsif( $attrName eq "timeout" ) {
|
} elsif( $attrName eq "timeout" ) {
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
$hash->{timeout} = $attrVal;
|
$hash->{helper}{timeout} = $attrVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( $cmd eq "set" ) {
|
if( $cmd eq "set" ) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user