Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue #212 - Web can not dim/brighten Insteon lights #231

Merged
merged 8 commits into from
Jul 14, 2013
4 changes: 2 additions & 2 deletions bin/mh.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2058,7 +2058,7 @@ eib_errata=2

@ These are the states displayed on the tk and web menus
@ French: insteon_menu_states=on,off,normal,eco,plus,moins,plus2,moins2,plus3,moins3,+40,-40,5%,30%,60%,100%
insteon_menu_states=on,off,+40,-40,5%,30%,60%,100%
insteon_menu_states=off,20%,40%,50%,60%,80%,on

******************************************************************************
# Category = Misc
Expand Down Expand Up @@ -2451,4 +2451,4 @@ owfs_uom_temp = F
# - add net parms. add cm11_serial parm.
#

#
#
3 changes: 0 additions & 3 deletions lib/Insteon.pm
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,6 @@ so that each class can have its own unique set of voice commands.
sub generate_voice_commands
{

my $insteon_menu_states = $main::config_parms{insteon_menu_states} if $main::config_parms{insteon_menu_states};
&main::print_log("Generating Voice commands for all Insteon objects");
my $object_string;
for my $object (&main::list_all_objects) {
Expand Down Expand Up @@ -594,8 +593,6 @@ sub generate_voice_commands
$object_string .= &main::store_object_data($object_name_v, 'Voice_Cmd', 'Insteon', 'Insteon_link_commands');
push @_insteon_link, $object_name;
} elsif ($object->isa('Insteon::BaseDevice')) {
$states = $insteon_menu_states if $insteon_menu_states
&& ($object->can('is_dimmable') && $object->is_dimmable);
my $cmd_states = "$states,status,get engine version,scan link table,log links,update onlevel/ramprate"; #,on level,ramp rate";
$cmd_states .= ",link to interface,unlink with interface" if $object->isa("Insteon::BaseController") || $object->is_controller;
$object_string .= "$object_name_v = new Voice_Cmd '$command [$cmd_states]';\n";
Expand Down
24 changes: 7 additions & 17 deletions lib/Insteon/BaseInsteon.pm
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ sub derive_message
} else {
if ($command eq 'on')
{
$message->extra(sprintf("%02X",$level));
$message->extra(sprintf("%02X",int($level+.5)));
} else {
$message->extra('00');
}
Expand Down Expand Up @@ -594,7 +594,7 @@ sub _is_info_request
my $is_info_request = 0;
if ($cmd eq 'status_request') {
$is_info_request++;
my $ack_on_level = (hex($msg{extra}) >= 254) ? 100 : sprintf("%d", hex($msg{extra}) * 100 / 255);
my $ack_on_level = sprintf("%d", int((hex($msg{extra}) * 100 / 255)+.5));
&::print_log("[Insteon::BaseObject] received status for " .
$self->{object_name} . " with on-level: $ack_on_level%, "
. "hops left: $msg{hopsleft}") if $main::Debug{insteon};
Expand Down Expand Up @@ -1756,33 +1756,23 @@ sub restore_string
{
$restore_string .= $self->_aldb->restore_string();
}
if ($$self{states})
{
my $states = '';
foreach my $state (@{$$self{states}})
{
$states .= '|' if $states;
$states .= $state;
}
$restore_string .= $self->{object_name} . "->restore_states(q~$states~);\n";
}

return $restore_string;
}

=item C<restore_states()>

Used to reload the persistent states of variables on restart.
Obsolete / do not use.

Function should remain so that upgrading users will not have issues starting
MH from previous versions that referenced this function in the
mh_temp.saved_states file.

=cut

sub restore_states
{
my ($self, $states) = @_;
if ($states)
{
@{$$self{states}} = split(/\|/,$states);
}
}

=item C<restore_aldb()>
Expand Down
17 changes: 8 additions & 9 deletions lib/Insteon/Lighting.pm
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ sub new

my $self = new Insteon::BaseDevice($p_deviceid,$p_interface);
bless $self,$class;
# include very basic states
@{$$self{states}} = ('on','off');
# include very basic states; off first so web interface up/down works
$self->set_states('off','on');

return $self;
}
Expand Down Expand Up @@ -193,13 +193,7 @@ sub convert_level
my $level = 'ff';
if (defined ($on_level)) {
$on_level =~ s/(\d+)%?/$1/;
if ($on_level eq '100') {
$level = 'ff';
} elsif ($on_level eq '0') {
$level = '00';
} else {
$level = sprintf('%02X',$on_level * 2.55);
}
$level = sprintf('%02X',int(($on_level * 2.55) + .5));
}
return $level;
}
Expand All @@ -216,6 +210,11 @@ sub new

my $self = new Insteon::BaseLight($p_deviceid,$p_interface);
bless $self,$class;

if( $main::config_parms{insteon_menu_states}) {
$self->set_states(split( ',', $main::config_parms{insteon_menu_states}));
}

return $self;
}

Expand Down
4 changes: 0 additions & 4 deletions lib/http_server.pl
Original file line number Diff line number Diff line change
Expand Up @@ -2367,9 +2367,7 @@ sub html_item_state {
my $object_name = $object->{object_name};
my $object_name2 = &pretty_object_name($object_name);
my $isa_X10 = UNIVERSAL::isa($object, 'X10_Item');
# my $isa_X10 = $object->isa('X10_Item'); # This will abend if object is not an object
my $isa_EIB2 = UNIVERSAL::isa($object, 'EIB2_Item');
my $isa_insteon = UNIVERSAL::isa($object, 'Insteon_Device');

# If not a state item, just list it
unless ($isa_X10 or UNIVERSAL::isa($object, 'Group') or exists $object->{state} or $object->{states}) {
Expand All @@ -2384,9 +2382,7 @@ sub html_item_state {
# If >2 possible states, add a Select pull down form
my @states;
@states = @{$object->{states}} if $object->{states};
# print "db on=$object_name ix10=$isa_X10 s=@states\n";
@states = split ',', $config_parms{x10_menu_states} if $isa_X10;
@states = split ',', $config_parms{insteon_menu_states} if $isa_insteon;

@states = qw(on off) if UNIVERSAL::isa($object, 'X10_Appliance');

Expand Down
43 changes: 29 additions & 14 deletions web/bin/button.pl
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
#
# Create buttons with JPEG images generated on-the-fly using the GD module.
#
# For text buttons: <img src="/bin/button.pl?<text you want>" border="0">
# Example: <img src="/bin/button.pl?Close%20Garage%20Door" border="0">
#
# For item buttons: <img src="/bin/button.pl?<item_name>&item&<item_state>" border="0">
# Example: <img src="/bin/button.pl?$breakfast_nook_light&item&off" border="0">
#

$^W = 0; # Avoid redefined sub msgs

# Create jpeg buttons on-the-fly with GD module
# For text buttons: <img src="/bin/button.pl?text you want" border="0">
# For item buttons: <img src="/bin/button.pl?item_name&item&item_state" border="0">

# Authority: anyone

my ($text, $type, $state, $bg_color, $file_name_only) = @ARGV;
Expand All @@ -29,10 +34,14 @@
$image_file =~ s/ /_/g; # Blanks in file names are nasty
$image_file = "/cache/$image_file.jpg";


# Set to 1 if you'd like to disable the image cache. Normally you should
# not need to do this because it affects performance (MisterHouse needs
# to re-generate the button image every time). This is only useful if you
# are tweaking your button images and need new images re-generated every
# time the button generation script (this script) is called.
my $nocache = 0;
#$nocache = 1;
if (-e "$config_parms{data_dir}$image_file" or $nocache) {

if (-e "$config_parms{data_dir}$image_file" && !$nocache) {
return $image_file if $file_name_only;
# print "Returning data from: $image_file\n";
my $data = file_read "$config_parms{data_dir}$image_file";
Expand All @@ -41,21 +50,27 @@

# Look for an icon
my ($icon, $light);

if ($type eq 'item') {
my $object = &get_object_by_name($text);
($icon) = &http_get_local_file(&html_find_icon_image($object, 'voice'));
# $light = 1 if $text =~ /light/i or $text =~ /lite/i;
$light = 1 if $object->isa('X10_Item') and !$object->isa('X10_Appliance');
$light = 1 if $object->isa('EIB2_Item');
}
else {
# Uncomment this to put in images into group, category icons. Seem too small to be useful.
# ($icon) = &http_get_local_file(&html_find_icon_image($text, 'text'));

if ( ($object->isa('X10_Item') and !$object->isa('X10_Appliance') )
|| $object->isa('Insteon::BaseLight')
|| $object->isa('EIB2_Item')
|| $text =~ /light|lite/i) {
$light = 1;
}
} else {
# Uncomment this to put in images into group, category icons. Seem too small to be useful.
#($icon) = &http_get_local_file(&html_find_icon_image($text, 'text'));
}

undef $icon if $icon and $icon !~ /.jpg$/i; # GD does not do gifs :(
my $image_icon = GD::Image->newFromJpeg($icon) if $icon;

my $image;

if ($image_icon or $type eq 'item') {

# Template = blank_on/off/unk or blank_light_on/off/dim
Expand Down
56 changes: 44 additions & 12 deletions web/bin/button_action.pl
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,62 @@
my ($state, $x, $y) = $state_xy =~ /(\S+)\?(\d+),(\d+)/;
#print "db ln=$list_name, i=$item, s=$state_xy xy=$x,$y\n";

# Do not dim the dishwasher :)
unless (eval qq|$item->isa('X10_Appliance') or $item->isa('Fan_Motor') or $item->isa('Insteon_Device')|) {
$state = 'dim' if $x < 40; # Left side of image
$state = 'brighten' if $x > 110; # Right side of image
}
my $object = &get_object_by_name($item);

if ($object->isa('X10_Item') && !$object->isa('X10_Appliance') ) {
# Do not dim the dishwasher :)

if (eval qq|$item->isa('EIB7_Item')|) { # Motor/drive states are stop/up/down
# Dim if clicked on left side of image, brighten if clicked on right
# side of image, or use state passed through the button URL if clicked
# in the center of the image.
if ($x < 40) {
$state = 'dim';
} elsif ($x > 110) {
$state = 'brighten';
}
} elsif ($object->isa('EIB7_Item') ) { # Motor/drive states are stop/up/down
$state = 'stop';
$state = 'down' if $x < 40; # Left side of image
$state = 'up' if $x > 110; # Right side of image
}
} elsif ($object->isa('Insteon::DimmableLight') ) {
my @states = $object->get_states();
my $curr_state = $object->state();

#if (eval qq|$item->isa('Insteon_Device'|) {
# $state = "toggle";
#}
# Find the index into @states for the element that corresponds to the
# current state.
my ($index) = grep { $states[$_] eq $curr_state } 0..$#states;

eval qq|$item->set("$state", 'web')|;
print "button_action.pl eval error: $@\n" if $@;
# Dim if clicked on left side of image, brighten if clicked on right
# side of image, or use state passed through the button URL if clicked
# in the center of the image.
if ($x < 40) {
$index-- if ($index); # Can't dim if light is off
$state = $states[$index];
} elsif ($x > 110) {
$index++ if ($index != $#states); # Can't brighten if light is fully on
$state = $states[$index];
}
}

$object->set("$state", 'web');

# print "dbx4a i=$item s=$state\n";
# my $object = &get_object_by_name($item);
# $state = $$object{state};
# print "dbx4b i=$item s=$state\n";

# Internal state of INSTEON devices does not change immediately after
# clicking on the button. That is because, unlike X10 devices (for example),
# an acknowledgement from the INSTEON device needs to be received so MH
# can change the internal state. If we finish the HTTP transaction before
# the acknowledge comes back then the resulting HTML page will display the
# object that was just clicked on in the old state. This delay here prevents
# this problem at the expense of, well, an extra delay. As this is
# experimental, and this delay causes MH to pause for the duration of the
# delay, this is currently disabled by default. But feel free to enable
# to see if things improve.
#sleep(1);

my $h = &referer("/bin/list_buttons.pl?$list_name");

return &http_redirect($h);
2 changes: 2 additions & 0 deletions web/bin/list_buttons.pl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
my $icon;
if ($Info{module_GD}) {
# Use custom icons if they exist
$state = 'on' if $state eq '100%';
$state = 'off' if $state eq '0%';
$icon = $state;
$icon = 'dim' if $state =~ /d+/;
my $image = "/graphics/light-" . lc $item . "_" . $icon . ".gif";
Expand Down