############################################## # $Id$ ############################################## package main; use strict; use warnings; #add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though... BEGIN { if (!grep(/FHEM\/lib$/,@INC)) { foreach my $inc (grep(/FHEM$/,@INC)) { push @INC,$inc."/lib"; }; }; }; use Device::Firmata::Constants qw/ :all /; ##################################### my %sets = ( "angle" => "", ); sub FRM_SERVO_Initialize($) { my ($hash) = @_; $hash->{SetFn} = "FRM_SERVO_Set"; $hash->{DefFn} = "FRM_Client_Define"; $hash->{InitFn} = "FRM_SERVO_Init"; $hash->{UndefFn} = "FRM_Client_Undef"; $hash->{AttrFn} = "FRM_SERVO_Attr"; $hash->{AttrList} = "min-pulse max-pulse IODev $main::readingFnAttributes"; main::LoadModule("FRM"); } sub FRM_SERVO_Init($$) { my ($hash,$args) = @_; my $ret = FRM_Init_Pin_Client($hash,$args,PIN_SERVO); return $ret if (defined $ret); eval { my $firmata = FRM_Client_FirmataDevice($hash); $hash->{resolution}=$firmata->{metadata}{servo_resolutions}{$hash->{PIN}} if (defined $firmata->{metadata}{servo_resolutions}); FRM_SERVO_apply_attribute($hash,"max-pulse"); #sets min-pulse as well }; return FRM_Catch($@) if $@; main::readingsSingleUpdate($hash,"state","Initialized",1); return undef; } sub FRM_SERVO_Attr($$$$) { my ($command,$name,$attribute,$value) = @_; my $hash = $main::defs{$name}; eval { if ($command eq "set") { ARGUMENT_HANDLER: { $attribute eq "IODev" and do { if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $value)) { FRM_Client_AssignIOPort($hash,$value); FRM_Init_Client($hash) if (defined ($hash->{IODev})); } last; }; ($attribute eq "min-pulse" || $attribute eq "max-pulse") and do { if ($main::init_done) { $main::attr{$name}{$attribute}=$value; FRM_SERVO_apply_attribute($hash,$attribute); } last; }; } } }; my $ret = FRM_Catch($@) if $@; if ($ret) { $hash->{STATE} = "error setting $attribute to $value: ".$ret; return "cannot $command attribute $attribute to $value for $name: ".$ret; } return undef; } sub FRM_SERVO_apply_attribute { my ($hash,$attribute) = @_; if ( $attribute eq "min-pulse" || $attribute eq "max-pulse" ) { my $name = $hash->{NAME}; # defaults are taken from: http://arduino.cc/en/Reference/ServoAttach FRM_Client_FirmataDevice($hash)->servo_config($hash->{PIN},{min_pulse => main::AttrVal($name,"min-pulse",544), max_pulse => main::AttrVal($name,"max-pulse",2400)}); } } sub FRM_SERVO_Set($@) { my ($hash, @a) = @_; return "Need at least one parameters" if(@a < 2); return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets) if(!defined($sets{$a[1]})); my $command = $a[1]; my $value = $a[2]; eval { FRM_Client_FirmataDevice($hash)->servo_write($hash->{PIN},$value); main::readingsSingleUpdate($hash,"state",$value, 1); }; return $@; } 1; =pod =begin html
define <name> FRM_SERVO <pin>
set <name> angle <value>