############################################## # $Id: 30_pilight_dimmer.pm 0.54 2015-05-30 Risiko $ # # Usage # # define pilight_dimmer [protocol] # # Changelog # # V 0.10 2015-02-26 - initial beta version # V 0.50 2015-05-20 - NEW: handle screen messages (up,down) # V 0.50 2015-05-20 - NEW: max dimlevel for gui and device # V 0.51 2015-05-21 - CHG: modifications for dimers without dimlevel # V 0.52 2015-05-25 - CHG: attributes dimlevel_on, dimlevel_off # V 0.53 2015-05-30 - FIX: set dimlevel 0 # V 0.54 2015-05-30 - FIX: StateFn ############################################## package main; use strict; use warnings; use Time::HiRes qw(gettimeofday); use JSON; use Switch; #libswitch-perl sub pilight_dimmer_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "pilight_dimmer_Define"; $hash->{Match} = "^PISWITCH|^PIDIMMER|^PISCREEN"; $hash->{ParseFn} = "pilight_dimmer_Parse"; $hash->{SetFn} = "pilight_dimmer_Set"; $hash->{StateFn} = "pilight_dimmer_State"; $hash->{AttrList} = "dimlevel_max dimlevel_step dimlevel_max_device dimlevel_on dimlevel_off ".$readingFnAttributes; } ##################################### sub pilight_dimmer_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); if(@a < 5) { my $msg = "wrong syntax: define pilight_dimmer [protocol]"; Log3 undef, 2, $msg; return $msg; } my $me = $a[0]; my $protocol = $a[2]; my $id = $a[3]; my $unit = $a[4]; $hash->{STATE} = "defined"; $hash->{PROTOCOL} = lc($protocol); $hash->{ID} = $id; $hash->{UNIT} = $unit; $hash->{PROTOCOL2} = lc($a[5]) if (@a == 6); $hash->{helper}{OWN_DIM} = 1; $hash->{helper}{OWN_DIM} = 0 if ($hash->{PROTOCOL} =~ /screen/); $hash->{helper}{ISSCREEN} = 1 if ($hash->{PROTOCOL} =~ /screen/ or (defined($hash->{PROTOCOL2}) and $hash->{PROTOCOL2}) =~ /screen/); #$attr{$me}{verbose} = 5; $modules{pilight_dimmer}{defptr}{lc($id)}{$me} = $hash; AssignIoPort($hash); return undef; } ########################################### sub pilight_dimmer_Parse($$) { my ($mhash, $rmsg, $rawdata) = @_; my $backend = $mhash->{NAME}; Log3 $backend, 4, "pilight_dimmer_Parse: RCV -> $rmsg"; my ($dev,$protocol,$id,$unit,$state,$dimlevel) = split(",",$rmsg); return () if($dev !~ m/PISWITCH|PIDIMMER|PISCREEN/); my $chash; foreach my $n (keys %{ $modules{pilight_dimmer}{defptr}{lc($id)} }) { my $lh = $modules{pilight_dimmer}{defptr}{$id}{$n}; next if ( !defined($lh->{UNIT}) ); if ($lh->{ID} eq $id && $lh->{UNIT} eq $unit) { $chash = $lh; last; } } return () if (!defined($chash->{NAME})); my $dimlevel_max_dev = AttrVal($chash->{NAME}, "dimlevel_max_device",15); my $dimlevel_max = AttrVal($chash->{NAME}, "dimlevel_max",$dimlevel_max_dev); my $dimlevel_step = AttrVal($chash->{NAME}, "dimlevel_step",1); my $dimlevel_old = ReadingsVal($chash->{NAME},"dimlevel",0); my $state_old = ReadingsVal($chash->{NAME},"state",0); Log3 $chash->{NAME}, 4, "pilight_dimmer_Parse: RCV -> $rmsg"; if ($state eq "up") { $dimlevel = $dimlevel_old + $dimlevel_step; $dimlevel = $dimlevel_max if ($dimlevel > $dimlevel_max); $state="on"; } if ($state eq "down") { $dimlevel = $dimlevel_old - $dimlevel_step; $state="on"; if ($dimlevel <= 0) { $state="off"; $dimlevel= AttrVal($chash->{NAME}, "dimlevel_off",0); } } readingsBeginUpdate($chash); readingsBulkUpdate($chash,"state",$state) if ("$state_old" ne "$state"); if (defined($dimlevel)) { $chash->{helper}{DEV_DIMLEVEL} = $dimlevel; Log3 $chash->{NAME}, 5, "pilight_dimmer_Parse: $dimlevel $dimlevel_max_dev $dimlevel_max"; $dimlevel = $dimlevel / $dimlevel_max_dev * $dimlevel_max; Log3 $chash->{NAME}, 5, "pilight_dimmer_Parse: $dimlevel_old $dimlevel"; $dimlevel = int($dimlevel+0.5); Log3 $chash->{NAME}, 5, "pilight_dimmer_Parse: $dimlevel_old round $dimlevel"; readingsBulkUpdate($chash,"dimlevel",$dimlevel) if ($dimlevel_old != $dimlevel); } readingsEndUpdate($chash, 1); return $chash->{NAME}; } ##################################### sub pilight_dimmer_Write($$$) { my ($hash, $set, $dimlevel) = @_; my $me = $hash->{NAME}; my $proto = $hash->{PROTOCOL}; if ($set =~ /up|down/ and $proto !~ /screen/) { $proto = $hash->{PROTOCOL2} if (defined($hash->{PROTOCOL2})); } if ($set =~ /on|off/ and $proto =~ /screen/) { $proto = $hash->{PROTOCOL2} if (defined($hash->{PROTOCOL2})); } my $msg = "$me,$set"; $msg = $msg.",".$dimlevel if (defined($dimlevel)); my $help = $hash->{PROTOCOL}; $hash->{PROTOCOL} = $proto; Log3 $me, 4, "$me(Set): [$proto] $msg"; IOWrite($hash, $msg); $hash->{PROTOCOL} = $help; return undef; } ##################################### sub pilight_dimmer_ConvDimToDev($$) { my ($me,$dimlevel_gui) = @_; my $dimlevel_max_dev = AttrVal($me, "dimlevel_max_device",15); my $dimlevel_max = AttrVal($me, "dimlevel_max",$dimlevel_max_dev); my $dimlevel = $dimlevel_gui / $dimlevel_max * $dimlevel_max_dev; $dimlevel = int($dimlevel + 0.5); return $dimlevel; } ##################################### sub pilight_dimmer_Set($$) { my ($hash, @a) = @_; my $me = shift @a; return "no set value specified" if(int(@a) < 1); my $dimlevel_max_dev = AttrVal($me, "dimlevel_max_device",15); my $dimlevel_step = AttrVal($me, "dimlevel_step",1); my $dimlevel_max = AttrVal($me, "dimlevel_max",$dimlevel_max_dev); my $canSet = "on:noArg off:noArg"; $canSet .= " up:noArg down:noArg" if ($hash->{helper}{ISSCREEN}); return "Unknown argument ?, choose one of $canSet dimlevel:slider,0,$dimlevel_step,$dimlevel_max" if($a[0] eq "?"); my $set = $a[0]; my $dimlevel = undef; my $currlevel = ReadingsVal($me,"dimlevel",0); if ($set =~ m/up|down/ and !$hash->{helper}{ISSCREEN}) { Log3 $me, 1, "$me(Set): up|down not supported"; return undef; } if ($hash->{helper}{OWN_DIM} == 1) { switch($set) { case "dimlevel" { $dimlevel = pilight_dimmer_ConvDimToDev($me,$a[1]); $set = "on"; } case "on" { my $dimlevel_on = AttrVal($me, "dimlevel_on",$currlevel); $dimlevel_on = $dimlevel_max if ($dimlevel_on eq "dimlevel_max"); $dimlevel = pilight_dimmer_ConvDimToDev($me,$currlevel); } } } else { # device without dimlevel support switch($set) { case "dimlevel" { my $newlevel = $a[1]; my $cnt = int(($newlevel - $currlevel) / $dimlevel_step); return undef if ($cnt==0); $set = "up" if ($cnt>0); $set = "down" if ($cnt<0); $cnt = abs($cnt) - 1; # correction for loop -1 if ($newlevel == 0) { $set = "off"; $cnt=0; #break for loop my $dimlevel_off = AttrVal($me, "dimlevel_off",$newlevel); readingsSingleUpdate($hash,"dimlevel",$dimlevel_off,1); } Log3 $me, 5, "$me(Set): cnt $cnt"; for (my $i=0; $i < $cnt; $i++) { pilight_dimmer_Write($hash,$set,undef); } } case "on" { my $dimlevel_on = AttrVal($me, "dimlevel_on",$currlevel); $dimlevel_on = $dimlevel_max if ($dimlevel_on eq "dimlevel_max"); readingsSingleUpdate($hash,"dimlevel",$dimlevel_on,1); } case "off" { my $dimlevel_off = AttrVal($me, "dimlevel_off",$currlevel); readingsSingleUpdate($hash,"dimlevel",$dimlevel_off,1); } } } if (defined($dimlevel)) { my $dimOld = $hash->{helper}{DEV_DIMLEVEL}; if (defined($dimOld)) { return undef if ($dimOld == $dimlevel); } } delete $hash->{helper}{DEV_DIMLEVEL} if ($set eq "off"); pilight_dimmer_Write($hash,$set,$dimlevel); #keinen Trigger bei Set auslösen #Aktualisierung erfolgt in Parse my $skipTrigger = 1; return undef,$skipTrigger; } ##################################### sub pilight_dimmer_State($$$$) { my ($hash, $time, $name, $val) = @_; my $me = $hash->{NAME}; #$hash->{STATE} wird nur ersetzt, wenn $hash->{STATE} == ??? fhem.pl Z: 2469 #machen wir es also selbst $hash->{STATE} = $val if ($name eq "state"); return undef; } 1; =pod =begin html

pilight_dimmer

    pilight_dimmer represents a dimmmer controled with\from pilight
    You have to define the base device pilight_ctrl first.
    Further information to pilight: http://www.pilight.org/
    Supported dimmers: http://wiki.pilight.org/doku.php/protocols#dimmers

    It is possible to add the screen feature to a dimmer. So you can change the dimlevel by set 'up' or 'down'.
    If you push up or down on the remote control the dimlevel will be changed by dimlevel_step.
    Further it is possible to define a simulated dimmer with a screen and switch protocol. See example three.
    That means if you change the dimlevel a up or down command will be send n times to dim the device instead of send a dimlevel directly.

    Define
      define <name> pilight_dimmer protocol id unit [protocol]
      The second protocol is optional. With it you can add the pilight screen feature (up|down) Example:
        define myctrl pilight_dimmer kaku_dimmer 13483668 0
        define myctrl pilight_dimmer kaku_dimmer 13483668 0 kaku_screen - Dimmer with screen feature
        define myctrl pilight_dimmer quigg_screen 1 0 quigg_gt7000 - Simulated dimmer with screen feature

    Set

    • on
    • off
    • up only if defined with screen protocol
    • down only if defined with screen protocol
    • dimlevel

    Readings

    • state
      state of the dimmer on or off
    • dimlevel
      dimlevel of the dimmer

    Attributes
    • dimlevel_max_device
      Maximum of the dimlevel of the device - default 15
      Have to be less or equal than dimlevel_max
    • dimlevel_max
      Maximum of the dimlevel in FHEM - default dimlevel_max_device
    • dimlevel_step
      Step of the dimlevel - default 1
    • dimlevel_on
      Change dimlevel to value if on set - default no changing
      Could be a numeric value or dimlevel_max
    • dimlevel_off
      Change dimlevel to value if off set - default no changing

=end html =cut