diff --git a/fhem/FHEM/10_FRM.pm b/fhem/FHEM/10_FRM.pm index 5a3a62b1b..74bb76774 100755 --- a/fhem/FHEM/10_FRM.pm +++ b/fhem/FHEM/10_FRM.pm @@ -325,6 +325,8 @@ sub FRM_DoInit($) { $main::defs{$name}{onewire_pins} = join(",", sort{$a<=>$b}(@$onewirepins)) if (defined $onewirepins and scalar @$onewirepins); my $encoderpins = $device->{metadata}{encoder_pins}; $main::defs{$name}{encoder_pins} = join(",", sort{$a<=>$b}(@$encoderpins)) if (defined $encoderpins and scalar @$encoderpins); + my $stepperpins = $device->{metadata}{stepper_pins}; + $main::defs{$name}{stepper_pins} = join(",", sort{$a<=>$b}(@$stepperpins)) if (defined $stepperpins and scalar @$stepperpins); if (defined $device->{metadata}{analog_resolutions}) { my @analog_resolutions; foreach my $pin (sort{$a<=>$b}(keys %{$device->{metadata}{analog_resolutions}})) { @@ -353,6 +355,13 @@ sub FRM_DoInit($) { } $main::defs{$name}{encoder_resolutions} = join(",",@encoder_resolutions) if (scalar @encoder_resolutions); } + if (defined $device->{metadata}{stepper_resolutions}) { + my @stepper_resolutions; + foreach my $pin (sort{$a<=>$b}(keys %{$device->{metadata}{stepper_resolutions}})) { + push @stepper_resolutions,$pin.":".$device->{metadata}{stepper_resolutions}{$pin}; + } + $main::defs{$name}{stepper_resolutions} = join(",",@stepper_resolutions) if (scalar @stepper_resolutions); + } $found = 1; } else { select (undef,undef,undef,0.01); diff --git a/fhem/FHEM/20_FRM_ROTENC.pm b/fhem/FHEM/20_FRM_ROTENC.pm index a0728cb78..47d1b47be 100755 --- a/fhem/FHEM/20_FRM_ROTENC.pm +++ b/fhem/FHEM/20_FRM_ROTENC.pm @@ -79,11 +79,11 @@ FRM_ROTENC_Init($$) sub FRM_ROTENC_observer { - my ( $data, $hash ) = @_; + my ( $encoder, $value, $hash ) = @_; my $name = $hash->{NAME}; - Log3 $name,5,"onEncoderMessage for pins ".$hash->{PINA}.",".$hash->{PINB}." encoder: ".$data->{encoderNum}." position: ".$data->{value}."\n"; + Log3 $name,5,"onEncoderMessage for pins ".$hash->{PINA}.",".$hash->{PINB}." encoder: ".$encoder." position: ".$value."\n"; main::readingsBeginUpdate($hash); - main::readingsBulkUpdate($hash,"position",$data->{value}, 1); + main::readingsBulkUpdate($hash,"position",$value, 1); main::readingsEndUpdate($hash,1); } diff --git a/fhem/FHEM/20_FRM_STEPPER.pm b/fhem/FHEM/20_FRM_STEPPER.pm new file mode 100755 index 000000000..55da32662 --- /dev/null +++ b/fhem/FHEM/20_FRM_STEPPER.pm @@ -0,0 +1,325 @@ +############################################# +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 = ( + "reset" => "noArg", + "position" => "", + "step" => "", +); + +my %gets = ( + "position" => "noArg", +); + +sub +FRM_STEPPER_Initialize($) +{ + my ($hash) = @_; + + $hash->{SetFn} = "FRM_STEPPER_Set"; + $hash->{GetFn} = "FRM_STEPPER_Get"; + $hash->{DefFn} = "FRM_Client_Define"; + $hash->{InitFn} = "FRM_STEPPER_Init"; + $hash->{UndefFn} = "FRM_Client_Undef"; + $hash->{AttrFn} = "FRM_STEPPER_Attr"; + $hash->{StateFn} = "FRM_STEPPER_State"; + + $hash->{AttrList} = "restoreOnReconnect:on,off restoreOnStartup:on,off speed acceleration deceleration IODev $main::readingFnAttributes"; + main::LoadModule("FRM"); +} + +sub +FRM_STEPPER_Init($$) +{ + my ($hash,$args) = @_; + + my $u = "wrong syntax: define FRM_STEPPER [DRIVER|TWO_WIRE|FOUR_WIRE] directionPin stepPin [motorPin3 motorPin4] stepsPerRev [id]"; + return $u unless defined $args; + + my $driver = shift @$args; + + return $u unless ( $driver eq 'DRIVER' or $driver eq 'TWO_WIRE' or $driver eq 'FOUR_WIRE' ); + return $u if (($driver eq 'DRIVER' or $driver eq 'TWO_WIRE') and (scalar(@$args) < 3 or scalar(@$args) > 4)); + return $u if (($driver eq 'FOUR_WIRE') and (scalar(@$args) < 5 or scalar(@$args) > 6)); + + $hash->{DRIVER} = $driver; + + $hash->{PIN1} = shift @$args; + $hash->{PIN2} = shift @$args; + + if ($driver eq 'FOUR_WIRE') { + $hash->{PIN3} = shift @$args; + $hash->{PIN4} = shift @$args; + } + + $hash->{STEPSPERREV} = shift @$args; + $hash->{STEPPERNUM} = shift @$args; + + eval { + FRM_Client_AssignIOPort($hash); + my $firmata = FRM_Client_FirmataDevice($hash); + $firmata->stepper_config( + $hash->{STEPPERNUM}, + $driver, + $hash->{STEPSPERREV}, + $hash->{PIN1}, + $hash->{PIN2}, + $hash->{PIN3}, + $hash->{PIN4}); + $firmata->observe_stepper(0, \&FRM_STEPPER_observer, $hash ); + }; + if ($@) { + $@ =~ /^(.*)( at.*FHEM.*)$/; + $hash->{STATE} = "error initializing: ".$1; + return "error initializing '".$hash->{NAME}."': ".$1; + } + $hash->{POSITION} = 0; + $hash->{DIRECTION} = 0; + $hash->{STEPS} = 0; + if (! (defined AttrVal($hash->{NAME},"stateFormat",undef))) { + $main::attr{$hash->{NAME}}{"stateFormat"} = "position"; + } + main::readingsSingleUpdate($hash,"state","Initialized",1); + return undef; +} + +sub +FRM_STEPPER_observer +{ + my ( $stepper, $hash ) = @_; + my $name = $hash->{NAME}; + Log3 $name,5,"onStepperMessage for pins ".$hash->{PIN1}.",".$hash->{PIN2}.(defined ($hash->{PIN3}) ? ",".$hash->{PIN3} : ",-").(defined ($hash->{PIN4}) ? ",".$hash->{PIN4} : ",-")." stepper: ".$stepper; + my $position = $hash->{DIRECTION} ? $hash->{POSITION} - $hash->{STEPS} : $hash->{POSITION} + $hash->{STEPS}; + $hash->{POSITION} = $position; + $hash->{DIRECTION} = 0; + $hash->{STEPS} = 0; + main::readingsSingleUpdate($hash,"position",$position,1); +} + +sub +FRM_STEPPER_Set +{ + my ($hash, @a) = @_; + return "Need at least one parameters" if(@a < 2); + shift @a; + my $name = $hash->{NAME}; + my $command = shift @a; + if(!defined($sets{$command})) { + my @commands = (); + foreach my $key (sort keys %sets) { + push @commands, $sets{$key} ? $key.":".join(",",$sets{$key}) : $key; + } + return "Unknown argument $command, choose one of " . join(" ", @commands); + } + COMMAND_HANDLER: { + $command eq "reset" and do { + $hash->{POSITION} = 0; + main::readingsSingleUpdate($hash,"position",0,1); + last; + }; + $command eq "position" and do { + my $position = $hash->{POSITION}; + my $value = shift @a; + my $direction = $value < $position ? 1 : 0; + my $steps = $direction ? $position - $value : $value - $position; + my $speed = shift @a; + $speed = AttrVal($name,"speed",30) unless (defined $speed); + my $accel = shift @a; + $accel = AttrVal($name,"acceleration",undef) unless (defined $accel); + my $decel = shift @a; + $decel = AttrVal($name,"deceleration",undef) unless (defined $decel); + $hash->{DIRECTION} = $direction; + $hash->{STEPS} = $steps; + eval { + # $stepperNum, $direction, $numSteps, $stepSpeed, $accel, $decel + FRM_Client_FirmataDevice($hash)->stepper_step($hash->{STEPPERNUM},$direction,$steps,$speed,$accel,$decel); + }; + last; + }; + $command eq "step" and do { + my $value = shift @a; + my $direction = $value < 0 ? 1 : 0; + my $steps = abs $value; + my $speed = shift @a; + $speed = AttrVal($name,"speed",100) unless (defined $speed); + my $accel = shift @a; + $accel = AttrVal($name,"acceleration",undef) unless (defined $accel); + my $decel = shift @a; + $decel = AttrVal($name,"deceleration",undef) unless (defined $decel); + $hash->{DIRECTION} = $direction; + $hash->{STEPS} = $steps; + eval { + # $stepperNum, $direction, $numSteps, $stepSpeed, $accel, $decel + FRM_Client_FirmataDevice($hash)->stepper_step($hash->{STEPPERNUM},$direction,$steps,$speed,$accel,$decel); + }; + last; + }; + } +} + +sub +FRM_STEPPER_Get +{ + my ($hash, @a) = @_; + return "Need at least one parameters" if(@a < 2); + shift @a; + my $name = $hash->{NAME}; + my $command = shift @a; + return "Unknown argument $command, choose one of " . join(" ", sort keys %gets) unless defined($gets{$command}); +} + + +sub FRM_STEPPER_State($$$$) +{ + my ($hash, $tim, $sname, $sval) = @_; + +STATEHANDLER: { + $sname eq "value" and do { + if (AttrVal($hash->{NAME},"restoreOnStartup","on") eq "on") { + FRM_STEPPER_Set($hash,$hash->{NAME},$sval); + } + last; + } + } +} + +sub +FRM_STEPPER_Attr($$$$) { + my ($command,$name,$attribute,$value) = @_; + if ($command eq "set") { + ARGUMENT_HANDLER: { + $attribute eq "IODev" and do { + my $hash = $main::defs{$name}; + if (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $value) { + $hash->{IODev} = $defs{$value}; + FRM_Init_Client($hash) if (defined ($hash->{IODev})); + } + last; + }; + $main::attr{$name}{$attribute}=$value; + } + } +} + +1; + +=pod +=begin html + + +

FRM_STEPPER

+ +
+ +=end html +=cut diff --git a/fhem/FHEM/lib/Device/Firmata.pm b/fhem/FHEM/lib/Device/Firmata.pm index 30fe847f7..a7cf37c8d 100644 --- a/fhem/FHEM/lib/Device/Firmata.pm +++ b/fhem/FHEM/lib/Device/Firmata.pm @@ -19,7 +19,7 @@ Version 0.50 =cut -our $VERSION = '0.53'; +our $VERSION = '0.54'; our $DEBUG = 0; diff --git a/fhem/FHEM/lib/Device/Firmata/Constants.pm b/fhem/FHEM/lib/Device/Firmata/Constants.pm index c7ade028c..01ca350ed 100644 --- a/fhem/FHEM/lib/Device/Firmata/Constants.pm +++ b/fhem/FHEM/lib/Device/Firmata/Constants.pm @@ -214,6 +214,7 @@ use constant ( EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq STRING_DATA => 0x71, # a string message with 14-bits per char + STEPPER_DATA => 0x72, # control a stepper motor ONEWIRE_DATA => 0x73, # OneWire read/write/reset/select/skip/search request + read/search reply SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits) I2C_REQUEST => 0x76, # send an I2C read/write request @@ -233,7 +234,8 @@ use constant ( SERVO => 0x04, # digital pin in Servo output mode SHIFT => 0x05, # shiftIn/shiftOut mode I2C => 0x06, # pin included in I2C setup - ONEWIRE => 0x07, + ONEWIRE => 0x07, # pin configured for 1-Wire commuication + STEPPER => 0x08, # pin configured for stepper motor # Deprecated entries deprecated => [ @@ -267,6 +269,7 @@ use constant ( EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq STRING_DATA => 0x71, # a string message with 14-bits per char + STEPPER_DATA => 0x72, # control a stepper motor ONEWIRE_DATA => 0x73, # OneWire read/write/reset/select/skip/search request + read/search reply SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits) I2C_REQUEST => 0x76, # send an I2C read/write request @@ -286,8 +289,8 @@ use constant ( SERVO => 0x04, # digital pin in Servo output mode SHIFT => 0x05, # shiftIn/shiftOut mode I2C => 0x06, # pin included in I2C setup - ONEWIRE => 0x07, - + ONEWIRE => 0x07, # pin configured for 1-Wire commuication + STEPPER => 0x08, # pin configured for stepper motor # Deprecated entries deprecated => [ qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL ) diff --git a/fhem/FHEM/lib/Device/Firmata/Platform.pm b/fhem/FHEM/lib/Device/Firmata/Platform.pm index a8a128630..fb5b097b9 100644 --- a/fhem/FHEM/lib/Device/Firmata/Platform.pm +++ b/fhem/FHEM/lib/Device/Firmata/Platform.pm @@ -28,6 +28,8 @@ use Device::Firmata::Base analog_resolutions => {}, pwm_resolutions => {}, servo_resolutions => {}, + stepper_resolutions => {}, + encoder_resolutions => {}, ports => [], pins => {}, pin_modes => {}, @@ -87,6 +89,8 @@ sub detach { $self->{sysex_observer} = undef; $self->{i2c_observer} = undef; $self->{onewire_observer} = []; + $self->{stepper_observer} = []; + $self->{encoder_observer} = []; $self->{scheduler_observer} = undef; $self->{tasks} = []; $self->{metadata} = {}; @@ -111,6 +115,8 @@ sub system_reset { $self->{sysex_observer} = undef; $self->{i2c_observer} = undef; $self->{onewire_observer} = []; + $self->{stepper_observer} = []; + $self->{encoder_observer} = []; $self->{scheduler_observer} = undef; $self->{tasks} = []; $self->{metadata} = {}; @@ -279,9 +285,11 @@ sub sysex_handle { } if ($capabilities->{$pin}->{PIN_STEPPER+0}) { push @stepperpins, $pin; + $self->{metadata}{stepper_resolutions}{$pin} = $capabilities->{$pin}->{PIN_STEPPER+0}->{resolution}; } if ($capabilities->{$pin}->{PIN_ENCODER+0}) { push @encoderpins, $pin; + $self->{metadata}{encoder_resolutions}{$pin} = $capabilities->{$pin}->{PIN_ENCODER+0}->{resolution}; } } } @@ -347,18 +355,22 @@ sub sysex_handle { } last; }; - + $sysex_message->{command_str} eq 'STEPPER_DATA' and do { - #TODO implement handling of STEPPER_DATA and call observer. + my $stepperNum = $data->{stepperNum}; + my $observer = $self->{stepper_observer}[$stepperNum]; + if (defined $observer) { + $observer->{method}( $stepperNum, $observer->{context} ); + }; last; }; - + $sysex_message->{command_str} eq 'ENCODER_DATA' and do { foreach my $encoder_data ( @$data ) { my $encoderNum = $encoder_data->{encoderNum}; my $observer = $self->{encoder_observer}[$encoderNum]; if (defined $observer) { - $observer->{method}( $encoder_data, $observer->{context} ); + $observer->{method}( $encoderNum, $encoder_data->{value}, $observer->{context} ); } }; last; @@ -769,6 +781,20 @@ sub onewire_command_series { return $self->{io}->data_write($self->{protocol}->packet_onewire_request( $pin, $args )); } +sub stepper_config { + my ( $self, $stepperNum, $interface, $stepsPerRev, $directionPin, $stepPin, $motorPin3, $motorPin4 ) = @_; + die "unsupported mode 'STEPPER' for pin '".$directionPin."'" unless $self->is_supported_mode($directionPin,PIN_STEPPER); + die "unsupported mode 'STEPPER' for pin '".$stepPin."'" unless $self->is_supported_mode($stepPin,PIN_STEPPER); + die "unsupported mode 'STEPPER' for pin '".$motorPin3."'" unless (!(defined $motorPin3) or $self->is_supported_mode($motorPin3,PIN_STEPPER)); + die "unsupported mode 'STEPPER' for pin '".$motorPin4."'" unless (!(defined $motorPin4) or $self->is_supported_mode($motorPin4,PIN_STEPPER)); + return $self->{io}->data_write($self->{protocol}->packet_stepper_config( $stepperNum, $interface, $stepsPerRev, $directionPin, $stepPin, $motorPin3, $motorPin4 )); +} + +sub stepper_step { + my ( $self, $stepperNum, $direction, $numSteps, $stepSpeed, $accel, $decel ) = @_; + return $self->{io}->data_write($self->{protocol}->packet_stepper_step( $stepperNum, $direction, $numSteps, $stepSpeed, $accel, $decel )); +} + sub encoder_attach { my ( $self, $encoderNum, $pinA, $pinB ) = @_; die "unsupported mode 'ENCODER' for pin '".$pinA."'" unless $self->is_supported_mode($pinA,PIN_ENCODER); @@ -872,7 +898,12 @@ sub observe_onewire { } sub observe_stepper { - #TODO implement observe_stepper + my ( $self, $stepperNum, $observer, $context ) = @_; +#TODO validation? die "unsupported mode 'STEPPER' for pin '".$pin."'" unless ($self->is_supported_mode($pin,PIN_STEPPER)); + $self->{stepper_observer}[$stepperNum] = { + method => $observer, + context => $context, + }; return 1; } diff --git a/fhem/FHEM/lib/Device/Firmata/Protocol.pm b/fhem/FHEM/lib/Device/Firmata/Protocol.pm index 4437da9e8..72c098f2c 100644 --- a/fhem/FHEM/lib/Device/Firmata/Protocol.pm +++ b/fhem/FHEM/lib/Device/Firmata/Protocol.pm @@ -78,6 +78,12 @@ our $STEPPER_COMMANDS = { STEPPER_STEP => 1, }; +our $STEPPER_INTERFACES = { + DRIVER => 1, + TWO_WIRE => 2, + FOUR_WIRE => 4, +}; + our $ENCODER_COMMANDS = { ENCODER_ATTACH => 0, ENCODER_REPORT_POSITION => 1, @@ -305,12 +311,12 @@ sub sysex_parse { $return_data = $self->handle_scheduler_response($sysex_data); last; }; - + $command == $protocol_commands->{STEPPER_DATA} and do { - #TODO implement and call handle_stepper_response + $return_data = $self->handle_stepper_response($sysex_data); last; }; - + $command == $protocol_commands->{ENCODER_DATA} and do { $return_data = $self->handle_encoder_response($sysex_data); last; @@ -867,18 +873,68 @@ sub handle_scheduler_response { } } -#TODO packet_stepper_config +# stepper_data 0 +# stepper_config 1 +# devicenum 2 (0 < devicenum < 6) +# interface (DRIVER | TWO_WIRE | FOUR_WIRE) 3 +# stepsPerRev 4+5 (14bit) +# directionPin 6 +# stepPin 7 +# motorPin3 8 (interface FOUR_WIRE only) +# motorPin4 9 (interface FOUR_WIRE only) + sub packet_stepper_config { - my ( $self ) = @_; - my $packet = $self->packet_sysex_command('STEPPER_DATA', $STEPPER_COMMANDS->{STEPPER_CONFIG}); + my ( $self, $stepperNum, $interface, $stepsPerRev, $directionPin, $stepPin, $motorPin3, $motorPin4 ) = @_; + + die "invalid stepper interface ".$interface unless defined ($STEPPER_INTERFACES->{$interface}); + my @configdata = ($stepperNum,$STEPPER_INTERFACES->{$interface}); + + push_value_as_two_7bit($stepsPerRev, \@configdata); + push @configdata, $directionPin; + push @configdata, $stepPin; + + if ($interface eq 'FOUR_WIRE') { + push @configdata, $motorPin3; + push @configdata, $motorPin4; + } + my $packet = $self->packet_sysex_command('STEPPER_DATA',$STEPPER_COMMANDS->{STEPPER_CONFIG},@configdata); + return $packet; } -#TODO packet_stepper_step +# stepper_data 0 +# stepper_step 1 +# devicenum 2 +# stepDirection 3 0/>0 +# numSteps 4,5,6 (21bit) +# stepSpeed 7,8 (14bit) +# accel 9,10 (14bit, optional, aber nur zusammen mit decel) +# decel 11,12 (14bit, optional, aber nur zusammen mit accel) + sub packet_stepper_step { - my ( $self ) = @_; - my $packet = $self->packet_sysex_command('STEPPER_DATA', $STEPPER_COMMANDS->{STEPPER_STEP}); + my ( $self, $stepperNum, $direction, $numSteps, $stepSpeed, $accel, $decel ) = @_; + my @stepdata = ($stepperNum, $direction); + push @stepdata, $numSteps & 0x7f; + push @stepdata, ($numSteps >> 7) & 0x7f; + push @stepdata, ($numSteps >> 14) & 0x7f; + push_value_as_two_7bit($stepSpeed, \@stepdata); + if (defined $accel and defined $decel) { + push_value_as_two_7bit($accel, \@stepdata); + push_value_as_two_7bit($decel, \@stepdata); + } + my $packet = $self->packet_sysex_command('STEPPER_DATA', $STEPPER_COMMANDS->{STEPPER_STEP},@stepdata); + return $packet; } +sub handle_stepper_response { + my ( $self, $sysex_data ) = @_; + + my $stepperNum = shift @$sysex_data; + return { + stepperNum => $stepperNum, + }; +} + + sub packet_encoder_attach { my ( $self,$encoderNum, $pinA, $pinB ) = @_; my $packet = $self->packet_sysex_command('ENCODER_DATA', $ENCODER_COMMANDS->{ENCODER_ATTACH}, $encoderNum, $pinA, $pinB); @@ -904,7 +960,7 @@ sub packet_encoder_reset_position { } sub packet_encoder_report_auto { - my ( $self,$arg ) = @_; #TODO clarify encoder_report_auto $arg + my ( $self,$arg ) = @_; my $packet = $self->packet_sysex_command('ENCODER_DATA', $ENCODER_COMMANDS->{ENCODER_REPORT_AUTO}, $arg); return $packet; } diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index 0cb6e6351..473fac66a 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -61,12 +61,15 @@ FHEM/17_SIS_PMS.pm painseeker http://forum.fhem.de Sonstiges FHEM/18_CUL_HOERMANN.pm rudolfkoenig http://forum.fhem.de SlowRF FHEM/19_Revolt.pm martinppp/mehf http://forum.fhem.de SlowRF FHEM/20_FRM_AD.pm ntruchsess http://forum.fhem.de Sonstiges +FHEM/20_FRM_ROTENC.pm ntruchsess http://forum.fhem.de Sonstiges FHEM/20_FRM_I2C.pm ntruchsess http://forum.fhem.de Sonstiges FHEM/20_FRM_IN.pm ntruchsess http://forum.fhem.de Sonstiges FHEM/20_FRM_LCD.pm ntruchsess http://forum.fhem.de Sonstiges FHEM/20_FRM_OUT.pm ntruchsess http://forum.fhem.de Sonstiges FHEM/20_FRM_PWM.pm ntruchsess http://forum.fhem.de Sonstiges +FHEM/20_FRM_RBG.pm ntruchsess http://forum.fhem.de Sonstiges FHEM/20_FRM_SERVO.pm ntruchsess http://forum.fhem.de Sonstiges +FHEM/20_FRM_STEPPER.pm ntruchsess http://forum.fhem.de Sonstiges FHEM/20_OWFS.pm mfr69bs http://forum.fhem.de 1Wire (deprecated) FHEM/20_X10.pm borisneubert http://forum.fhem.de SlowRF FHEM/20_ROOMMATE.pm loredo http://forum.fhem.de Automatisierung @@ -149,7 +152,7 @@ FHEM/70_USBWX.pm wherzig http://forum.fhem.de Sonstiges FHEM/70_VIERA.pm teevau http://forum.fhem.de Sonstiges FHEM/70_WS3600.pm Josch http://forum.fhem.de Sonstiges FHEM/70_XBMC.pm dennisb http://forum.fhem.de Multimedia -FHEM/70_Pushover.pm Johannes_B http://forum.fhem.de Unterstützende Dienste +FHEM/70_Pushover.pm Johannes_B http://forum.fhem.de Unterst�tzende Dienste FHEM/71_LISTENLIVE.pm betateilchen http://forum.fhem.de Multimedia FHEM/71_YAMAHA_AVR.pm markusbloch http://forum.fhem.de Multimedia FHEM/71_YAMAHA_BD.pm markusbloch http://forum.fhem.de Multimedia @@ -197,7 +200,7 @@ FHEM/98_RandomTimer.pm dietmar63 http://forum.fhem.de Unterstue FHEM/98_SVG.pm rudolfkoenig http://forum.fhem.de Frontends FHEM/98_THRESHOLD.pm damian-s http://forum.fhem.de Automatisierung FHEM/98_WeekdayTimer.pm dietmar63 http://forum.fhem.de Unterstuetzende Dienste -FHEM/98_WOL.pm dietmar63 http://forum.fhem.de Unterstützende Dienste +FHEM/98_WOL.pm dietmar63 http://forum.fhem.de Unterst�tzende Dienste FHEM/98_XmlList.pm rudolfkoenig http://forum.fhem.de Automatisierung FHEM/98_autocreate.pm rudolfkoenig http://forum.fhem.de Automatisierung FHEM/98_average.pm rudolfkoenig http://forum.fhem.de Automatisierung