lightwaverf 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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