lightwaverf 0.5.0 → 0.6.0

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 +11 -3
  2. data/lib/lightwaverf.rb +111 -81
  3. metadata +2 -2
@@ -71,9 +71,17 @@
71
71
  return false;
72
72
  } );
73
73
  $('a.ajax').click( function ( ) {
74
- $a = $(this);
75
- $.get( $a.attr('href'), function ( js ) {
76
- alert( js.result || $a.text( ));
74
+ var $a = $(this);
75
+ var status = $a.data( 'status' ) == 'on' ? 'off' : 'on';
76
+ $.ajax( {
77
+ url: $a.attr('href') + '?status=' + status,
78
+ type: 'PUT',
79
+ success: function( js ) {
80
+ $a.data( 'status', status );
81
+ $a.removeClass( status === 'on' ? 'off' : 'on' );
82
+ $a.addClass( status );
83
+ alert( js.result || $a.text( ));
84
+ }
77
85
  } );
78
86
  return false;
79
87
  } );
data/lib/lightwaverf.rb CHANGED
@@ -4,7 +4,6 @@
4
4
  # Get rid of references in yaml cache file - use dup more? Or does it not matter?
5
5
  # Cope with events that start and end in the same run?
6
6
  # Add info about states to timer log
7
- # Consider adding a 'random' time shift modifier to make holiday security lights more 'realistic'
8
7
  # Build / update cron job automatically
9
8
 
10
9
 
@@ -310,8 +309,6 @@ class LightWaveRF
310
309
  m += 1
311
310
  end
312
311
  end
313
- # add 'all off' special mood
314
- rooms[room['name']]['mood']['alloff'] = 'Fa'
315
312
  r += 1
316
313
  end
317
314
  rooms
@@ -322,7 +319,6 @@ class LightWaveRF
322
319
  # Example:
323
320
  # >> LightWaveRF.new.state 'on' # 'F1'
324
321
  # >> LightWaveRF.new.state 'off' # 'F0'
325
- # >> LightWaveRF.new.state 'alloff' # 'Fa'
326
322
  #
327
323
  # Arguments:
328
324
  # state: (String)
@@ -333,11 +329,10 @@ class LightWaveRF
333
329
  case state
334
330
  when 'off'
335
331
  state = 'F0'
336
- when 'alloff'
337
- state = 'Fa'
332
+ when 0
333
+ state = 'F0'
338
334
  when 'on'
339
335
  state = 'F1'
340
- # preset dim levels
341
336
  when 'low'
342
337
  state = 'FdP8'
343
338
  when 'mid'
@@ -396,6 +391,9 @@ class LightWaveRF
396
391
  # >> LightWaveRF.new.send 'our', 'light', 'on'
397
392
  # >> LightWaveRF.new.send 'our', '', 'off'
398
393
  #
394
+ # This method was too confusing, got rid of "alloff"
395
+ # it can be done with "[room] all off" anyway
396
+ #
399
397
  # Arguments:
400
398
  # room: (String)
401
399
  # device: (String)
@@ -404,9 +402,9 @@ class LightWaveRF
404
402
  success = false
405
403
  debug and ( p 'Executing send on device: ' + device + ' in room: ' + room + ' with state: ' + state )
406
404
  rooms = self.class.get_rooms self.get_config, debug
407
- state = 'alloff' if ( device.empty? and state == 'off' )
408
405
 
409
406
  unless rooms[room] and state
407
+ debug and ( p 'Missing room (' + room.to_s + ') or state (' + state.to_s + ')' );
410
408
  STDERR.puts self.usage( room );
411
409
  else
412
410
  # support for setting state for all devices in the room (recursive)
@@ -419,7 +417,7 @@ class LightWaveRF
419
417
  end
420
418
  success = true
421
419
  # process single device
422
- elsif state == 'alloff' || (device and rooms[room]['device'][device])
420
+ elsif device and rooms[room]['device'][device]
423
421
  state = self.class.get_state state
424
422
  command = self.command rooms[room], device, state
425
423
  debug and ( p 'command is ' + command )
@@ -546,10 +544,14 @@ class LightWaveRF
546
544
  data['message']['annotation'] = { 'title' => title.to_s, 'text' => note.to_s }
547
545
  end
548
546
  debug and ( p data )
549
- File.open( self.get_log_file, 'a' ) do | f |
550
- f.write( data.to_json + "\n" )
547
+ begin
548
+ File.open( self.get_log_file, 'a' ) do | f |
549
+ f.write( data.to_json + "\n" )
550
+ end
551
+ data['message']
552
+ rescue
553
+ puts 'error writing to log'
551
554
  end
552
- data['message']
553
555
  end
554
556
  end
555
557
 
@@ -689,8 +691,8 @@ class LightWaveRF
689
691
  time_modifier = 0
690
692
  if command_length > modifier_start
691
693
  debug and ( p "May have modifiers..." )
692
- when_modifiers = Array.new
693
- unless_modifiers = Array.new
694
+ when_modifiers = [ ]
695
+ unless_modifiers = [ ]
694
696
  modifier_count = command_length - modifier_start
695
697
  debug and ( p "Count of modifiers is " + modifier_count.to_s )
696
698
  for i in modifier_start..(command_length-1)
@@ -715,7 +717,6 @@ class LightWaveRF
715
717
  end
716
718
 
717
719
  # parse the date string
718
- debug and ( p "Time string is: " + e.elements['summary'].text)
719
720
  event_time = /When: ([\w ]+) (\d\d:\d\d) to ([\w ]+)?(\d\d:\d\d)&nbsp;\n(.*)<br>(.*)/.match e.elements['summary'].text
720
721
  debug and ( p "Event times are: " + event_time.to_s )
721
722
  start_date = event_time[1].to_s
@@ -726,11 +727,14 @@ class LightWaveRF
726
727
  if end_date == '' or end_date.nil? # copy start date to end date if it wasn't given (as the same date)
727
728
  end_date = start_date
728
729
  end
729
- debug and ( p "Start date: " + start_date)
730
- debug and ( p "Start time: " + start_time)
731
- debug and ( p "End date: " + end_date)
732
- debug and ( p "End time: " + end_time)
733
- debug and ( p "Timezone: " + timezone)
730
+
731
+ time_modifier += self.class.variance e.elements['title'].text
732
+
733
+ debug and ( p 'Start date: ' + start_date )
734
+ debug and ( p 'Start time: ' + start_time )
735
+ debug and ( p 'End date: ' + end_date )
736
+ debug and ( p 'End time: ' + end_time )
737
+ debug and ( p 'Timezone: ' + timezone )
734
738
 
735
739
  # convert to datetimes
736
740
  start_dt = DateTime.parse( start_date.strip + ' ' + start_time.strip + ' ' + timezone.strip )
@@ -738,19 +742,19 @@ class LightWaveRF
738
742
 
739
743
  # apply time modifier if it exists
740
744
  if time_modifier != 0
741
- debug and ( p "Adjusting timings by: " + time_modifier.to_s )
745
+ debug and ( p 'Adjusting timings by: ' + time_modifier.to_s )
742
746
  start_dt = (( start_dt.to_time ) + time_modifier * 60 ).to_datetime
743
747
  end_dt = (( end_dt.to_time ) + time_modifier * 60 ).to_datetime
744
748
  end
745
749
 
746
- debug and ( p "Start datetime: " + start_dt.to_s )
747
- debug and ( p "End datetime: " + end_dt.to_s )
750
+ debug and ( p 'Start datetime: ' + start_dt.to_s )
751
+ debug and ( p 'End datetime: ' + end_dt.to_s )
748
752
 
749
753
  # populate the dates
750
754
  event['date'] = start_dt
751
755
  # handle device entries without explicit on/off state
752
756
  if event['type'] == 'device' and ( event['state'].nil? or ( event['state'] != 'on' and event['state'] != 'off' ))
753
- debug and ( p "Duplicating event without explicit on/off state..." )
757
+ debug and ( p 'Duplicating event without explicit on/off state...' )
754
758
  # if not state was given, assume we meant 'on'
755
759
  if event['state'].nil?
756
760
  event['state'] = 'on'
@@ -762,7 +766,7 @@ class LightWaveRF
762
766
  events.push end_event
763
767
  # create state plus start and end events if a state
764
768
  elsif event['type'] == 'state'
765
- debug and ( p "Processing state : " + event['state'])
769
+ debug and ( p 'Processing state : ' + event['state'] )
766
770
  # create state
767
771
  state = Hash.new
768
772
  state['name'] = event['state']
@@ -805,10 +809,22 @@ class LightWaveRF
805
809
  self.log_timer_event 'update', nil, nil, nil, true
806
810
 
807
811
  else
808
- self.log_timer_event 'update', nil, nil, nil, false
812
+ self.log_timer_event 'update', nil, nil, nil, false
809
813
  end
810
814
  end
811
815
 
816
+ # Return the randomness value that may be in the event title
817
+ def self.variance title = '', debug = nil
818
+ randomness = /random\w* (\d+)/.match title
819
+ if randomness
820
+ n = randomness[1].to_i
821
+ debug and ( p 'randomness is ' + n.to_s )
822
+ return rand( n ) - ( n / 2 )
823
+ end
824
+ debug and ( p 'no randomness return 0' )
825
+ return 0
826
+ end
827
+
812
828
  # Convert a string to seconds, assume it is in minutes
813
829
  def self.to_seconds interval = 0
814
830
  match = /^(\d+)([shd])$/.match( interval.to_s )
@@ -827,7 +843,7 @@ class LightWaveRF
827
843
 
828
844
  def run_timers interval = 5, debug = false
829
845
  p '----------------'
830
- p "Running timers..."
846
+ p 'Running timers...'
831
847
  get_timer_cache
832
848
  debug and ( p 'Timer list is: ' + YAML.dump( @timers ))
833
849
 
@@ -871,7 +887,7 @@ class LightWaveRF
871
887
  debug and ( p 'Event has when modifiers. Checking they are all met...')
872
888
 
873
889
  # determine which states apply at the time of the event
874
- applicable_states = Array.new
890
+ applicable_states = [ ]
875
891
  @timers['states'].each do | state |
876
892
  if event['date'] >= state['start'] and event['date'] < state['end']
877
893
  applicable_states.push state['name']
@@ -939,7 +955,7 @@ class LightWaveRF
939
955
  if triggered.length > 0
940
956
  debug and ( p triggered.length.to_s + ' events so annotating energy log too...' )
941
957
  title = 'timer'
942
- text = triggered.map { | e | e.join " " }.join ", "
958
+ text = triggered.map { | e | e.join ' ' }.join ', '
943
959
  end
944
960
  self.energy title, text, debug
945
961
 
@@ -947,23 +963,27 @@ class LightWaveRF
947
963
  end
948
964
 
949
965
  def self.get_contents file
950
- file = File.open file, 'r'
951
- content = file.read
952
- file.close
953
- content
966
+ begin
967
+ file = File.open file, 'r'
968
+ content = file.read
969
+ file.close
970
+ rescue
971
+ STDERR.puts 'cannot open ' + file
972
+ end
973
+ content.to_s
954
974
  end
955
975
 
956
976
  def build_web_page debug = nil
957
977
 
958
978
  rooms = self.class.get_rooms self.get_config
959
979
  list = '<dl>'
960
- config = 'usage: lightwaverf ' + rooms.values.first['name'] + ' ' + rooms.values.first['device'].keys.first.to_s + ' on # where "' + rooms.keys.first + '" is a room in ' + self.get_config_file
961
980
  rooms.each do | name, room |
962
981
  debug and ( puts name + ' is ' + room.to_s )
963
- list += '<dt>' + name + '</dt><dd><ul>'
982
+ list += '<dt><a>' + name + '</a></dt><dd><ul>'
964
983
  room['device'].each do | device |
965
- debug and ( puts 'device is ' + device.to_s )
966
- list += '<li>' + room['name'].to_s + ' ' + device.first.to_s + '</li>'
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>'
967
987
  end
968
988
  list += '</ul></dd>'
969
989
  end
@@ -974,41 +994,49 @@ class LightWaveRF
974
994
  date = Time.new.to_s
975
995
  title = self.get_config.has_key?('title') ? self.get_config['title'] : ( 'Lightwaverf energy stats ' + date )
976
996
  intro = <<-end
977
- Sample page generated #{date} with <code>lightwaverf web</code>.
978
- Check out <a href="https://github.com/pauly/lightwaverf">the new simplified repo</a> for details
979
- or <a href="https://rubygems.org/gems/lightwaverf">gem install lightwaverf && lightwaverf web</a>...
980
- <br />@todo make a decent, useful, simple, configurable web page...
997
+ Sample page generated #{date} with <code>lightwaverf web</code>.
998
+ Check out <a href="https://github.com/pauly/lightwaverf">the new simplified repo</a> for details
999
+ or <a href="https://rubygems.org/gems/lightwaverf">gem install lightwaverf && lightwaverf web</a>...
1000
+ <br />@todo make a decent, useful, simple, configurable web page...
981
1001
  end
982
1002
  help = list
983
1003
  html = <<-end
984
1004
  <html>
985
1005
  <head>
986
1006
  <title>#{title}</title>
987
- <style type="text/css">
988
- body { font-family: arial, verdana, sans-serif; }
989
- div#energy_chart { width: 800px; height: 600px; }
990
- div#gauge_div { width: 100px; height: 100px; }
991
- </style>
992
- </head>
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>
993
1016
  <body>
994
1017
  <div class="container">
995
1018
  <div class="row">
996
1019
  <div class="col">
997
- <h1>#{title}</h1>
998
- <p class="intro">#{intro}</p>
999
- <div id="energy_chart"></div>
1000
- <h2>Rooms and devices</h2>
1001
- <p>@todo make these links to control the devices...</p>
1002
- <p class="help">#{help}</p>
1003
- #{js}
1004
- </div>
1020
+ <h1>#{title}</h1>
1021
+ <p class="intro">#{intro}</p>
1022
+ <div id="energy_chart">
1023
+ Not seeing an energy chart here?
1024
+ Maybe not working in your device yet, sorry.
1025
+ This uses google chart api which may generate FLASH :-(
1026
+ Try in a web browser.
1027
+ </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>
1005
1033
  <div class="col">
1006
1034
  <div class="col" id="gauge_div"></div>
1007
- </div>
1008
- </div>
1009
- </div>
1010
- <p>By <a href="http://www.clarkeology.com/blog/">Paul Clarke</a>, a work in progress.</p>
1011
- </body>
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>
1012
1040
  </html>
1013
1041
  end
1014
1042
  end
@@ -1023,32 +1051,35 @@ class LightWaveRF
1023
1051
  File.open( self.get_log_file, 'r' ).each_line do | line |
1024
1052
  line = JSON.parse( line )
1025
1053
  if line and line['timestamp']
1026
- new_line = []
1027
- d = line['timestamp'][2..3] + line['timestamp'][5..6] + line['timestamp'][8..9] # compact version of date
1028
- ts = Time.parse( line['timestamp'] ).strftime '%s'
1029
- ts = ts.to_i
1030
- if start_date > 0
1031
- ts = ts - start_date
1032
- else
1033
- start_date = ts
1034
- end
1035
- new_line << ts
1036
- new_line << line['message']['usage'].to_i / 10
1037
- if line['message']['annotation'] and line['message']['annotation']['title'] and line['message']['annotation']['text']
1038
- new_line << line['message']['annotation']['title']
1039
- new_line << line['message']['annotation']['text']
1040
- end
1041
- data << new_line
1042
- if line['message']['today'] > daily[d]['today']
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'] )
1043
1071
  daily[d] = line['message']
1044
- end
1072
+ end
1045
1073
  end
1046
1074
  end
1047
1075
  debug and ( puts 'got ' + data.length.to_s + ' lines in the log' )
1048
1076
  data = data.last( 60 * 24 * days )
1049
1077
  debug and ( puts 'now got ' + data.length.to_s + ' lines in the log ( 60 * 24 * ' + days.to_s + ' = ' + ( 60 * 24 * days ).to_s + ' )' )
1050
- if data[0][0] != start_date
1051
- data[0][0] += start_date
1078
+ if data and data[0]
1079
+ debug and ( puts 'data[0] is ' + data[0].to_s )
1080
+ if data[0][0] != start_date
1081
+ data[0][0] += start_date
1082
+ end
1052
1083
  end
1053
1084
  summary_file = self.get_summary_file
1054
1085
  File.open( summary_file, 'w' ) do |file|
@@ -1064,4 +1095,3 @@ class LightWaveRF
1064
1095
  end
1065
1096
 
1066
1097
  end
1067
-
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.5.0
4
+ version: 0.6.0
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-04 00:00:00.000000000 Z
14
+ date: 2013-07-30 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: htmlentities