Skip to content

Commit

Permalink
Merge pull request #231 from mstovenour/fix_issue_212
Browse files Browse the repository at this point in the history
Fix issue #212 - Web can not dim/brighten Insteon lights
  • Loading branch information
mstovenour committed Jul 14, 2013
2 parents 4009e98 + 313d46e commit 507561a
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 61 deletions.
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

0 comments on commit 507561a

Please sign in to comment.