lightwaverf 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/app/views/_graphs.ejs +5 -2
  2. data/lib/lightwaverf.rb +114 -88
  3. metadata +2 -2
@@ -42,8 +42,6 @@
42
42
  energy_data.addRows( raw_data.map( function ( e ) {
43
43
  if ( e[0] !== start_date ) e[0] += start_date;
44
44
  e[0] = new Date( 1000 * e[0] ); // as it is now a timestamp
45
- // var d = '' + e[0];
46
- // e[0] = new Date( '20' + d[0] + d[1] + '-' + d[2] + d[3] + '-' + d[4] + d[5] + ' ' + d[6] + d[7] + ':' + d[8] + d[9] );
47
45
  e[1] = e[1] * 10;
48
46
  e[2] = e[2] || '';
49
47
  e[3] = e[3] || '';
@@ -66,6 +64,7 @@
66
64
  gauge.draw( gauge_data, gauge_options );
67
65
  } );
68
66
  $( function ( ) {
67
+ var key = 'foo';
69
68
  $('dt a').click( function ( ) {
70
69
  $(this).parent( ).next('dd').slideDown( );
71
70
  return false;
@@ -75,6 +74,10 @@
75
74
  var status = $a.data( 'status' ) == 'on' ? 'off' : 'on';
76
75
  $.ajax( {
77
76
  url: $a.attr('href') + '?status=' + status,
77
+ data: {
78
+ status: status,
79
+ key: key,
80
+ },
78
81
  type: 'PUT',
79
82
  success: function( js ) {
80
83
  $a.data( 'status', status );
data/lib/lightwaverf.rb CHANGED
@@ -538,19 +538,33 @@ class LightWaveRF
538
538
  match = /W=(\d+),(\d+),(\d+),(\d+)/.match data
539
539
  debug and ( p match )
540
540
  if match
541
- data = { 'message' => { 'usage' => match[1].to_i, 'max' => match[2].to_i, 'today' => match[3].to_i }}
541
+ data = {
542
+ 'message' => {
543
+ 'usage' => match[1].to_i,
544
+ 'max' => match[2].to_i,
545
+ 'today' => match[3].to_i
546
+ }
547
+ }
542
548
  data['timestamp'] = Time.now.to_s
543
549
  if note
544
550
  data['message']['annotation'] = { 'title' => title.to_s, 'text' => note.to_s }
545
551
  end
546
552
  debug and ( p data )
547
553
  begin
548
- File.open( self.get_log_file, 'a' ) do | f |
554
+ File.open( self.get_log_file, 'a' ) do | f |
549
555
  f.write( data.to_json + "\n" )
550
- end
551
- data['message']
556
+ end
557
+ file = self.get_summary_file.gsub 'summary', 'daily'
558
+ json = self.class.get_contents file
559
+ begin
560
+ data['message']['history'] = JSON.parse json
561
+ rescue => e
562
+ data['message']['error'] = 'error parsing ' + file + '; ' + e.to_s
563
+ data['message']['history_json'] = json
564
+ end
565
+ data['message']
552
566
  rescue
553
- puts 'error writing to log'
567
+ puts 'error writing to log'
554
568
  end
555
569
  end
556
570
  end
@@ -592,9 +606,15 @@ class LightWaveRF
592
606
  query_start = now - self.class.to_seconds( past )
593
607
  query_end = now + self.class.to_seconds( future )
594
608
 
595
- url = LightWaveRF.new.get_config['calendar']
596
- # url += '?ctz=' + Time.new.zone
597
- url += '?ctz=UTC'
609
+ # url = LightWaveRF.new.get_config['calendar']
610
+ url = self.get_config['calendar']
611
+
612
+ url += '?ctz=' + Time.new.zone
613
+ # url += '?ctz=UTC'
614
+ if Time.new.zone != 'UTC'
615
+ p 'time zone is ' + Time.new.zone + ' so look out...'
616
+ end
617
+
598
618
  url += '&singleevents=true'
599
619
  url += '&start-min=' + query_start.strftime( '%FT%T%:z' ).sub('+', '%2B')
600
620
  url += '&start-max=' + query_end.strftime( '%FT%T%:z' ).sub('+', '%2B')
@@ -625,20 +645,20 @@ class LightWaveRF
625
645
 
626
646
  # refresh the list of entries for the caching period
627
647
  doc.elements.each 'feed/entry' do | e |
628
- debug and ( p "-------------------")
629
- debug and ( p "Processing entry...")
648
+ debug and ( p '-------------------' )
649
+ debug and ( p 'Processing entry...' )
630
650
  event = Hash.new
631
651
 
632
652
  # tokenise the title
633
- debug and ( p "Event title is: " + e.elements['title'].text )
653
+ debug and ( p 'Event title is: ' + e.elements['title'].text )
634
654
  command = e.elements['title'].text.split
635
655
  command_length = command.length
636
- debug and ( p "Number of words is: " + command_length.to_s )
656
+ debug and ( p 'Number of words is: ' + command_length.to_s )
637
657
  if command and command.length >= 1
638
658
  first_word = command[0].to_s
639
659
  # determine the type of the entry
640
660
  if first_word[0,1] == '#'
641
- debug and ( p "Type is: state" )
661
+ debug and ( p 'Type is: state' )
642
662
  event['type'] = 'state' # temporary type, will be overridden later
643
663
  event['room'] = nil
644
664
  event['device'] = nil
@@ -647,21 +667,21 @@ class LightWaveRF
647
667
  else
648
668
  case first_word
649
669
  when 'mood'
650
- debug and ( p "Type is: mood" )
670
+ debug and ( p 'Type is: mood' )
651
671
  event['type'] = 'mood'
652
672
  event['room'] = command[1].to_s
653
673
  event['device'] = nil
654
674
  event['state'] = command[2].to_s
655
675
  modifier_start = 3
656
676
  when 'sequence'
657
- debug and ( p "Type is: sequence" )
677
+ debug and ( p 'Type is: sequence' )
658
678
  event['type'] = 'sequence'
659
679
  event['room'] = nil
660
680
  event['device'] = nil
661
681
  event['state'] = command[1].to_s
662
682
  modifier_start = 2
663
683
  else
664
- debug and ( p "Type is: device" )
684
+ debug and ( p 'Type is: device' )
665
685
  event['type'] = 'device'
666
686
  event['room'] = command[0].to_s
667
687
  event['device'] = command[1].to_s
@@ -669,18 +689,19 @@ class LightWaveRF
669
689
  if command_length > 2
670
690
  third_word = command[2].to_s
671
691
  first_char = third_word[0,1]
672
- debug and ( p "First char is: " + first_char )
692
+ debug and ( p 'First char is: ' + first_char )
673
693
  # if the third word does not start with a modifier flag, assume it's a state
674
- if first_char != '@' and first_char != '!' and first_char != '+' and first_char != '-'
675
- debug and ( p "State has been given.")
694
+ # if first_char != '@' and first_char != '!' and first_char != '+' and first_char != '-'
695
+ if /\w/.match first_char
696
+ debug and ( p 'State has been given.')
676
697
  event['state'] = command[2].to_s
677
698
  modifier_start = 3
678
699
  else
679
- debug and ( p "State has not been given." )
700
+ debug and ( p 'State has not been given.' )
680
701
  modifier_start = 2
681
702
  end
682
703
  else
683
- debug and ( p "State has not been given." )
704
+ debug and ( p 'State has not been given.' )
684
705
  event['state'] = nil
685
706
  modifier_start = 2
686
707
  end
@@ -690,24 +711,24 @@ class LightWaveRF
690
711
  # get modifiers if they exist
691
712
  time_modifier = 0
692
713
  if command_length > modifier_start
693
- debug and ( p "May have modifiers..." )
714
+ debug and ( p 'May have modifiers...' )
694
715
  when_modifiers = [ ]
695
716
  unless_modifiers = [ ]
696
717
  modifier_count = command_length - modifier_start
697
- debug and ( p "Count of modifiers is " + modifier_count.to_s )
718
+ debug and ( p 'Count of modifiers is ' + modifier_count.to_s )
698
719
  for i in modifier_start..(command_length-1)
699
720
  modifier = command[i]
700
721
  if modifier[0,1] == '@'
701
- debug and ( p "Found when modifier: " + modifier[1..-1] )
722
+ debug and ( p 'Found when modifier: ' + modifier[1..-1] )
702
723
  when_modifiers.push modifier[1..-1]
703
724
  elsif modifier[0,1] == '!'
704
- debug and ( p "Found unless modifier: " + modifier[1..-1] )
725
+ debug and ( p 'Found unless modifier: ' + modifier[1..-1] )
705
726
  unless_modifiers.push modifier[1..-1]
706
727
  elsif modifier[0,1] == '+'
707
- debug and ( p "Found positive time modifier: " + modifier[1..-1] )
728
+ debug and ( p 'Found positive time modifier: ' + modifier[1..-1] )
708
729
  time_modifier = modifier[1..-1].to_i
709
730
  elsif modifier[0,1] == '-'
710
- debug and ( p "Found negative time modifier: " + modifier[1..-1] )
731
+ debug and ( p 'Found negative time modifier: ' + modifier[1..-1] )
711
732
  time_modifier = modifier[1..-1].to_i * -1
712
733
  end
713
734
  end
@@ -718,7 +739,7 @@ class LightWaveRF
718
739
 
719
740
  # parse the date string
720
741
  event_time = /When: ([\w ]+) (\d\d:\d\d) to ([\w ]+)?(\d\d:\d\d)&nbsp;\n(.*)<br>(.*)/.match e.elements['summary'].text
721
- debug and ( p "Event times are: " + event_time.to_s )
742
+ debug and ( p 'Event times are: ' + event_time.to_s )
722
743
  start_date = event_time[1].to_s
723
744
  start_time = event_time[2].to_s
724
745
  end_date = event_time[3].to_s
@@ -729,6 +750,7 @@ class LightWaveRF
729
750
  end
730
751
 
731
752
  time_modifier += self.class.variance e.elements['title'].text
753
+ event['annotate'] = ! ( /do not annotate/.match e.elements['title'].text )
732
754
 
733
755
  debug and ( p 'Start date: ' + start_date )
734
756
  debug and ( p 'Start time: ' + start_time )
@@ -884,7 +906,7 @@ class LightWaveRF
884
906
 
885
907
  # if has modifiers, check modifiers against states
886
908
  unless event['when_modifiers'].nil?
887
- debug and ( p 'Event has when modifiers. Checking they are all met...')
909
+ debug and ( p 'Event has when modifiers. Checking they are all met...' )
888
910
 
889
911
  # determine which states apply at the time of the event
890
912
  applicable_states = [ ]
@@ -893,12 +915,12 @@ class LightWaveRF
893
915
  applicable_states.push state['name']
894
916
  end
895
917
  end
896
- debug and ( p 'Applicable states are: ' + applicable_states.to_s)
918
+ debug and ( p 'Applicable states are: ' + applicable_states.to_s )
897
919
 
898
920
  # check that each when modifier exists in appliable states
899
921
  event['when_modifiers'].each do | modifier |
900
922
  unless applicable_states.include? modifier
901
- debug and ( p 'Event when modifier not met: ' + modifier)
923
+ debug and ( p 'Event when modifier not met: ' + modifier )
902
924
  run_now = false
903
925
  break
904
926
  end
@@ -907,7 +929,7 @@ class LightWaveRF
907
929
  # check that each unless modifier does not exist in appliable states
908
930
  event['unless_modifiers'].each do | modifier |
909
931
  if applicable_states.include? modifier
910
- debug and ( p 'Event unless modifier not met: ' + modifier)
932
+ debug and ( p 'Event unless modifier not met: ' + modifier )
911
933
  run_now = false
912
934
  break
913
935
  end
@@ -927,32 +949,32 @@ class LightWaveRF
927
949
 
928
950
  triggered = [ ]
929
951
 
952
+ annotate = false
930
953
  run_list.each do | event |
931
954
  # execute based on type
932
955
  case event['type']
933
956
  when 'mood'
934
957
  p 'Executing mood. Room: ' + event['room'] + ', Mood: ' + event['state']
935
958
  result = self.mood event['room'], event['state'], debug
936
- sleep 1
937
- triggered << [ event['room'], event['device'], event['state'] ]
938
959
  when 'sequence'
939
960
  p 'Executing sequence. Sequence: ' + event['state']
940
961
  result = self.sequence event['state'], debug
941
- sleep 1
942
- triggered << [ event['room'], event['device'], event['state'] ]
943
962
  else
944
963
  p 'Executing device. Room: ' + event['room'] + ', Device: ' + event['device'] + ', State: ' + event['state']
945
964
  result = self.send event['room'], event['device'], event['state'], debug
946
- sleep 1
947
- triggered << [ event['room'], event['device'], event['state'] ]
948
965
  end
949
- self.log_timer_event event['type'], event['room'], event['device'], event['state'], result
966
+ sleep 1
967
+ triggered << [ event['room'], event['device'], event['state'] ]
968
+ if event['annotate']
969
+ annotate = true
970
+ end
971
+ self.log_timer_event event['type'], event['room'], event['device'], event['state'], result
950
972
  end
951
973
 
952
974
  # update energy log
953
975
  title = nil
954
976
  text = nil
955
- if triggered.length > 0
977
+ if annotate
956
978
  debug and ( p triggered.length.to_s + ' events so annotating energy log too...' )
957
979
  title = 'timer'
958
980
  text = triggered.map { | e | e.join ' ' }.join ', '
@@ -981,9 +1003,9 @@ class LightWaveRF
981
1003
  debug and ( puts name + ' is ' + room.to_s )
982
1004
  list += '<dt><a>' + name + '</a></dt><dd><ul>'
983
1005
  room['device'].each do | device |
984
- # link ideally relative to avoid cross domain issues
985
- link = '/room/' + room['name'].to_s + '/' + device.first.to_s
986
- list += '<li><a class="ajax off" href="' + link + '">' + room['name'].to_s + ' ' + device.first.to_s + '</a></li>'
1006
+ # link ideally relative to avoid cross domain issues
1007
+ link = '/room/' + room['name'].to_s + '/' + device.first.to_s
1008
+ list += '<li><a class="ajax off" href="' + link + '">' + room['name'].to_s + ' ' + device.first.to_s + '</a></li>'
987
1009
  end
988
1010
  list += '</ul></dd>'
989
1011
  end
@@ -1004,39 +1026,39 @@ class LightWaveRF
1004
1026
  <html>
1005
1027
  <head>
1006
1028
  <title>#{title}</title>
1007
- <style type="text/css">
1008
- body { font-family: arial, verdana, sans-serif; }
1009
- div#energy_chart { width: 800px; height: 600px; }
1010
- div#gauge_div { width: 100px; height: 100px; }
1011
- dd { display: none; }
1012
- .off, .on:hover { padding-right: 18px; background: url(lightning_delete.png) no-repeat top right; }
1013
- .on, .off:hover { padding-right: 18px; background: url(lightning_add.png) no-repeat top right; }
1014
- </style>
1015
- </head>
1029
+ <style type="text/css">
1030
+ body { font-family: arial, verdana, sans-serif; }
1031
+ div#energy_chart { width: 800px; height: 600px; }
1032
+ div#gauge_div { width: 100px; height: 100px; }
1033
+ dd { display: none; }
1034
+ .off, .on:hover { padding-right: 18px; background: url(lightning_delete.png) no-repeat top right; }
1035
+ .on, .off:hover { padding-right: 18px; background: url(lightning_add.png) no-repeat top right; }
1036
+ </style>
1037
+ </head>
1016
1038
  <body>
1017
1039
  <div class="container">
1018
1040
  <div class="row">
1019
1041
  <div class="col">
1020
- <h1>#{title}</h1>
1021
- <p class="intro">#{intro}</p>
1042
+ <h1>#{title}</h1>
1043
+ <p class="intro">#{intro}</p>
1022
1044
  <div id="energy_chart">
1023
1045
  Not seeing an energy chart here?
1024
1046
  Maybe not working in your device yet, sorry.
1025
1047
  This uses google chart api which may generate FLASH :-(
1026
1048
  Try in a web browser.
1027
1049
  </div>
1028
- <h2>Rooms and devices</h2>
1029
- <p>@todo make these links to control the devices...</p>
1030
- <p class="help">#{help}</p>
1031
- #{js}
1032
- </div>
1050
+ <h2>Rooms and devices</h2>
1051
+ <p>@todo make these links to control the devices...</p>
1052
+ <p class="help">#{help}</p>
1053
+ #{js}
1054
+ </div>
1033
1055
  <div class="col">
1034
1056
  <div class="col" id="gauge_div"></div>
1035
- </div>
1036
- </div>
1037
- </div>
1038
- <p>By <a href="http://www.clarkeology.com/blog/">Paul Clarke</a>, a work in progress.</p>
1039
- </body>
1057
+ </div>
1058
+ </div>
1059
+ </div>
1060
+ <p>By <a href="http://www.clarkeology.com/blog/">Paul Clarke</a>, a work in progress.</p>
1061
+ </body>
1040
1062
  </html>
1041
1063
  end
1042
1064
  end
@@ -1045,35 +1067,38 @@ class LightWaveRF
1045
1067
  def summarise days = 7, debug = nil
1046
1068
  days = days.to_i
1047
1069
  data = [ ]
1048
- daily = { }
1070
+ file = self.get_summary_file.gsub 'summary', 'daily'
1071
+ json = self.class.get_contents file
1072
+ daily = JSON.parse json
1049
1073
  start_date = 0
1050
1074
  d = nil
1051
1075
  File.open( self.get_log_file, 'r' ).each_line do | line |
1052
- line = JSON.parse( line )
1076
+ line = JSON.parse line
1053
1077
  if line and line['timestamp']
1054
- new_line = []
1055
- d = line['timestamp'][2..3] + line['timestamp'][5..6] + line['timestamp'][8..9] # compact version of date
1056
- ts = Time.parse( line['timestamp'] ).strftime '%s'
1057
- ts = ts.to_i
1058
- if start_date > 0
1059
- ts = ts - start_date
1060
- else
1061
- start_date = ts
1062
- end
1063
- new_line << ts
1064
- new_line << line['message']['usage'].to_i / 10
1065
- if line['message']['annotation'] and line['message']['annotation']['title'] and line['message']['annotation']['text']
1066
- new_line << line['message']['annotation']['title']
1067
- new_line << line['message']['annotation']['text']
1068
- end
1069
- data << new_line
1070
- if ( ! daily[d] or line['message']['today'] > daily[d]['today'] )
1078
+ new_line = []
1079
+ d = line['timestamp'][2..3] + line['timestamp'][5..6] + line['timestamp'][8..9] # compact version of date
1080
+ ts = Time.parse( line['timestamp'] ).strftime '%s'
1081
+ ts = ts.to_i
1082
+ if start_date > 0
1083
+ ts = ts - start_date
1084
+ else
1085
+ start_date = ts
1086
+ end
1087
+ new_line << ts
1088
+ new_line << line['message']['usage'].to_i / 10
1089
+ if line['message']['annotation'] and line['message']['annotation']['title'] and line['message']['annotation']['text']
1090
+ new_line << line['message']['annotation']['title']
1091
+ new_line << line['message']['annotation']['text']
1092
+ end
1093
+ data << new_line
1094
+ if (( ! daily[d] ) or ( line['message']['today'] > daily[d]['today'] ))
1071
1095
  daily[d] = line['message']
1072
- end
1096
+ daily[d].delete 'usage'
1097
+ end
1073
1098
  end
1074
1099
  end
1075
1100
  debug and ( puts 'got ' + data.length.to_s + ' lines in the log' )
1076
- data = data.last( 60 * 24 * days )
1101
+ data = data.last 60 * 24 * days
1077
1102
  debug and ( puts 'now got ' + data.length.to_s + ' lines in the log ( 60 * 24 * ' + days.to_s + ' = ' + ( 60 * 24 * days ).to_s + ' )' )
1078
1103
  if data and data[0]
1079
1104
  debug and ( puts 'data[0] is ' + data[0].to_s )
@@ -1085,12 +1110,13 @@ class LightWaveRF
1085
1110
  File.open( summary_file, 'w' ) do |file|
1086
1111
  file.write data.to_s
1087
1112
  end
1088
- # @todo fix the daily stats, every night it reverts to the minimum value...
1113
+ # @todo fix the daily stats, every night it reverts to the minimum value because the timezones are different
1114
+ # so 1am on the wifi-link looks midnight on the server
1089
1115
  File.open( summary_file.gsub( 'summary', 'daily' ), 'w' ) do | file |
1090
- file.write daily.to_s
1116
+ file.write daily.to_json.to_s
1091
1117
  end
1092
1118
  File.open( summary_file.gsub( 'summary', 'daily.' + d ), 'w' ) do | file |
1093
- file.write daily.select { |key| key == daily.keys.last }.to_s
1119
+ file.write daily.select { |key| key == daily.keys.last }.to_json.to_s
1094
1120
  end
1095
1121
  end
1096
1122
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lightwaverf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-07-30 00:00:00.000000000 Z
14
+ date: 2013-08-04 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: htmlentities