diff --git a/lib/Nanoleaf_Aurora.pm b/lib/Nanoleaf_Aurora.pm index 8308f371d..f821d744e 100644 --- a/lib/Nanoleaf_Aurora.pm +++ b/lib/Nanoleaf_Aurora.pm @@ -1,6 +1,6 @@ package Nanoleaf_Aurora; -# v1.1.01 +# v2.0 #if any effect is changed, by definition the static child should be set to off. #cmd data returns, need to check by command @@ -43,6 +43,17 @@ use IO::Socket::INET; # $aurora_static1 = new Nanoleaf_Aurora_Static($aurora, "effect string"); # $aurora_comm = new Nanoleaf_Aurora_Comm($aurora); +#Set static string, ie "3 82 1 255 0 255 0 20 60 1 0 255 255 0 20 118 1 0 0 0 0 20", + +# = 3 +# = 1 +#Panel 1: +#PanelId: 82, R:255, G:0, B:255, W:0, TransitionTime:20*0.1s +#Panel 2: +#PanelId: 60, R:0, G:255, B:255, W:0, TransitionTime:20*0.1s +#Panel 3: +#PanelId:118, R:0, G:0, B:0, W:0, TransitionTime:20*0.1s + # MH.INI settings # If the token is auto generated, it will be written to the mh.ini. MH.INI settings can be used # instead of object definitions @@ -88,27 +99,32 @@ $rest{off} = "state"; #$rest{set_effect} = "effects/select"; $rest{set_effect} = "effects"; $rest{set_static} = "effects"; +$rest{set_hsb} = "effects"; #$rest{brightness} = "state/brightness"; #$rest{brightness2} = "state/brightness"; $rest{brightness} = "state"; $rest{brightness2} = "state"; $rest{get_static} = "effects"; +$rest{get_hsb} = "effects"; $rest{identify} = "identify"; our %opts; $opts{info} = "-ua"; $opts{auth} = "-json -post '{}'"; -$opts{on} = "-response_code -json -put '{\"on\":true}'"; -$opts{off} = "-response_code -json -put '{\"on\":false}'"; +$opts{on} = "-response_code -json -put '{\"on\":{\"value\":true}}'"; +$opts{off} = "-response_code -json -put '{\"on\":{\"value\":false}}'"; $opts{set_effect} = "-response_code -json -put '{\"select\":"; $opts{set_static} = "-response_code -json -put '{\"write\":{\"command\":\"display\",\"version\":\"1.0\",\"animType\":\"static\",\"animData\":"; +$opts{set_hsb} = "-response_code -json -put '{\"write\":{\"command\":\"display\",\"version\":\"1.0\",\"animType\":\"solid\",\"palette\":"; #$opts{brightness} = "-response_code -json -put '{\"value\":"; #$opts{brightness2} = "-response_code -json -put '{\"increment\":"; $opts{brightness} = "-response_code -json -put '{\"brightness\":{\"value\":"; $opts{brightness2} = "-response_code -json -put '{\"brightness\":{\"increment\":"; $opts{get_static} = "-response_code -json -put '{\"write\":{\"command\":\"request\",\"version\":\"1.0\",\"animName\":\"*Static*\"}}'"; +$opts{get_hsb} = "-response_code -json -put '{\"write\":{\"command\":\"request\",\"version\":\"1.0\",\"animName\":\"*Solid*\"}}'"; $opts{identify} = "-response_code -json -put '{}'"; + my $api_path = "/api/v1"; our %active_auroras = (); @@ -129,7 +145,7 @@ sub new { $self->{updating} = 0; $self->{data}->{retry} = 0; $self->{status} = ""; - $self->{module_version} = "v1.1.01"; + $self->{module_version} = "v1.2.01"; $self->{ssdp_timeout} = 4000; $self->{last_static} = ""; @@ -164,7 +180,7 @@ sub new { $self->{poll_process}->set_output( $self->{poll_data_file} ); @{ $self->{cmd_queue} } = (); $self->{cmd_data_file} = "$::config_parms{data_dir}/Aurora_cmd_" . $self->{name} . ".data"; - unlink "$::config_parms{data_dir}/Auroroa_cmd_" . $self->{name} . ".data"; + unlink "$::config_parms{data_dir}/Aurora_cmd_" . $self->{name} . ".data"; $self->{cmd_process} = new Process_Item; $self->{cmd_process}->set_output( $self->{cmd_data_file} ); $self->{init} = 0; @@ -369,7 +385,7 @@ sub process_check { main::print_log( "[Aurora:" . $self->{name} . "] Background Command " . $self->{cmd_process_mode} . " process completed" ) if ( $self->{debug} ); $self->get_data(); #poll since the command is done to get a new state - + $self->{data}->{info}->{palette} = 0; #assume this is not a solid effect change. my $file_data = &main::file_read( $self->{cmd_data_file} ); my ($responsecode) = $file_data =~ /^RESPONSECODE:(\d+)\n/; @@ -379,7 +395,7 @@ sub process_check { #print "success\n\n" if (($responsecode == 204) or ($responsecode == 200)); my $com_status = "offline"; - if ( ( $responsecode == 204 ) or ( $responsecode == 200 ) ) { + if ( ( $responsecode == 204 ) or ( $responsecode == 200 ) or ( $responsecode == 404) ) { #added 404 since a few calls can generate 404 if the data isn't present (like querying static without a static scene active) $com_status = "online"; # Successful commands should be [200 OK, 204 No Content] @@ -422,6 +438,24 @@ sub process_check { } } + if ( $self->{cmd_process_mode} eq "get_hsb" ) { + main::print_log( "[Aurora:" . $self->{name} . "] get_hsb returned" ); + #strangely, this query has proper hue/sat/brightness information and the general query doesn't +#TODO, figure out brightness when a solid +#print Dumper $data->{palette}; + for ( my $i = 0; $i < @{$data->{palette}}; $i++ ) { + $self->{data}->{info}->{brightness}->{value2} .= ${$data->{palette}}[$i]->{brightness} . ","; + $self->{data}->{info}->{saturation}->{value2} .= ${$data->{palette}}[$i]->{saturation} . ","; + $self->{data}->{info}->{hue}->{value2} = ${$data->{palette}}[$i]->{hue} . ","; + } + chop($self->{data}->{info}->{brightness}->{value2}); + chop($self->{data}->{info}->{saturation}->{value2}); + chop($self->{data}->{info}->{hue}->{value2}); +#print "B=".$self->{data}->{info}->{brightness}->{value2}." S=".$self->{data}->{info}->{saturation}->{value2}."H=".$self->{data}->{info}->{hue}->{value2} ."\n"; + $self->{data}->{info}->{palette} = 1; + + } + } $self->poll; @@ -721,7 +755,6 @@ sub print_info { } else { main::print_log( "[Aurora:" . $self->{name} . "] Rhythm Module: Not Present"); } - main::print_log( "[Aurora:" . $self->{name} . "] Firmware: " . $self->{data}->{info}->{firmwareVersion} ); main::print_log( "[Aurora:" . $self->{name} . "] Connected Panels: " . $self->{data}->{panels} ); main::print_log( "[Aurora:" . $self->{name} . "] Panel Size: " . $self->{data}->{panel_size} ); @@ -737,8 +770,22 @@ sub print_info { else { main::print_log( "[Aurora:" . $self->{name} . "] State:\t OFF" ); } - main::print_log( - "[Aurora:" . $self->{name} . "] Mode:\t " . $self->{data}->{info}->{state}->{colorMode} . " " . $self->{data}->{info}->{effects}->{select} ); + main::print_log("[Aurora:" . $self->{name} . "] Mode:\t " . $self->{data}->{info}->{state}->{colorMode} . " " . $self->{data}->{info}->{effects}->{select} ); + + if ($self->{data}->{info}->{palette} == 1) { + main::print_log( "[Aurora:" + . $self->{name} + . "] Brightness:\t " + . $self->{data}->{info}->{state}->{brightness}->{value2}); + main::print_log( "[Aurora:" + . $self->{name} + . "] Hue:\t\t " + . $self->{data}->{info}->{state}->{hue}->{value2}); + main::print_log( "[Aurora:" + . $self->{name} + . "] Saturation:\t " + . $self->{data}->{info}->{state}->{sat}->{value2}); + } else { main::print_log( "[Aurora:" . $self->{name} . "] Brightness:\t " @@ -760,12 +807,13 @@ sub print_info { . $self->{data}->{info}->{state}->{sat}->{min} . "-" . $self->{data}->{info}->{state}->{sat}->{max} . "]" ); + } main::print_log( "[Aurora:" . $self->{name} . "] Color Temp:\t " - . $self->{data}->{info}->{state}->{brightness}->{value} . "\t[" - . $self->{data}->{info}->{state}->{brightness}->{min} . "-" - . $self->{data}->{info}->{state}->{brightness}->{max} + . $self->{data}->{info}->{state}->{ct}->{value} . "\t[" + . $self->{data}->{info}->{state}->{ct}->{min} . "-" + . $self->{data}->{info}->{state}->{ct}->{max} . "]" ); main::print_log( "[Aurora:" . $self->{name} . "] -- Active Effects --" ); if ( defined $self->{data}->{info}->{effects}->{list} ) { @@ -838,7 +886,11 @@ sub process_data { } $self->{init_data} = 1; } - + if (( lc $self->{data}->{info}->{effects}->{select} eq "*dynamic*" ) or ( lc $self->{data}->{info}->{effects}->{select} eq "*solid*" )) { + $self->{data}->{info}->{palette} = 1; + } else { + $self->{data}->{info}->{palette} = 0; + } if ( $self->{previous}->{info}->{firmwareVersion} ne $self->{data}->{info}->{firmwareVersion} ) { main::print_log( "[Aurora:" . $self->{name} . "] Firmware changed from $self->{previous}->{info}->{firmwareVersion} to $self->{data}->{info}->{firmwareVersion}" ); @@ -1051,6 +1103,17 @@ sub set_static { } +#TODO set hue and Saturation directly +sub set_hsb { + my ( $self, $hue, $saturation, $brightness ) = @_; + + my $params = $opts{set_hsb} . '[{ "hue":' . $hue . ',"saturation":' . $saturation . ',"brightness":' . $brightness . "}],"; + $params .= '"colorType": "HSB"}}' . "'"; + + $self->_push_JSON_data( 'set_hsb', $params ); + return ('1'); +} + sub check_static { my ( $self, $string, $prev_effect ) = @_; @@ -1083,6 +1146,39 @@ sub get_static { return ('1'); } +sub get_hsb { + my ($self) = @_; + + $self->_push_JSON_data('get_hsb'); + return ('1'); +} + +sub hue { + my ( $self) = @_; + my $return = $self->{data}->{info}->{state}->{hue}->{value}; + $return = $self->{data}->{info}->{state}->{hue}->{value2} if ($self->{data}->{info}->{palette} == 1); + return $return; +} + +sub saturation { + my ( $self) = @_; + my $return = $self->{data}->{info}->{state}->{sat}->{value}; + $return = $self->{data}->{info}->{state}->{sat}->{value2} if ($self->{data}->{info}->{palette} == 1); + return $return; +} + +sub brightness { + my ( $self) = @_; + my $return = $self->{data}->{info}->{state}->{brightness}->{value}; + $return = $self->{data}->{info}->{state}->{brightness}->{value2} if ($self->{data}->{info}->{palette} == 1); + return $return; +} + +sub ct { + my ( $self) = @_; + return $self->{data}->{info}->{state}->{brightness}->{value} +} + sub print_discovery_info { my ($self) = @_; @@ -1227,6 +1323,7 @@ sub new { $$self{loop} = 0; $$self{string} = $static_string if ( defined $static_string ); $object->register( $self, 'static' ); + $self->SUPER::set('off'); #turn off at initialization and then set when data comes in. return $self; } @@ -1331,4 +1428,6 @@ sub set { # v1.0.13 - ability to print and purge the command queue in case a network error prevents clearing, empty poll queue if max reached # v1.0.14 - commands now queue properly # v1.0.15 - fixed polling -# v1.1.01 - firmware v2.2.0 and rhythm module \ No newline at end of file +# v1.1.01 - firmware v2.2.0 and rhythm module +# v1.1.03 - fixed a few typos +# v2.0.00 - added in hue/Saturation ability diff --git a/lib/http_server.pl b/lib/http_server.pl index ce64ee87e..6a6f35875 100644 --- a/lib/http_server.pl +++ b/lib/http_server.pl @@ -684,6 +684,11 @@ sub http_process_request { # print "Error, no SET argument: $header\n" unless $get_arg; + #allow setby to be passed in URL. Objects can then take a setby argument if there is an alternative action. + #used for RGB. Downside is that the true setby (web) would be lost. + my $get_arg_setby = ""; + ($get_arg_setby) = $get_arg =~ /select_setby=(\S+)/; + $get_arg =~ s/select_setby=(\S+)// if ($get_arg_setby); # Change select_item=$item&select_state=abc to $item=abc $get_arg =~ s/select_item=(\S+)\&&select_state=/$1=/; @@ -758,10 +763,10 @@ sub http_process_request { # Can be a scalar or a object $state =~ tr/\"/\'/; # So we can use "" to quote it - + $get_arg_setby = "web [$client_ip_address]" unless $get_arg_setby; # my $eval_cmd = qq[($item and ref($item) and UNIVERSAL::isa($item, 'Generic_Item')) ? my $eval_cmd = qq[($item and ref($item) ne '' and ref($item) ne 'SCALAR' and $item->can('set')) ? - ($item->set("$state", "web [$client_ip_address]")) : ($item = "$state")]; + ($item->set("$state", "$get_arg_setby")) : ($item = "$state")]; print "SET eval: $eval_cmd\n" if $main::Debug{http}; eval $eval_cmd; print "SET eval error. cmd=$eval_cmd error=$@\n" if $@; diff --git a/lib/json_server.pl b/lib/json_server.pl index fa3e1c1e5..79b747630 100755 --- a/lib/json_server.pl +++ b/lib/json_server.pl @@ -883,34 +883,52 @@ sub json_get { } if ( $path[0] eq 'security' ) { - #check if $Authorized if (defined $path[1] and $path[1] eq 'authorize') { - print "IN AUTHORIZE\n"; + # Passwords are stored as MD5 hashes in the user data file + # Take that MD5, then take the current date (in YYYYDDMM format) and then calculate + # an authorization MD5 value. Adding in the current date means that the lifespan of a compromised + # password token is at most 1 day. my $status = ""; if ($args{user} && $args{user}[0] eq "") { - $status = "Empty Username"; + $status = "fail"; + &main::print_log("json_server.pl: ERROR, authorize attempt with no username"); } elsif ($args{password} && $args{password}[0] eq "") { - $status = "Empty Password"; + $status = "fail"; + &main::print_log("json_server.pl: ERROR, authorize attempt with no password"); + } else { my $password = &Groups('getpw','',$args{user}[0]); my $time_seed = &main::time_date_stamp('18',$Time); - my $time_seedY = &main::time_date_stamp('18',$Time - 86400); - my $time_seedT = &main::time_date_stamp('18',$Time + 86400); - + #to account for clock drift, check today and tomorrow values around midnight #if time is between 11:55 and midnight then also check tomorrow #if time is between midnight and 00:05 then also check yesterday - print "PW=$password, time_seed=$time_seed, $time_seedY, $time_seedT\n"; + if (time_greater_than("11:55 PM")) { + my $time_seedT = &main::time_date_stamp('18',$Time + 86400); + my $pwdcheck1 = md5_hex($password . $time_seedT); + $status = "success" if (lc $args{password}[0] eq lc $pwdcheck1); + } + if (time_less_than("00:05 AM")) { + my $time_seedY = &main::time_date_stamp('18',$Time - 86400); + my $pwdcheck2 = md5_hex($password . $time_seedY); + $status = "success" if (lc $args{password}[0] eq lc $pwdcheck2); + } + #print "PW=$password, time_seed=$time_seed"; my $pwdcheck = md5_hex($password . $time_seed); - print "PWC=$pwdcheck\n"; + #print "PWC=$pwdcheck\n"; - if (lc $args{password}[0] eq lc $pwdcheck) { + if ($status eq "" and (lc $args{password}[0] eq lc $pwdcheck)) { $status = "success"; + &main::print_log("json_server.pl: INFO, user $args{user}[0] successfully authenticated"); + } else { $status = "fail"; + &main::print_log("json_server.pl: WARNING, user $args{user}[0] authentication attempt failed"); + } } $json_data{security}->{authorize} = $status; } else { + #check if $Authorized my $ref; my $users; my $found = 0; @@ -1508,7 +1526,7 @@ sub json_object_detail { my %json_complete_object; my @f = qw( category filename measurement rf_id set_by members state states state_log type label sort_order groups hidden parents schedule logger_status - idle_time text html seconds_remaining fp_location fp_icons fp_icon_set img link level); + idle_time text html seconds_remaining fp_location fp_icons fp_icon_set img link level rgb); # Build list of fields based on those requested. foreach my $f ( sort @f ) { @@ -1551,6 +1569,14 @@ sub json_object_detail { $value = $a if ( defined $a and $a ne "" ); #don't return a null value } + elsif ( $f eq 'rgb' ) { + my ($a,$b,$c) = $object->$method; + + $value = "$a,$b,$c" if (( defined $a and $a ne "" ) #don't return a null value + and ( defined $b and $b ne "" ) + and ( defined $c and $c ne "" )); + } + #if ( $f eq 'hidden' ) { # my $a = $object->$method; # if ($a == 1 or $a eq "1") { diff --git a/web/ia7/house/whatsnew.shtml b/web/ia7/house/whatsnew.shtml index e717af24e..8dd1f9b0e 100644 --- a/web/ia7/house/whatsnew.shtml +++ b/web/ia7/house/whatsnew.shtml @@ -4,6 +4,21 @@
+
+ +
+
+
    +
  • Color dot shows on objects that have color controls +
  • Modal has RGB sliders that can change the color. Click OK or outside modal to close +
+
+
+

@@ -44,7 +59,7 @@
  • Users and Groups can be created from the GUI -
  • MH can be used as an authentication source /json/security/authorize?username=&password=MD5HASHYYYYDDMM +
  • MH can be used as an authentication source /json/security/authorize?username=&password=MD5(MD5(PWD)YYYYDDMM)

diff --git a/web/ia7/include/javascript.js b/web/ia7/include/javascript.js index 719fc8088..747b861db 100644 --- a/web/ia7/include/javascript.js +++ b/web/ia7/include/javascript.js @@ -1,5 +1,5 @@ -var ia7_ver = "v2.0.690"; +var ia7_ver = "v2.0.820"; var coll_ver = ""; var entity_store = {}; //global storage of entities var json_store = {}; @@ -534,7 +534,7 @@ function loadPrefs (config_name){ //show ia7 prefs, args ia7_prefs, ia7_rrd_pref contentType: 'application/json', data: JSON.stringify(json_store.ia7_config), success: function( data, status, error ){ - console.log("data="+data+" status="+status+" error="+error); + //console.log("data="+data+" status="+status+" error="+error); //throw up red warning if the response isn't good from MH $('#lastResponse').modal({ show: true @@ -561,8 +561,6 @@ function loadPrefs (config_name){ //show ia7 prefs, args ia7_prefs, ia7_rrd_pref config_modal_loop = setTimeout(function(){ $('#lastResponse').modal('hide'); }, 3000); - console.log("status="+status); - console.log("error="+error); $(".modal-header").append($("

 Failure: "+message+"

")); $(".write-status").delay(4000).fadeOut("slow", function () { $(this).remove(); }); } @@ -605,7 +603,6 @@ function security (){ } } for (var i in data){ - console.log("sec="+i); if (i == "group") { html += ""+ i + ""; //if data[i].length > 0 otherwise print no group data found @@ -644,7 +641,6 @@ function security (){ row++; var groups=""; for (var p in data.user[j]) { - console.log(p + ":" + data.user[j][p] + "
"); groups += group_pos[p]+","; } groups = groups.slice(0,-1); @@ -750,7 +746,6 @@ function security (){ } }); $('.security-submit').off('click').on('click', function(){ - console.log("submit"); var data = {}; var name = '#new_group'; var pk = 'add_group'; @@ -766,7 +761,6 @@ function security (){ data.name = $(entity_name).val(); if (data.name == '') { $(entity_name).css('border-color', 'red'); - console.log('return1'+entity_name); return } else { $(entity_name).css('border-color', ''); @@ -781,7 +775,6 @@ function security (){ } else { var groups = $('#usr_groups_'+row).editable('getValue').user_new; data.groups = []; - console.log("g="+JSON.stringify(groups)); for (var i in groups) { data.groups.push(group_data[groups[i]-1].text); } @@ -795,7 +788,6 @@ function security (){ data.submit = "true"; MD5(data.password); } - console.log("row="+row+" data="+JSON.stringify(data)); $.ajax({ url: "/json/security", type: 'post', @@ -1058,7 +1050,7 @@ var loadList = function() { var button_text = ''; var button_html = ''; var entity_arr = []; - URLHash.fields = "category,label,sort_order,members,state,states,state_log,hidden,type,text,schedule,logger_status,link"; + URLHash.fields = "category,label,sort_order,members,state,states,state_log,hidden,type,text,schedule,logger_status,link,rgb"; $.ajax({ type: "GET", url: "/json/"+HashtoJSONArgs(URLHash), @@ -1171,6 +1163,11 @@ var loadList = function() { if (json_store.ia7_config.prefs.always_double_buttons == "yes") { if (name.length < 30) dbl_btn = "
"; } + var btn_rgb = ""; + if (json_store.objects[entity].rgb !== undefined) { + btn_rgb = ''; + btn_rgb += ''; + } // direct control item, differentiate the button var btn_direct = ""; if (json_store.ia7_config.objects !== undefined && json_store.ia7_config.objects[entity] !== undefined) { @@ -1180,7 +1177,7 @@ var loadList = function() { } button_html = "
"; + button_html += name+btn_rgb+dbl_btn+""+json_store.objects[entity].state+"
"; entity_arr.push(button_html); } }//entity each loop @@ -1380,6 +1377,7 @@ var sliderDetails = function (states) { var pct = 0; var slider_array = []; for(var i = 0; i < states.length; i++) { +//TODO gives tostring error on null object items sensor_garage_motion_off var val = states[i].toString(); if(val.indexOf('%') != -1) pct=1; val = val.replace(/\%/g,''); @@ -1418,7 +1416,7 @@ var sortArrayByArray = function (listArray, sortArray){ //Used to dynamically update the state of objects var updateList = function(path) { var URLHash = URLToHash(); - URLHash.fields = "state,state_log,schedule,logger_status,type"; + URLHash.fields = "state,state_log,schedule,logger_status,type,rgb"; URLHash.long_poll = 'true'; URLHash.time = json_store.meta.time; if (updateSocket !== undefined && updateSocket.readyState != 4){ @@ -1440,17 +1438,21 @@ var updateList = function(path) { // This is not an entity, skip it if (json.data[entity] === undefined ) continue; if (json.data[entity].type === undefined) continue; - + if ($('button[entity="'+entity+'"]').hasClass('btn-voice-cmd')) continue; //don't change color for voice commands var color; if (json.data[entity].state === undefined) { color = "default"; } else { color = getButtonColor(json.data[entity].state); } - $('button[entity="'+entity+'"]').find('.pull-right').text( - json.data[entity].state); + var btn_rgb = ""; + if (json.data[entity].rgb !== undefined) { + $('button[entity="'+entity+'"]').find('.object-color').css("color",'rgb('+json.data[entity].rgb+')'); + } + $('button[entity="'+entity+'"]').find('.object-state').text(json.data[entity].state); $('button[entity="'+entity+'"]').removeClass("btn-default"); $('button[entity="'+entity+'"]').removeClass("btn-success"); + $('button[entity="'+entity+'"]').removeClass("btn-purple"); $('button[entity="'+entity+'"]').removeClass("btn-warning"); $('button[entity="'+entity+'"]').removeClass("btn-danger"); $('button[entity="'+entity+'"]').removeClass("btn-info"); @@ -1489,7 +1491,7 @@ var updateItem = function(item,link,time) { time = ""; } var path_str = "/objects" // override, for now, would be good to add voice_cmds - var arg_str = "fields=state,states,label,state_log,schedule,logger_status&long_poll=true&items="+item+"&time="+time; + var arg_str = "fields=state,states,label,state_log,schedule,logger_status,rgb&long_poll=true&items="+item+"&time="+time; $.ajax({ type: "GET", url: "/LONG_POLL?json('GET','"+path_str+"','"+arg_str+"')", @@ -1501,9 +1503,9 @@ var updateItem = function(item,link,time) { JSONStore(json); requestTime = json_store.meta.time; var color = getButtonColor(json.data[item].state); - $('button[entity="'+item+'"]').find('.pull-right').text( - json.data[item].state); + $('button[entity="'+item+'"]').find('.object-state').text(json.data[item].state); $('button[entity="'+item+'"]').removeClass("btn-default"); + $('button[entity="'+item+'"]').removeClass("btn-purple"); $('button[entity="'+item+'"]').removeClass("btn-success"); $('button[entity="'+item+'"]').removeClass("btn-warning"); $('button[entity="'+item+'"]').removeClass("btn-danger"); @@ -1567,9 +1569,10 @@ var updateStaticPage = function(link,time) { if ($(this).attr('entity') != '' && json.data[$(this).attr('entity')] != undefined ) { //need an entity item for this to work. entity = $(this).attr('entity'); var color = getButtonColor(json.data[entity].state); - $('button[entity="'+entity+'"]').find('.pull-right').text(json.data[entity].state); + $('button[entity="'+entity+'"]').find('.object-state').text(json.data[entity].state); $('button[entity="'+entity+'"]').removeClass("btn-default"); $('button[entity="'+entity+'"]').removeClass("btn-success"); + $('button[entity="'+entity+'"]').removeClass("btn-purple"); $('button[entity="'+entity+'"]').removeClass("btn-warning"); $('button[entity="'+entity+'"]').removeClass("btn-danger"); $('button[entity="'+entity+'"]').removeClass("btn-info"); @@ -1744,7 +1747,7 @@ var loadCollection = function(collection_keys) { if (name.length < 30) dbl_btn = "
"; var button_html = "
"; + button_html += name+dbl_btn+""+json_store.objects[item].state+"
"; button_html = "
" + button_html + "
"; entity_arr.push(button_html); items += item+","; @@ -1866,7 +1869,6 @@ var loadCollection = function(collection_keys) { }); // test multiple items at some point - console.log("items="+items); updateItem(items); } loadModule('developer'); @@ -1965,7 +1967,6 @@ var something_went_wrong = function(module,text,fadeout) { } }); if (found) return; - console.log("creating SWW window for "+module); var type = "dark"; var mobile = ""; if ($(window).width() <= 768) { // override the responsive mobile top-buffer @@ -2148,14 +2149,13 @@ var get_wi_icon = function (conditions,rain,snow,night) { var get_notifications = function(time) { if (updateSocketN !== undefined && updateSocketN.readyState != 4){ // Only allow one update thread to run at once - console.log ("Notify aborted "+updateSocketN.readyState); + //console.log ("Notify aborted "+updateSocketN.readyState); updateSocketN.abort(); } if (time === undefined) time = new Date().getTime(); //this triggers on failure. var arg_str = "long_poll=true&time="+time; var path_str = "/notifications"; var requestTime; - console.log("in get_notifications"); updateSocketN = $.ajax({ type: "GET", url: "/LONG_POLL?json('GET','"+path_str+"','"+arg_str+"')", @@ -2253,9 +2253,7 @@ var ajax_req_success = function(module) { var errors = 0; for(var i in req_errors) { errors += req_errors[i]; - console.log("success reconnect "+i+" "+req_errors[i]+" "+errors); } - console.log("In success reconnect for "+module+ ":"+errors); // if (errors === 0) { //$("#mh_title").css("color", "black"); @@ -2394,10 +2392,14 @@ var graph_rrd = function(start,group,time) { var new_data = 1; var data_timeout = 0; var refresh = 60; //refresh data every 60 seconds by default - - if (!$('#rrd-graph').is(':visible')) { + if (!$('#rrd-graph').is(':visible')) { //If not on an RRD page then stop the timer, otherwise show the loader + //console.log("checking loader "+URLHash.path+" : x : "+$('#top-graph').length); + if (URLHash.path === undefined || URLHash.path.substring(0,4) !== "/rrd") { + clearTimeout(rrd_refresh_loop); + return; + } $('#loader').show(); - } + } if (json_store.ia7_config.prefs.rrd_refresh !== undefined) refresh = json_store.ia7_config.prefs.rrd_refresh; @@ -2538,6 +2540,7 @@ var graph_rrd = function(start,group,time) { var previousPoint = null; $("#rrd-graph").bind("plothover", function(event, pos, item) { +//tofixed caused a problem $("#x").text(pos.x.toFixed(2)); $("#y").text(pos.y.toFixed(2)); if (item) { @@ -3550,6 +3553,10 @@ var create_state_modal = function(entity) { var name = entity; if (json_store.objects[entity].label !== undefined) name = json_store.objects[entity].label; $('#slider').remove(); + $('#sliderR').remove(); + $('#sliderG').remove(); + $('#sliderB').remove(); + // $('#control').modal('show'); //make sure the modal is centered on all devices @@ -3569,7 +3576,11 @@ var create_state_modal = function(entity) { var modal_state = json_store.objects[entity].state; - $('#control').find('.object-title').html(name + " - " + json_store.objects[entity].state + ""); + var title = name + " - " + json_store.objects[entity].state + ""; + if (json_store.objects[entity].rgb !== undefined) { + title += ' '; + } + $('#control').find('.object-title').html(title); $('#control').find('.control-dialog').attr("entity", entity); var modal_states = json_store.objects[entity].states; // HP need to have at least 2 states to be a controllable object... @@ -3639,8 +3650,7 @@ var create_state_modal = function(entity) { } var slider_data = sliderDetails(modal_states); $('#control').find('.states').append("
"); - var val = $(".object-state").text().replace(/\%/,''); - + var val = $(".modal-object-state").text().replace(/\%/,''); var position = slider_data.values.indexOf(val); if (val == "on") position = slider_data.max; if (val == "off") position = slider_data.min; @@ -3659,7 +3669,7 @@ var create_state_modal = function(entity) { } else { if (slider_data.pct) sliderstate += "%"; } - $('#control').find('.object-state').text(sliderstate); + $('#control').find('.modal-object-state').text(sliderstate); }); $( "#slider" ).on( "slidechange", function(event, ui) { @@ -3678,7 +3688,47 @@ var create_state_modal = function(entity) { $(".get-status").delay(4000).fadeOut("slow", function () { $(this).remove(); }); }); }); - + if (json_store.objects[entity].rgb !== undefined) { + $('#control').find('.states').append("
"); + $('#control').find('.states').append("
"); + $('#control').find('.states').append("
"); + + $('#sliderR' ).slider({ + min: 0, + max: 255, + value: json_store.objects[entity].rgb.split(',')[0] + }); + $('#sliderG' ).slider({ + min: 0, + max: 255, + value: json_store.objects[entity].rgb.split(',')[1] + }); + $('#sliderB' ).slider({ + min: 0, + max: 255, + value: json_store.objects[entity].rgb.split(',')[2] + }); + $( ".rgb-slider" ).on( "slide", function(event, ui) { + var sliderstate; + if ($(this).hasClass("red-handle")) { + sliderstate = ui.value+","+$('#sliderG').slider("value")+","+$('#sliderB').slider("value"); + } else if ($(this).hasClass("green-handle")) { + sliderstate = $('#sliderR').slider("value")+","+ui.value+","+$('#sliderB').slider("value"); + } else if ($(this).hasClass("blue-handle")) { + sliderstate = $('#sliderR').slider("value")+","+$('#sliderG').slider("value")+","+ui.value; + } + $('.object-color').css("color","rgb("+sliderstate+")"); + }); + $( ".rgb-slider" ).on( "slidechange", function(event, ui) { + var sliderstate = $('#sliderR').slider("value")+","+$('#sliderG').slider("value")+","+$('#sliderB').slider("value"); + var rgb_url= '/SET;none?select_item='+$(this).parents('.control-dialog').attr("entity")+'&select_state='+sliderstate+'&select_setby=rgb'; + $.get(rgb_url).fail(function() { + $(".modal-header").append($("

 Failure: Could not send command to Misterhouse

")); + $(".get-status").delay(4000).fadeOut("slow", function () { $(this).remove(); }); + }); + }); + + } } if (slider_active) { advanced_html = "
"+advanced_html; //this is clunky but showing advanced states is kinda ugly anyways @@ -3830,7 +3880,6 @@ var create_state_modal = function(entity) { contentType: 'application/json', data: JSON.stringify(data), success: function( data, status, error ){ - console.log("data="+data+" status="+status+" error="+error); //throw up red warning if the response isn't good from MH if (data.status !== undefined || data.status == "error") { var message = "Unknown server error"; @@ -3851,8 +3900,6 @@ var create_state_modal = function(entity) { var message = "Unknown ajax request error"; var data = JSON.parse(xhr.responseText); if (data !== undefined && data.text !== undefined) message = data.text; - console.log("status="+status); - console.log("error="+error); $(".modal-header").append($("

 Failure: "+message+"

")); $(".write-status").delay(4000).fadeOut("slow", function () { $(this).remove(); }); } @@ -4035,7 +4082,6 @@ var create_develop_item_modal = function(colid,col_parent) { if (!(prop == "mode")) { // loop through properties if ($('#col_'+prop).val() !== '') json_store.collections[colid][prop] = $('#col_'+prop).val(); - console.log("prop="+prop+" val="+$('#col_'+prop).val()); } } } @@ -4382,7 +4428,6 @@ var trigger = function() { contentType: 'application/json', data: JSON.stringify(data), success: function( data, status, error ){ - console.log("trigger success data="+data+" status="+status+" error="+error); if (data.status !== undefined || data.status == "error") { console.log("error!"); } else { @@ -4732,14 +4777,14 @@ function getScript(source, callback) { var loadModule = function(name,callback) { if (modules[name].loaded == 1) { - console.log("Module "+name+" already loaded"); + //console.log("Module "+name+" already loaded"); return 0; } //loop through all modules if all if (modules[name].script !== undefined ) { for (var i = 0, len = modules[name].script.length; i < len; i++) { - console.log("loading script "+name+" "+modules[name].script[i]); + //console.log("loading script "+name+" "+modules[name].script[i]); modules[name].loaded = 1; if (modules[name].callback !== undefined && (i + 1) == (len)) callback = modules[name].callback; getScript("/ia7/include/"+modules[name].script[i], callback); @@ -4748,7 +4793,7 @@ var loadModule = function(name,callback) { if (modules[name].css !== undefined ) { for (var i = 0, len = modules[name].css.length; i < len; i++) { modules[name].loaded = 1; - console.log("loading css "+name+" "+modules[name].css[i]); + //console.log("loading css "+name+" "+modules[name].css[i]); var fileref = document.createElement("link") fileref.setAttribute("rel", "stylesheet") fileref.setAttribute("type", "text/css") diff --git a/web/ia7/index.shtml b/web/ia7/index.shtml index d06a2ae6f..f22597ec5 100644 --- a/web/ia7/index.shtml +++ b/web/ia7/index.shtml @@ -233,7 +233,6 @@ .sched-dropdown-menu { margin-left: 14px !important; } - .brightness-slider { margin-left: 16px; margin-right: 16px; @@ -249,30 +248,37 @@ width: 32px; margin-left: -16px } + .red-handle .ui-slider-handle { + background: red; + } + .green-handle .ui-slider-handle { + background: green; + } + .blue-handle .ui-slider-handle { + background: blue; + } .popover { min-width: 200px; - } - + } .mh-page-link { padding-left: 30px; } - .mh-wi-text { font-size: 15px; margin-top: 13px; } - .mh-wi-icon { margin-top: 2px; } - #option_collection { margin-top: 5px; } - .whatsnew-panel { margin-right: 15px; } + .fa-rgb-border { + text-shadow: -1px 0 #000, 0 1px #000, 1px 0 #000, 0 -1px #000; + } #loader { position: absolute; @@ -354,7 +360,7 @@