From d5215a25d11017a2760f46e0a116eb2811ca74c0 Mon Sep 17 00:00:00 2001 From: betateilchen <> Date: Sat, 21 Jun 2014 21:47:17 +0000 Subject: [PATCH] 98_WIFILED.pm - added for simple use with LW12 git-svn-id: https://svn.fhem.de/fhem/trunk@6151 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/98_WIFILED.pm | 428 +++++++++++++++++++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 fhem/contrib/98_WIFILED.pm diff --git a/fhem/contrib/98_WIFILED.pm b/fhem/contrib/98_WIFILED.pm new file mode 100644 index 000000000..ab60dc46f --- /dev/null +++ b/fhem/contrib/98_WIFILED.pm @@ -0,0 +1,428 @@ +# ############################################################################ +# +# FHEM Modue for WLAN based LED Driver +# +# ############################################################################ +# +# This is absolutley open source. Please feel free to use just as you +# like. Please note, that no warranty is given and no liability +# granted +# +# ############################################################################ +# +# we have the following readings +# state on|off +# +# ############################################################################ +# +# we have the following attributes +# timeout the timeout in seconds for the TCP connection +# +# ############################################################################ +# we have the following internals (all UPPERCASE) +# RED last red value +# GREEN last green value +# BLUE last blue value +# IP the IP of the device +# RGB for the RGB Values of color-picker +# MODE the last number of the built in modes +# +# ############################################################################ +# TODO: the speed of the animation: 0xBB, ??, ??, 0x44 +# ############################################################################ + +package main; +use strict; +use warnings; + +use IO::Socket; +# include this for the self-calling timer we use later on +use Time::HiRes qw(gettimeofday); + +# for the color picker module +use Color; + +use SetExtensions; + +# ---------------------------------------------------------------------------- +# Initialisation routine called upon start-up of FHEM +# ---------------------------------------------------------------------------- +sub WIFILED_Initialize( $ ) { + my ($hash) = @_; + + # the commands we provide to FHEM + # installs the respecitive call-backs for FHEM. The call back in quotes + # must be realised as a sub later on in the file + $hash->{DefFn} = "WIFILED_Define"; + $hash->{SetFn} = "WIFILED_Set"; + $hash->{GetFn} = "WIFILED_Get"; + + # the attributes we have. Space separated list of attribute values in + # the form name:default1,default2 + $hash->{AttrList} = "timeout loglevel:0,1,2,3,4,5,6 " . $readingFnAttributes; + + # initialize the color picker + FHEM_colorpickerInit(); + +} + + +# ---------------------------------------------------------------------------- +# Definition of a module instance +# called when defining an element via fhem.cfg +# ---------------------------------------------------------------------------- +sub WIFILED_Define( $$ ) { + my ( $hash, $def ) = @_; + + my $name = $hash->{NAME}; + + my @a = split("[ \t][ \t]*", $def); + + # do we have the right number of arguments? + if( @a != 3 ) { + Log( $attr{$name}{loglevel}, "WIFILED_Define: falsche Anzahl an Argumenten" ); + return( "wrong syntax: define WIFILED " ); + } + + # preset the internals + $hash->{IP} = $a[ 2 ]; + + $hash->{RED} = 255; + $hash->{GREEN} = 255; + $hash->{BLUE} = 255; + $hash->{MODE} = 0; + + if( !defined( $attr{$name}{timeout} ) ) { + $attr{$name}{timeout} = 2; + } + + if( !defined( $attr{$name}{loglevel} ) ) { + $attr{$name}{loglevel} = 4; + } + + # Preset our readings if undefined + my $tn = TimeNow(); + + if( !defined( $hash->{READINGS}{state}{VAL} ) ) { + $hash->{READINGS}{state}{VAL} = "?"; + $hash->{READINGS}{state}{TIME} = $tn; + } + + if( !defined( $hash->{READINGS}{rgb}{VAL} ) ) { + $hash->{READINGS}{rgb}{VAL} = "FFFFFF"; + $hash->{READINGS}{rgb}{TIME} = $tn; + } + + if( !defined( $hash->{READINGS}{RGB}{VAL} ) ) { + $hash->{READINGS}{RGB}{VAL} = "FFFFFF"; + $hash->{READINGS}{RGB}{TIME} = $tn; + } + + if( !defined( $hash->{READINGS}{dim}{VAL} ) ) { + $hash->{READINGS}{dim}{VAL} = 100; + $hash->{READINGS}{dim}{TIME} = $tn; + } + + return( undef ); +} + + +# ---------------------------------------------------------------------------- +# Set of a module +# called upon set cmd, arg1, arg2, .... +# ---------------------------------------------------------------------------- +sub WIFILED_Set( $@ ) { + my ( $hash, $name, $cmd, @arg ) = @_; + + # check if we have received a command + if( !defined( $cmd ) ) { + return( "$name: set needs at least one parameter" ); + } + + my $cmdList = "" . + "on off next:noArg prev:noArg mode " . + "color brightness:slider,0,1,100 dim:slider,0,1,100 " . + "rgb:colorpicker,RGB "; + + # now parse the commands + if( $cmd eq "?" ) { + # this one should give us a drop down list + return SetExtensions( $hash, $cmdList, $name, $cmd, @arg ); + } elsif( $cmd eq "on" ) { + WIFILED_Write( $hash, "\x{CC}\x{23}\x{33}" ); + # and update the state + readingsSingleUpdate( $hash, + "state", + "on", + 1 ); + Log( GetLogLevel( $name, 4 ), "$name switched on" ); + } elsif( $cmd eq "off" ) { + WIFILED_Write( $hash, "\x{CC}\x{24}\x{33}" ); + # and update the state + readingsSingleUpdate( $hash, + "state", + "off", + 1 ); + Log( GetLogLevel( $name, 4 ), "$name switched off" ); + } elsif( $cmd eq "run" ) { + WIFILED_Write( $hash, "\x{CC}\x{21}\x{33}" ); + } elsif( $cmd eq "stop" ) { + WIFILED_Write( $hash, "\x{CC}\x{22}\x{33}" ); + } elsif( $cmd eq "next" ) { + my $offset = 38; + my $mode = $offset + $hash->{MODE}; + if( $mode > ( $offset + 20 ) ) { + $mode = $offset; + } + $hash->{MODE} = $mode; + WIFILED_Write( $hash, "\x{BB}" . chr( $mode ) . "\x{19}\x{44}" ); + } elsif( $cmd eq "prev" ) { + my $offset = 38; + my $mode = $offset + $hash->{MODE}; + if( $mode < $offset ) { + $mode = $offset + 20; + } + $hash->{MODE} = $mode; + WIFILED_Write( $hash, "\x{BB}" . chr( $mode ) . "\x{19}\x{44}" ); + } elsif( $cmd eq "mode" ) { + my $offset = 38; + if( ( $arg[ 0 ] < 0 ) || ( $arg[ 0 ] > 19 ) ) { + my $msg = "WIFILED_Set: wrong mode number given"; + Log( $attr{$name}{loglevel}, $msg ); + return( $msg ); + } + $hash->{MODE} = $arg[ 0 ] + $offset; + WIFILED_Write( $hash, "\x{BB}" . chr( $hash->{MODE} ) . "\x{19}\x{44}" ); + } elsif( $cmd eq "color" ) { + if( @arg != 3 ) { + my $msg = "WIFILED_Set: wrong number of arguments for set color"; + Log( $attr{$name}{loglevel}, $msg ); + return( $msg ); + } else { + $hash->{RED} = $arg[ 0 ]; + $hash->{GREEN} = $arg[ 1 ]; + $hash->{BLUE} = $arg[ 2 ]; + WIFILED_Write( $hash, "\x{56}" . + chr( $arg[ 0 ] ) . + chr( $arg[ 1 ] ) . + chr( $arg[ 2 ] ) . + "\x{AA}" ); + WIFILED_UpdateRGB( $hash ); + Log( GetLogLevel( $name, 4 ), "$name set to " . + "$hash->{RED} $hash->{GREEN} $hash->{BLUE}" ); + + } + } elsif( $cmd eq "rgb" ) { + if( @arg != 1 ) { + my $msg = "WIFILED_Set: wrong number of arguments for set rgb"; + Log( $attr{$name}{loglevel}, $msg ); + return( $msg ); + } else { + $arg[ 0 ] = uc( $arg[ 0 ] ); + my @colors = ( $arg[ 0 ] =~ m/..?/g ); + + if( @colors != 3 ) { + my $msg = "WIFILED_Set: malformed RBG given."; + Log( $attr{$name}{loglevel}, $msg ); + return( $msg ); + } else { + $hash->{RED} = hex( $colors[ 0 ] ); + $hash->{GREEN} = hex( $colors[ 1 ] ); + $hash->{BLUE} = hex( $colors[ 2 ] ); + WIFILED_Write( $hash, "\x{56}" . + chr( $hash->{RED} ) . + chr( $hash->{GREEN} ) . + chr( $hash->{BLUE} ) . + "\x{AA}" ); + WIFILED_UpdateRGB( $hash ); + Log( GetLogLevel( $name, 4 ), "$name set to " . + "$hash->{RED} $hash->{GREEN} $hash->{BLUE}" ); + } + } + } elsif( ( $cmd eq "brightness" ) || ( $cmd eq "dim" ) ) { + if( @arg != 1 ) { + my $msg = "WIFILED_Set: wrong number of arguments for set brightness"; + Log( $attr{$name}{loglevel}, $msg ); + return( $msg ); + } else { + # brightness is in percent (0..100) + my $bright = $arg[ 0 ]; + my $red = $hash->{RED}; + my $green = $hash->{GREEN}; + my $blue = $hash->{BLUE}; + + if( ( $bright > 100 ) || ( $bright < 0 ) ) { + $bright = 50; + } + + # we need to determine what is 100% + my $upscale = 0; + + # what is the smallest upscale factor? + if( $red > $green ) { + if( $red > $blue ) { + $upscale = 255 / $red; + } else { + $upscale = 255 / $blue; + } + } else { + if( $green > $blue ) { + $upscale = 255 / $green; + } else { + $upscale = 255 / $blue; + } + } + + $red = int( ( ( $red * $upscale ) * $bright ) / 100 ); + $blue = int( ( ( $blue * $upscale ) * $bright ) / 100 ); + $green = int( ( ( $green * $upscale ) * $bright ) / 100 ); + WIFILED_Write( $hash, "\x{56}" . chr( $red ) . chr( $green ) . + chr( $blue ) . "\x{AA}\n" ); + $hash->{RED} = $red; + $hash->{GREEN} = $green; + $hash->{BLUE} = $blue; + WIFILED_UpdateRGB( $hash ); + readingsSingleUpdate( $hash, "dim", $bright, 1 ); + } + } else { +# my $msg = "WIFILED_Set: unsupported command given $cmd @arg"; +# Log( $attr{$name}{loglevel}, $msg ); +# return( $msg ); + return SetExtensions ($hash, $cmdList, $name, $cmd, @arg); + } + + return( undef ); +} + +# ---------------------------------------------------------------------------- +# Get of a module +# called upon get arg1 +# ---------------------------------------------------------------------------- +sub WIFILED_Get( $@ ) { + my ($hash, @a) = @_; + + my $name = $a[ 0 ]; + + if( int( @a ) != 2 ) { + my $msg = "WIFILED_Get: wrong number of arguments"; + Log( $attr{$name}{loglevel}, $msg ); + return( $msg ); + } + + if( ( $a[ 1 ] eq "rgb" ) || ( $a[ 1 ] eq "RGB" ) ) { + return( ReadingsVal( "$name", "rgb", "F0F0F0" ) ); + } elsif( ( $a[ 1 ] eq "dim" ) || ( $a[ 1 ] eq "DIM" ) ) { + return( ReadingsVal( "$name", "dim", "50" ) ); + } else { + my $msg = "WIFILED_Get: unkown argument"; + Log( $attr{$name}{loglevel}, $msg ); + return( $msg ); + } + +} + + +# ---------------------------------------------------------------------------- +# write something to the WIFI LED +# ---------------------------------------------------------------------------- +sub WIFILED_Write( $$ ) { + my ( $hash, $out ) = @_; + my $name = $hash->{NAME}; + + my $s = new IO::Socket::INET( PeerAddr => $hash->{IP}, + PeerPort => 5577, + Proto => 'tcp', + Timeout => int( $attr{$name}{timeout} ) ); + + if( defined $s ) { + my $res = ""; + + $s->autoflush( 1 ); + + print $s $out; + + close( $s ); + } +} + + +# ---------------------------------------------------------------------------- +# Update the RGB Readings for the color picker +# ---------------------------------------------------------------------------- +sub WIFILED_UpdateRGB( $ ) { + my ( $hash, @rest ) = @_; + my $name = $hash->{NAME}; + + my $buf = sprintf( "%02X%02X%02X", + $hash->{RED}, + $hash->{GREEN}, + $hash->{BLUE} ); + + readingsSingleUpdate( $hash, + "RGB", + $buf, + 1 ); + + readingsSingleUpdate( $hash, + "rgb", + $buf, + 1 ); + CommandTrigger( "", "$hash->{NAME} RGB: $buf" ); + + return; +} + + + +# DO NOT WRITE BEYOND THIS LINE +1; + +=pod +=begin html + + +

WIFILED

+
    + Define a WIFI LED Controler. +

    + + + Define +
      + define <name> WIFILED <ip> +

      + + Example: + define myled WIFILED 192.168.38.17 +
        +
      +
    +
    + + + Set +
      + set <name> <value>
      + Set any value. +
    +
    + + + Get
      N/A

    + + + Attributes +
      +
    • setList
      + Space separated list of commands, which will be returned upon "set name ?", + so the FHEMWEB frontend can construct a dropdown and offer on/off + switches. Example: attr WIFILEDName setList on off +
    • +
    • readingFnAttributes
    • +
    +
    + +
+ +=end html +=cut