Skip to content

Instantly share code, notes, and snippets.

@tobyink

tobyink/hue-mood.pl

Created Jan 22, 2021
Embed
What would you like to do?
Cycles a list of Philips Hue light bulbs through a gradient of colours
#!/usr/bin/env perl
use v5.16;
use warnings;
package ColourSet {
use Moo;
use Types::Standard -types;
has initial => (
is => 'ro',
isa => ArrayRef,
required => 1,
);
has colours => (
is => 'lazy',
isa => ArrayRef,
);
sub _build_colours {
my ( $self ) = ( shift );
my @colours = @{ $self->initial };
for my $depth ( 0 .. 4 ) {
push @colours, $self->initial->[0];
my @temp;
for my $ix ( 0 .. $#colours - 1 ) {
my $x = $colours[$ix];
my $y = $colours[$ix+1];
push @temp, $x, $self->_blend( $x, $y );
}
@colours = @temp;
}
\@colours;
}
sub _blend {
my ( $self, $alpha, $beta ) = ( shift, @_ );
my @hexStart = ( $alpha =~ /^#?(..)(..)(..)$/i );
my @hexEnd = ( $beta =~ /^#?(..)(..)(..)$/i );
my @decStart = (
hex( "0x" . $hexStart[0] ),
hex( "0x" . $hexStart[1] ),
hex( "0x" . $hexStart[2] ),
);
my @decEnd = (
hex( "0x" . $hexEnd[0] ),
hex( "0x" . $hexEnd[1] ),
hex( "0x" . $hexEnd[2] ),
);
my $avRed = int( ( $decStart[0] + $decEnd[0] ) / 2 );
my $avGrn = int( ( $decStart[1] + $decEnd[1] ) / 2 );
my $avBlu = int( ( $decStart[2] + $decEnd[2] ) / 2 );
# And convert the averages back into hex.
sprintf '#%02x%02x%02x', $avRed, $avGrn, $avBlu;
}
}
package Light {
use Moo;
use Types::Standard -types;
has id => (
is => 'ro',
isa => Int,
required => 1,
);
sub on {
my ( $self ) = ( shift );
system 'hueadm', 'light', $self->id, 'on';
}
sub off {
my ( $self ) = ( shift );
system 'hueadm', 'light', $self->id, 'off';
}
sub colour {
my ( $self, $colour, $brightness ) = ( shift, @_ );
$brightness //= '254';
$brightness = "=$brightness" unless $brightness =~ /^[+=-]/;
system 'hueadm', 'light', $self->id, $colour, "bri$brightness";
}
}
package MyEffect {
use Moo;
use Types::Standard -types;
has lights => (
is => 'ro',
isa => ArrayRef,
required => 1,
);
has colours => (
is => 'ro',
isa => Object->plus_coercions(
ArrayRef, sub { 'ColourSet'->new( initial => $_ ) },
),
required => 1,
coerce => 1,
);
sub do_cycle {
my ( $self, $brightness, $pause, $gap ) = ( shift, @_ );
my $length = @{ $self->colours->colours };
$gap //= ( $length / 10 );
my @indices = map { $gap * $_ } 0 .. $#{ $self->lights };
while ( 1 ) {
@indices = map $_ % $length, @indices;
for my $ix ( 0 .. $#indices ) {
my $colour = $self->colours->colours->[ $indices[$ix] ];
say "Setting light $ix to $colour...";
$self->lights->[$ix]->colour( $colour, $brightness );
}
++$_ for @indices;
sleep $pause;
}
}
}
'MyEffect'->new(
lights => [
'Light'->new( id => 8 ),
'Light'->new( id => 4 ),
'Light'->new( id => 13 ),
],
colours => [
'#FFEFAE',
'#F50002',
'#FFA8F3',
'#C70271',
'#FFB6AE',
],
)->do_cycle( '=64', 2 );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment