From 35dd1dec91b2ea92885d49dac85cd85aaadd716c Mon Sep 17 00:00:00 2001 From: justme-1968 Date: Fri, 10 Jan 2014 19:48:19 +0000 Subject: [PATCH] added 38_CO20.pm git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@4612 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- CHANGED | 1 + FHEM/38_CO20.pm | 334 ++++++++++++++++++++++++++++++++++++++++++++++++ MAINTAINER.txt | 13 +- 3 files changed, 342 insertions(+), 6 deletions(-) create mode 100755 FHEM/38_CO20.pm diff --git a/CHANGED b/CHANGED index 3867ad606..bd883aa05 100644 --- a/CHANGED +++ b/CHANGED @@ -1,6 +1,7 @@ # 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. - SVN + - feature: new module 38_CO20.pm added (justme1968) - feature: new module 98_GEOFANCY.pm added (loredo) - feature: new module 70_XBMC.pm added (dbokermann) - feature: new module 51_RPI_GPIO.pm added (klausw) diff --git a/FHEM/38_CO20.pm b/FHEM/38_CO20.pm new file mode 100755 index 000000000..6b9527c07 --- /dev/null +++ b/FHEM/38_CO20.pm @@ -0,0 +1,334 @@ + +# $Id$ + +# basic idea from https://github.com/justinribeiro/idleCO20 + +package main; + +use strict; +use warnings; + +use Device::USB; + +sub +CO20_Initialize($) +{ + my ($hash) = @_; + + $hash->{DefFn} = "CO20_Define"; + $hash->{NotifyFn} = "CO20_Notify"; + $hash->{UndefFn} = "CO20_Undefine"; + #$hash->{SetFn} = "CO20_Set"; + $hash->{GetFn} = "CO20_Get"; + $hash->{AttrFn} = "CO20_Attr"; + $hash->{AttrList} = "disable:1 ". + "interval ". + $readingFnAttributes; +} + +##################################### + +sub +CO20_Define($$) +{ + my ($hash, $def) = @_; + + my @a = split("[ \t][ \t]*", $def); + + return "Usage: define CO20 [bus:device]" if(@a < 2); + + delete $hash->{ID}; + + my $name = $a[0]; + + $hash->{tag} = undef; + $hash->{ID} = $a[2] if( defined($a[2])); + + $hash->{NAME} = $name; + + if( $init_done ) { + delete $modules{CO20}->{NotifyFn}; + CO20_Disconnect($hash); + CO20_Connect($hash); + } elsif( $hash->{STATE} ne "???" ) { + $hash->{STATE} = "Initialized"; + } + + return undef; +} + +sub +CO20_Notify($$) +{ + my ($hash,$dev) = @_; + + if( grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}) ) { + delete $modules{CO20}->{NotifyFn}; + + foreach my $d (keys %defs) { + next if($defs{$d}{TYPE} ne "CO20"); + CO20_Connect($defs{$d}); + } + } +} + +my $VENDOR = 0x03eb; +my $PRODUCT = 0x2013; + +sub +CO20_Connect($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + return undef if( AttrVal($name, "disable", 0 ) == 1 ); + + $hash->{USB} = Device::USB->new() if( !$hash->{USB} ); + + if( $hash->{ID} =~ m/(\d.*):(\d.*)/ ) { + my $dirname = $1; + my $filename = $2; + delete $hash->{DEV}; + foreach my $bus ($hash->{USB}->list_busses()) { + next if( $bus->{dirname} != $dirname ); + + foreach my $device (@{$bus->{devices}}) { + next if( $device->idVendor() != $VENDOR ); + next if( $device->idProduct() != $PRODUCT ); + next if( $device->{filename} != $filename ); + $hash->{DEV} = $device; + last; + } + last if( $hash->{DEV} ); + } + + } else { + $hash->{DEV} = $hash->{USB}->find_device( $VENDOR, $PRODUCT ); + } + + if( $hash->{DEV} ) { + $hash->{STATE} = "found"; + Log3 $name, 3, "$name: CO20 device found"; + + $hash->{DEV}->open(); + + $hash->{manufacturer} = $hash->{DEV}->manufacturer(); + $hash->{product} = $hash->{DEV}->product(); + + if( $hash->{manufacturer} && $hash->{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 ) { + $hash->{STATE} = "waiting"; + Log3 $name, 3, "$name: waiting for CO20 device"; + return; + } elsif( $ret != 0 ) { + Log3 $name, 3, "$name: failed to claim CO20 device"; + CO20_Disconnect($hash); + } + + $hash->{STATE} = "opened"; + Log3 $name, 3, "$name: CO20 device opened"; + + my $interval = AttrVal($name, "interval", 0); + $interval = 60*5 if( !$interval ); + $hash->{INTERVAL} = $interval; + + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+10, "CO20_poll", $hash, 1); + + my $buf; + $hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, 1000); + + } else { + Log3 $name, 3, "$name: failed to open CO20 device"; + CO20_Disconnect($hash); + } + } else { + Log3 $name, 3, "$name: filed to find CO20 device"; + } +} + +sub +CO20_Disconnect($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + RemoveInternalTimer($hash); + + return if( !$hash->{USB} ); + if( $hash->{manufacturer} && $hash->{product} ) { + $hash->{DEV}->release_interface(0); + } + + delete( $hash->{USB} ); + delete( $hash->{DEV} ); + delete( $hash->{manufacturer} ); + delete( $hash->{product} ); + + $hash->{STATE} = "disconnected"; + Log3 $name, 3, "$name: disconnected"; +} + +sub +CO20_Undefine($$) +{ + my ($hash, $arg) = @_; + + CO20_Disconnect($hash); + + return undef; +} + +sub +CO20_Set($$@) +{ + my ($hash, $name, $cmd) = @_; + + my $list = ""; + return "Unknown argument $cmd, choose one of $list"; +} + +sub +CO20_poll($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + if(!$hash->{LOCAL}) { + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+$hash->{INTERVAL}, "CO20_poll", $hash, 1); + } + + if( $hash->{manufacturer} && $hash->{product} ) { + my $buf = "\x40\x68\x2a\x54\x52\x0a\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40"; + my $ret = $hash->{DEV}->interrupt_write(0x00000002, $buf, 0x0000010, 1000); + + $ret = $hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, 1000); + if( $ret == 16 ) { + my $voc = ord(substr($buf,3,1))*256 + ord(substr($buf,2,1)); + readingsSingleUpdate($hash, "voc", $voc, 1 ); + $hash->{DEV}->interrupt_read(0x00000081, $buf, 0x0000010, 1000); + } else { + Log3 $name, 3, "$name: read failed"; + CO20_Disconnect($hash); + CO20_Connect($hash); + } + + $hash->{LAST_POLL} = FmtDateTime( gettimeofday() ); + } else { + CO20_Disconnect($hash); + CO20_Connect($hash); + } +} + + +sub +CO20_Get($$@) +{ + my ($hash, $name, $cmd) = @_; + + my $list = "update:noArg"; + + if( $cmd eq "update" ) { + $hash->{LOCAL} = 1; + CO20_poll($hash); + delete $hash->{LOCAL}; + return undef; + } + + return "Unknown argument $cmd, choose one of $list"; +} + +sub +CO20_Attr($$$) +{ + my ($cmd, $name, $attrName, $attrVal) = @_; + + my $orig = $attrVal; + $attrVal = int($attrVal) if($attrName eq "interval"); + $attrVal = 60 if($attrName eq "interval" && $attrVal < 60 && $attrVal != 0); + + if( $attrName eq "disable" ) { + my $hash = $defs{$name}; + if( $cmd eq "set" && $attrVal ne "0" ) { + CO20_Disconnect($hash); + } else { + $attr{$name}{$attrName} = 0; + CO20_Disconnect($hash); + CO20_Connect($hash); + } + } elsif( $attrName eq "interval" ) { + my $hash = $defs{$name}; + $hash->{INTERVAL} = $attrVal; + CO20_poll($hash) if( $init_done ); + } + + if( $cmd eq "set" ) { + if( $orig ne $attrVal ) { + $attr{$name}{$attrName} = $attrVal; + return $attrName ." set to ". $attrVal; + } + } + + return; +} + +1; + +=pod +=begin html + + +

CO20

+ + +=end html +=cut diff --git a/MAINTAINER.txt b/MAINTAINER.txt index 7e4a4fe19..dad892d67 100644 --- a/MAINTAINER.txt +++ b/MAINTAINER.txt @@ -89,12 +89,13 @@ FHEM/32_mailcheck.pm justme1968 http://forum.fhem.de Automatis FHEM/33_readingsGroup.pm justme1968 http://forum.fhem.de Frontends FHEM/33_readingsproxy.pm justme1968 http://forum.fhem.de Automatisierung FHEM/32_speedtest.pm justme1968 http://forum.fhem.de Sonstiges -FHEM/34_panStamp.pm justme1968 http://forum.fhem.de Sonstiges Systeme -FHEM/34_SWAP.pm justme1968 http://forum.fhem.de Sonstiges Systeme -FHEM/35_SWAP_0000002200000003.pm justme1968 http://forum.fhem.de Sonstiges Systeme -FHEM/36_JeeLink.pm justme1968 http://forum.fhem.de Sonstiges Systeme -FHEM/36_PCA301.pm justme1968 http://forum.fhem.de Sonstiges Systeme -FHEM/36_LaCrosse.pm justme1968 http://forum.fhem.de Sonstiges Systeme +FHEM/34_panStamp.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/34_SWAP.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/35_SWAP_0000002200000003.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/36_JeeLink.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/36_PCA301.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/36_LaCrosse.pm justme1968 http://forum.fhem.de Sonstige Systeme +FHEM/38_CO20.pm justme1968 http://forum.fhem.de Sonstiges FHEM/40_RFXCOM.pm wherzig http://forum.fhem.de RFXTRX FHEM/41_OREGON.pm wherzig http://forum.fhem.de Sonstiges FHEM/42_RFXMETER.pm wherzig http://forum.fhem.de RFXTRX