lightwaverf 0.6.6 → 0.7

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.
@@ -1,6 +1,6 @@
1
- <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
2
- <script type="text/javascript" src="https://www.google.com/jsapi"></script>
3
- <script type="text/javascript">
1
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
2
+ <script src="//www.google.com/jsapi"></script>
3
+ <script>
4
4
  var gauge, gauge_data, gauge_options;
5
5
  google.load( 'visualization', '1.0', { packages: [ 'corechart', 'gauge', 'annotatedtimeline' ] } );
6
6
  google.setOnLoadCallback( function ( ) {
@@ -9,39 +9,35 @@
9
9
  energy_data.addColumn( 'number', 'Electricity used' );
10
10
  energy_data.addColumn( 'string', 'title1' );
11
11
  energy_data.addColumn( 'string', 'text1' );
12
- if (!Array.prototype.map) {
13
- Array.prototype.map = function(callback, thisArg) {
12
+ if ( ! Array.prototype.map ) { // polyfill
13
+ Array.prototype.map = function( callback, thisArg ) {
14
14
  var T, A, k;
15
- if (this == null) {
16
- throw new TypeError(" this is null or not defined");
17
- }
15
+ if ( this == null ) throw new TypeError( 'this is null or not defined' );
18
16
  var O = Object(this);
19
17
  var len = O.length >>> 0;
20
- if (typeof callback !== "function") {
21
- throw new TypeError(callback + " is not a function");
22
- }
23
- if (thisArg) {
24
- T = thisArg;
25
- }
26
- A = new Array(len);
18
+ if ( typeof callback !== 'function' ) throw new TypeError( callback + ' is not a function' );
19
+ if ( thisArg ) T = thisArg;
20
+ A = new Array( len );
27
21
  k = 0;
28
- while(k < len) {
22
+ while ( k < len ) {
29
23
  var kValue, mappedValue;
30
- if (k in O) {
24
+ if ( k in O ) {
31
25
  kValue = O[ k ];
32
26
  mappedValue = callback.call(T, kValue, k, O);
33
27
  A[ k ] = mappedValue;
34
28
  }
35
- k++;
29
+ k ++;
36
30
  }
37
31
  return A;
38
32
  };
39
33
  }
40
- var raw_data = <%- summary %>;
41
- var start_date = raw_data[0][0];
42
- energy_data.addRows( raw_data.map( function ( e ) {
43
- if ( e[0] !== start_date ) e[0] += start_date;
44
- e[0] = new Date( 1000 * e[0] ); // as it is now a timestamp
34
+ var rawData = <%- summary %>;
35
+ // var startDate = rawData[0][0];
36
+ var i = 0;
37
+ energy_data.addRows( rawData.map( function ( e ) {
38
+ ++ i;
39
+ // if ( e[0] !== startDate ) e[0] += startDate;
40
+ e[0] = new Date( e[0] * 1000 ); // as it is now a timestamp
45
41
  e[1] = e[1] * 10;
46
42
  e[2] = e[2] || '';
47
43
  e[3] = e[3] || '';
@@ -49,9 +45,8 @@
49
45
  } ));
50
46
  var chart = new google.visualization.AnnotatedTimeLine( document.getElementById( 'energy_chart' ));
51
47
  chart.draw( energy_data, { displayAnnotations: true, title: '24 hours electricity usage' } );
52
-
53
48
  gauge = new google.visualization.Gauge( document.getElementById( 'gauge_div' ));
54
- gauge_data = google.visualization.arrayToDataTable( [ ["Label", "Value"], ["Electric", raw_data.pop[1] ] ] );
49
+ gauge_data = google.visualization.arrayToDataTable( [[ 'Label', 'Value' ], [ 'Electric', rawData.pop[ 1 ]]] );
55
50
  gauge_options = {
56
51
  width: '200',
57
52
  height: '200',
@@ -64,7 +59,7 @@
64
59
  gauge.draw( gauge_data, gauge_options );
65
60
  } );
66
61
  $( function ( ) {
67
- var key = 'foo';
62
+ var key = ''; // @todo prompt for an pi key and save it in local storage like https://github.com/pauly/robot-butler does
68
63
  $('dt a').click( function ( ) {
69
64
  $(this).parent( ).next('dd').slideDown( );
70
65
  return false;
data/bin/lightwaverf CHANGED
@@ -1,32 +1,37 @@
1
1
  #!/usr/bin/ruby
2
2
  require 'lightwaverf'
3
+ obj = LightWaveRF.new
3
4
  case ARGV[0]
4
5
  when 'help'
5
- puts LightWaveRF.new.help
6
+ puts obj.help
7
+ when 'initlink'
8
+ puts obj.firmware ARGV[1]
9
+ when 'firmware'
10
+ puts obj.firmware ARGV[1]
6
11
  when 'timezone'
7
- puts LightWaveRF.new.timezone ARGV[1]
12
+ puts obj.timezone ARGV[1]
8
13
  when 'configure'
9
- puts LightWaveRF.new.configure
14
+ puts obj.configure ARGV[1]
10
15
  when 'sequence'
11
- puts LightWaveRF.new.sequence ARGV[1], ARGV[2]
16
+ puts obj.sequence ARGV[1], ARGV[2]
12
17
  when 'mood'
13
- puts LightWaveRF.new.mood ARGV[1], ARGV[2], ARGV[3]
18
+ puts obj.mood ARGV[1], ARGV[2], ARGV[3]
14
19
  when 'learnmood'
15
- puts LightWaveRF.new.learnmood ARGV[1], ARGV[2], ARGV[3]
20
+ puts obj.learnmood ARGV[1], ARGV[2], ARGV[3]
16
21
  when 'energy'
17
- puts LightWaveRF.new.energy ARGV[1], ARGV[2], ARGV[3]
22
+ puts obj.energy ARGV[1], ARGV[2], ARGV[3]
18
23
  when 'update_timers'
19
- puts LightWaveRF.new.update_timers ARGV[1], ARGV[2], ARGV[3]
24
+ puts obj.update_timers ARGV[1], ARGV[2], ARGV[3]
20
25
  when 'timer'
21
- puts LightWaveRF.new.run_timers ARGV[1], ARGV[2]
26
+ puts obj.run_timers ARGV[1], ARGV[2]
22
27
  when 'run_timers'
23
- puts LightWaveRF.new.run_timers ARGV[1], ARGV[2]
28
+ puts obj.run_timers ARGV[1], ARGV[2]
24
29
  when 'update'
25
- puts LightWaveRF.new.update_config ARGV[1], ARGV[2]
30
+ puts obj.update_config ARGV[1], ARGV[2]
26
31
  when 'web'
27
- puts LightWaveRF.new.build_web_page ARGV[1]
32
+ puts obj.build_web_page ARGV[1]
28
33
  when 'summarise'
29
- puts LightWaveRF.new.summarise ARGV[1], ARGV[2]
34
+ puts obj.summarise ARGV[1], ARGV[2]
30
35
  else
31
- LightWaveRF.new.send ARGV[0], ARGV[1], ARGV[2], ARGV[3]
36
+ obj.send ARGV[0], ARGV[1], ARGV[2], ARGV[3]
32
37
  end
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/ruby
2
2
  require 'lightwaverf'
3
+ config = LightWaveRF.new.get_config
4
+ config['spreadsheet']['password'] = nil
5
+ puts JSON.generate config
3
6
  require 'json'
4
- puts JSON.generate LightWaveRF.new.get_config
data/lib/lightwaverf.rb CHANGED
@@ -22,9 +22,10 @@ class LightWaveRF
22
22
  @config_file = nil
23
23
  @log_file = nil
24
24
  @summary_file = nil
25
- @log_timer_file = nil
25
+ @timer_log_file = nil
26
26
  @config = nil
27
27
  @timers = nil
28
+ @time = nil
28
29
 
29
30
  # Display usage info
30
31
  def usage room = nil
@@ -40,6 +41,12 @@ class LightWaveRF
40
41
  config
41
42
  end
42
43
 
44
+ # For debug timing, why is this so slow?
45
+ def time label = nil
46
+ @time = @time || Time.now
47
+ label.to_s + ' (' + ( Time.now - @time ).to_s + ')'
48
+ end
49
+
43
50
  # Display help
44
51
  def help
45
52
  help = self.usage + "\n"
@@ -53,19 +60,15 @@ class LightWaveRF
53
60
  # Configure, build config file. Interactive command line stuff
54
61
  #
55
62
  # Arguments:
56
- # debug: (Boolean
63
+ # debug: (Boolean)
57
64
  def configure debug = false
58
65
  config = self.get_config
59
- # puts 'What is the ip address of your wifi link? (' + self.get_config['host'] + '). Enter a blank line to broadcast UDP commands.'
60
- # host = STDIN.gets.chomp
61
- # if ! host.to_s.empty?
62
- # config['host'] = host
63
- # end
64
- puts 'What is the address of your google calendar? (' + self.get_config['calendar'] + '). Optional!'
66
+ puts 'What is the ip address of your wifi link? (currently "' + self.get_config['host'].to_s + '"). Enter a blank line to broadcast UDP commands (ok to just hit enter here).'
67
+ host = STDIN.gets.chomp
68
+ config['host'] = host if ! host.to_s.empty?
69
+ puts 'What is the address of your google calendar? (currently "' + self.get_config['calendar'].to_s + '"). Optional (ok to just hit enter here).'
65
70
  calendar = STDIN.gets.chomp
66
- if ! calendar.to_s.empty?
67
- config['calendar'] = calendar
68
- end
71
+ config['calendar'] = calendar if ! calendar.to_s.empty?
69
72
  device = 'x'
70
73
  while ! device.to_s.empty?
71
74
  puts 'Enter the name of a room and its devices, space separated. For example "lounge light socket tv". Enter a blank line to finish.'
@@ -77,6 +80,9 @@ class LightWaveRF
77
80
  found = false
78
81
  config['room'].each do | room |
79
82
  if room['name'] == new_room
83
+ parts.map! do | device |
84
+ { 'name' => device, 'type' => 'O' }
85
+ end
80
86
  room['device'] = parts
81
87
  found = true
82
88
  end
@@ -85,12 +91,13 @@ class LightWaveRF
85
91
  if ! found
86
92
  config['room'].push 'name' => new_room, 'device' => parts, 'mood' => nil
87
93
  end
88
- debug and ( p 'added ' + parts.to_s + ' to ' + new_room )
94
+ debug and ( p 'added ' + parts.to_s + ' to ' + new_room.to_s )
89
95
  end
90
96
  end
91
97
  end
92
98
  debug and ( p 'end of configure, config is now ' + config.to_s )
93
- self.put_config config
99
+ file = self.put_config config
100
+ 'Saved config file ' + file
94
101
  end
95
102
 
96
103
  # Config file setter
@@ -136,7 +143,7 @@ class LightWaveRF
136
143
  end
137
144
  unless message.nil?
138
145
  File.open( self.get_timer_log_file, 'a' ) do | f |
139
- f.write("\n" + Time.now.to_s + ' - ' + message + ' - ' + ( result ? 'SUCCESS!' : 'FAILED!' ))
146
+ f.write( "\n" + Time.now.to_s + ' - ' + message + ' - ' + ( result ? 'SUCCESS!' : 'FAILED!' ))
140
147
  end
141
148
  end
142
149
  end
@@ -164,10 +171,12 @@ class LightWaveRF
164
171
  end
165
172
  end
166
173
 
167
- def put_config config = { 'room' => [ { 'name' => 'our', 'device' => [ 'light', 'lights' ] } ] }
174
+ # Write the config file
175
+ def put_config config = { 'room' => [ { 'name' => 'our', 'device' => [ 'light' => { 'name' => 'light' }, 'lights' => { 'name' => 'lights' } ] } ] }
168
176
  File.open( self.get_config_file, 'w' ) do | handle |
169
177
  handle.write YAML.dump( config )
170
178
  end
179
+ self.get_config_file
171
180
  end
172
181
 
173
182
  # Get the config file, create it if it does not exist
@@ -179,15 +188,15 @@ class LightWaveRF
179
188
  end
180
189
  @config = YAML.load_file self.get_config_file
181
190
  # fix where update made names and devices into arrays
182
- if @config['room']
183
- @config['room'].map! do | room |
184
- room['name'] = room['name'].kind_of?( Array ) ? room['name'][0] : room['name']
185
- room['device'].map! do | device |
186
- device = device.kind_of?( Array ) ? device[0] : device
187
- end
188
- room
189
- end
190
- end
191
+ # if @config['room']
192
+ # @config['room'].map! do | room |
193
+ # room['name'] = room['name'].kind_of?( Array ) ? room['name'][0] : room['name']
194
+ # room['device'].map! do | device |
195
+ # device = device.kind_of?( Array ) ? device[0] : device
196
+ # end
197
+ # room
198
+ # end
199
+ # end
191
200
  end
192
201
  @config
193
202
  end
@@ -209,9 +218,7 @@ class LightWaveRF
209
218
  # Login to LightWaveRF Host server
210
219
  uri = URI.parse 'https://lightwaverfhost.co.uk/manager/index.php'
211
220
  http = Net::HTTP.new uri.host, uri.port
212
- if uri.scheme == 'https'
213
- http.use_ssl = true
214
- end
221
+ http.use_ssl = true if uri.scheme == 'https'
215
222
  data = 'pin=' + pin + '&email=' + email
216
223
  headers = { 'Content-Type'=> 'application/x-www-form-urlencoded' }
217
224
  resp, data = http.post uri.request_uri, data, headers
@@ -262,7 +269,7 @@ class LightWaveRF
262
269
  # o: All Off
263
270
  deviceStatusIndex = roomIndex * 10 + deviceIndex
264
271
  if variables['gDeviceStatus'] and variables['gDeviceStatus'][deviceStatusIndex] and variables['gDeviceStatus'][deviceStatusIndex][0] != 'I'
265
- roomDevices << deviceName
272
+ roomDevices << { 'name' => deviceName, 'type' => variables['gDeviceStatus'][deviceStatusIndex][0] }
266
273
  end
267
274
  end
268
275
  # Create a hash of the active room and active devices and add to rooms array
@@ -298,18 +305,19 @@ class LightWaveRF
298
305
  end
299
306
 
300
307
  # Get a cleaned up version of the rooms and devices from the config file
301
- def self.get_rooms config = { 'room' => [ ]}, debug = false
308
+ def self.get_rooms config = { 'room' => [ ] }, debug = false
302
309
  rooms = { }
303
310
  r = 1
304
311
  config['room'].each do | room |
305
- debug and ( puts room['name'] + ' = R' + r.to_s )
312
+ room = room.first if room.is_a? Array
306
313
  rooms[room['name']] = { 'id' => 'R' + r.to_s, 'name' => room['name'], 'device' => { }, 'mood' => { }, 'learnmood' => { }}
307
314
  d = 1
308
315
  unless room['device'].nil?
309
316
  room['device'].each do | device |
310
- # @todo possibly need to complicate this to get a device name back in here
311
- debug and ( puts ' - ' + device + ' = D' + d.to_s )
312
- rooms[room['name']]['device'][device] = 'D' + d.to_s
317
+ device = device.first if device.is_a? Array
318
+ device = { 'name' => device } if device.is_a? String
319
+ device['id'] = 'D' + d.to_s
320
+ rooms[room['name']]['device'][device['name']] = device
313
321
  d += 1
314
322
  end
315
323
  end
@@ -374,9 +382,10 @@ class LightWaveRF
374
382
  # state: (String)
375
383
  def command room, device, state
376
384
  # @todo get the device name in here...
385
+ device = device.to_s
377
386
  # Command structure is <transaction number>,<Command>|<Action>|<State><cr>
378
387
  if room and device and !device.empty? and state
379
- '666,!' + room['id'] + room['device'][device] + state + '|Turn ' + room['name'] + ' ' + device + '|' + state + ' via @pauly'
388
+ '666,!' + room['id'] + room['device'][device]['id'] + state + '|Turn ' + room['name'] + ' ' + device + '|' + state + ' via @pauly'
380
389
  else
381
390
  '666,!' + room['id'] + state + '|Turn ' + room['name'] + '|' + state + ' via @pauly'
382
391
  end
@@ -390,11 +399,9 @@ class LightWaveRF
390
399
  # Arguments:
391
400
  # debug: (Boolean)
392
401
  def timezone debug = false
393
- command = '666,!FzP' + (Time.now.gmt_offset/60/60).to_s
394
- debug and ( puts '[Info - LightWaveRF] timezone: command is ' + command )
395
- data = self.raw command
396
- debug and ( puts '[Info - LightWaveRF] timezone: response is ' + data )
397
- return (data == "666,OK\r\n")
402
+ command = '666,!FzP' + ( Time.now.gmt_offset/60/60 ).to_s
403
+ data = self.raw command, true, debug
404
+ return data == "666,OK\r\n"
398
405
  end
399
406
 
400
407
  # Turn one of your devices on or off or all devices in a room off
@@ -411,9 +418,11 @@ class LightWaveRF
411
418
  # device: (String)
412
419
  # state: (String)
413
420
  def send room = nil, device = nil, state = 'on', debug = false
421
+ debug and ( p self.time 'send' )
414
422
  success = false
415
423
  debug and ( p 'Executing send on device: ' + device + ' in room: ' + room + ' with state: ' + state )
416
424
  rooms = self.class.get_rooms self.get_config, debug
425
+ debug and ( p self.time 'got rooms' )
417
426
 
418
427
  unless rooms[room] and state
419
428
  debug and ( p 'Missing room (' + room.to_s + ') or state (' + state.to_s + ')' );
@@ -432,9 +441,9 @@ class LightWaveRF
432
441
  elsif device and rooms[room]['device'][device]
433
442
  state = self.class.get_state state
434
443
  command = self.command rooms[room], device, state
435
- debug and ( p 'command is ' + command )
444
+ debug and ( p self.time 'command is ' + command )
436
445
  data = self.raw command
437
- debug and ( p 'response is ' + data )
446
+ debug and ( p self.time 'response is ' + data.to_s )
438
447
  success = true
439
448
  else
440
449
  STDERR.puts self.usage( room );
@@ -482,15 +491,14 @@ class LightWaveRF
482
491
  # mood: (String)
483
492
  def mood room = nil, mood = nil, debug = false
484
493
  success = false
485
- debug and (p 'Executing mood: ' + mood + ' in room: ' + room)
486
- #debug and ( puts 'config is ' + self.get_config.to_s )
494
+ debug and ( p 'Executing mood: ' + mood + ' in room: ' + room )
487
495
  rooms = self.class.get_rooms self.get_config
488
496
  # support for setting a mood in all rooms (recursive)
489
497
  if room == 'all'
490
- debug and ( p "Processing all rooms..." )
498
+ debug and ( p 'Processing all rooms...' )
491
499
  rooms.each do | config, each_room |
492
500
  room = each_room['name']
493
- debug and ( p "Room is: " + room )
501
+ debug and ( p 'Room is: ' + room )
494
502
  success = self.mood room, mood, debug
495
503
  sleep 1
496
504
  end
@@ -508,8 +516,8 @@ class LightWaveRF
508
516
  state = mood[3..-1]
509
517
  debug and (p 'Selected state is: ' + state)
510
518
  rooms[room]['device'].each do | device |
511
- p 'Processing device: ' + device[0]
512
- self.send room, device[0], state, debug
519
+ p 'Processing device: ' + device[0].to_s
520
+ self.send room, device[0]['name'], state, debug
513
521
  sleep 1
514
522
  end
515
523
  success = true
@@ -530,8 +538,7 @@ class LightWaveRF
530
538
  # room: (String)
531
539
  # mood: (String)
532
540
  def learnmood room = nil, mood = nil, debug = false
533
- debug and (p 'Learning mood: ' + mood)
534
- #debug and ( puts 'config is ' + self.get_config.to_s )
541
+ debug and ( p 'Learning mood: ' + mood )
535
542
  rooms = self.class.get_rooms self.get_config
536
543
  if rooms[room] and mood and rooms[room]['learnmood'][mood]
537
544
  command = self.command rooms[room], nil, rooms[room]['learnmood'][mood]
@@ -542,10 +549,9 @@ class LightWaveRF
542
549
  end
543
550
  end
544
551
 
545
- def energy title = nil, note = nil, debug = false
546
- debug and note and ( p 'energy: ' + note )
547
- data = self.raw '666,@?'
548
- debug and ( p data )
552
+ def energy title = nil, text = nil, debug = false
553
+ debug and text and ( p 'energy: ' + text )
554
+ data = self.raw '666,@?', true
549
555
  # /W=(?<usage>\d+),(?<max>\d+),(?<today>\d+),(?<yesterday>\d+)/.match data # ruby 1.9 only?
550
556
  match = /W=(\d+),(\d+),(\d+),(\d+)/.match data
551
557
  debug and ( p match )
@@ -558,8 +564,38 @@ class LightWaveRF
558
564
  }
559
565
  }
560
566
  data['timestamp'] = Time.now.to_s
561
- if note
562
- data['message']['annotation'] = { 'title' => title.to_s, 'text' => note.to_s }
567
+ if text
568
+ data['message']['annotation'] = { 'title' => title.to_s, 'text' => text.to_s }
569
+ end
570
+
571
+ if text
572
+ if self.get_config['spreadsheet']
573
+ spreadsheet = self.get_config['spreadsheet']['url']
574
+ match = /key=([\w-]+)/.match spreadsheet
575
+ debug and ( p match )
576
+ if match
577
+ spreadsheet = match[1]
578
+ end
579
+ debug and ( p 'spreadsheet is ' + spreadsheet )
580
+ if spreadsheet
581
+ require 'google_drive'
582
+ session = GoogleDrive.login self.get_config['spreadsheet']['username'], self.get_config['spreadsheet']['password']
583
+ ws = session.spreadsheet_by_key( spreadsheet ).worksheets[0]
584
+ rows = ws.num_rows
585
+ debug and ( p rows.to_s + ' rows in ' + spreadsheet )
586
+ row = rows + 1
587
+ ws[ row, 1 ] = data['timestamp']
588
+ ws[ row, 2 ] = data['message']['usage']
589
+ ws[ row, 3 ] = data['message']['max']
590
+ ws[ row, 4 ] = data['message']['today']
591
+ ws[ row, 5 ] = data['message']['annotation']['title']
592
+ ws[ row, 6 ] = data['message']['annotation']['text']
593
+ ws.save( )
594
+ end
595
+ else
596
+ debug and ( p 'no spreadsheet in your config file...' )
597
+ end
598
+
563
599
  end
564
600
  debug and ( p data )
565
601
  begin
@@ -567,13 +603,7 @@ class LightWaveRF
567
603
  f.write( data.to_json + "\n" )
568
604
  end
569
605
  file = self.get_summary_file.gsub 'summary', 'daily'
570
- json = self.class.get_contents file
571
- begin
572
- data['message']['history'] = JSON.parse json
573
- rescue => e
574
- data['message']['error'] = 'error parsing ' + file + '; ' + e.to_s
575
- data['message']['history_json'] = json
576
- end
606
+ data['message']['history'] = self.class.get_json file
577
607
  data['message']
578
608
  rescue
579
609
  puts 'error writing to log'
@@ -581,37 +611,49 @@ class LightWaveRF
581
611
  end
582
612
  end
583
613
 
584
- def raw command
614
+ def raw command, listen = false, debug = false
615
+ debug and ( p self.time + ' ' + __method__.to_s + ' ' + command )
585
616
  response = nil
586
617
  # Get host address or broadcast address
587
618
  host = self.get_config['host'] || '255.255.255.255'
619
+ debug and ( p self.time 'got ' + host )
588
620
  # Create socket
589
621
  listener = UDPSocket.new
622
+ debug and ( p self.time 'got listener' )
590
623
  # Add broadcast socket options if necessary
591
- if (host == '255.255.255.255')
592
- listener.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
624
+ if host == '255.255.255.255'
625
+ listener.setsockopt Socket::SOL_SOCKET, Socket::SO_BROADCAST, true
593
626
  end
594
627
  if listener
595
- # Bind socket to listen for response
596
- begin
597
- listener.bind '0.0.0.0',9761
598
- rescue
599
- response = "can't bind to listen for a reply"
628
+ if listen
629
+ # Bind socket to listen for response
630
+ begin
631
+ listener.bind '0.0.0.0', 9761
632
+ rescue
633
+ response = "can't bind to listen for a reply"
634
+ end
600
635
  end
601
636
  # Broadcast command to server
602
- listener.send(command, 0, host, 9760)
637
+ debug and ( p self.time 'sending...' )
638
+ listener.send command, 0, host, 9760
639
+ debug and ( p self.time 'sent' )
603
640
  # Receive response
604
- if ! response
641
+ if listen and ! response
642
+ debug and ( p self.time 'receiving...' )
605
643
  response, addr = listener.recvfrom 200
644
+ debug and ( p self.time 'received' )
606
645
  end
646
+ debug and ( p self.time 'closing...' )
607
647
  listener.close
648
+ debug and ( p self.time 'closed' )
608
649
  end
650
+ debug and ( puts '[Info - LightWaveRF] ' + __method__.to_s + ': response is ' + response.to_s )
609
651
  response
610
652
  end
611
653
 
612
654
  def update_timers past = 60, future = 1440, debug = false
613
655
  p '----------------'
614
- p "Updating timers..."
656
+ p 'Updating timers...'
615
657
 
616
658
  # determine the window to query
617
659
  now = Time.new
@@ -983,15 +1025,16 @@ class LightWaveRF
983
1025
  p 'Executing sequence. Sequence: ' + event['state']
984
1026
  result = self.sequence event['state'], debug
985
1027
  else
986
- p 'Executing device. Room: ' + event['room'] + ', Device: ' + event['device'] + ', State: ' + event['state']
987
- result = self.send event['room'], event['device'], event['state'], debug
1028
+ p 'Executing device. Room: ' + event['room'] + ', Device: ' + event['device'].to_s + ', State: ' + event['state']
1029
+ # result = self.send event['room'], event['device']['name'], event['state'], debug
1030
+ result = self.send event['room'], event['device'].to_s, event['state'], debug # is this right?
988
1031
  end
989
1032
  sleep 1
990
- triggered << [ event['room'], event['device'], event['state'] ]
1033
+ triggered << [ event['room'], event['device'].to_s, event['state'] ]
991
1034
  if event['annotate']
992
1035
  annotate = true
993
1036
  end
994
- self.log_timer_event event['type'], event['room'], event['device'], event['state'], result
1037
+ self.log_timer_event event['type'], event['room'], event['device'].to_s, event['state'], result
995
1038
  end
996
1039
 
997
1040
  # update energy log
@@ -1053,7 +1096,7 @@ class LightWaveRF
1053
1096
  Sample page generated #{date} with <code>lightwaverf web</code>.
1054
1097
  Check out <a href="https://github.com/pauly/lightwaverf">the new simplified repo</a> for details
1055
1098
  or <a href="https://rubygems.org/gems/lightwaverf">gem install lightwaverf && lightwaverf web</a>...
1056
- <br />@todo make a decent, useful, simple, configurable web page...
1099
+ <br />@todo merge this with <a href="https://github.com/pauly/robot-butler">robot butler</a>...
1057
1100
  end
1058
1101
  help = list
1059
1102
  html = <<-end
@@ -1105,20 +1148,29 @@ class LightWaveRF
1105
1148
  daily = self.class.get_json file
1106
1149
  start_date = 0
1107
1150
  d = nil
1151
+ last = nil
1152
+ prev = nil
1108
1153
  File.open( self.get_log_file, 'r' ).each_line do | line |
1109
- line = JSON.parse line
1110
- if line and line['timestamp']
1154
+ begin
1155
+ line = JSON.parse line
1156
+ rescue
1157
+ line = nil
1158
+ end
1159
+ if line and line['timestamp'] and ( last != line['message']['usage'] )
1111
1160
  new_line = []
1112
1161
  d = line['timestamp'][2..3] + line['timestamp'][5..6] + line['timestamp'][8..9] # compact version of date
1113
1162
  ts = Time.parse( line['timestamp'] ).strftime '%s'
1114
1163
  ts = ts.to_i
1115
- if start_date > 0
1116
- ts = ts - start_date
1117
- else
1118
- start_date = ts
1164
+ ts = ts - start_date
1165
+ if start_date == 0
1166
+ # start_date = ts # can't get this delta working
1119
1167
  end
1120
1168
  new_line << ts
1121
- new_line << line['message']['usage'].to_i / 10
1169
+ smoothedUsage = line['message']['usage'].to_i
1170
+ if last && prev
1171
+ smoothedUsage = ( smoothedUsage + last + prev ) / 3 # average of last 3 readings
1172
+ end
1173
+ new_line << smoothedUsage / 10
1122
1174
  if line['message']['annotation'] and line['message']['annotation']['title'] and line['message']['annotation']['text']
1123
1175
  new_line << line['message']['annotation']['title']
1124
1176
  new_line << line['message']['annotation']['text']
@@ -1128,6 +1180,8 @@ class LightWaveRF
1128
1180
  daily[d] = line['message']
1129
1181
  daily[d].delete 'usage'
1130
1182
  end
1183
+ prev = last
1184
+ last = line['message']['usage'].to_i
1131
1185
  end
1132
1186
  end
1133
1187
  debug and ( puts 'got ' + data.length.to_s + ' lines in the log' )
@@ -1141,7 +1195,8 @@ class LightWaveRF
1141
1195
  end
1142
1196
  summary_file = self.get_summary_file
1143
1197
  File.open( summary_file, 'w' ) do |file|
1144
- file.write data.to_s
1198
+ # file.write data.to_s
1199
+ file.write( JSON.pretty_generate( data ))
1145
1200
  end
1146
1201
  # @todo fix the daily stats, every night it reverts to the minimum value because the timezones are different
1147
1202
  # so 1am on the wifi-link looks midnight on the server
@@ -1153,4 +1208,9 @@ class LightWaveRF
1153
1208
  end
1154
1209
  end
1155
1210
 
1211
+ # http://lightwaverfcommunity.org.uk/forums/topic/link-no-longer-responding-to-udp-commands-any-advice/page/4/#post-16098
1212
+ def firmware debug = true
1213
+ self.raw '666,!F*p', true, debug
1214
+ end
1215
+
1156
1216
  end
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.6
4
+ version: '0.7'
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-10-16 00:00:00.000000000 Z
14
+ date: 2014-10-24 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: htmlentities
@@ -47,7 +47,8 @@ dependencies:
47
47
  version: '0'
48
48
  description: ! " Interact with lightwaverf wifi-link from code or the command line.\n
49
49
  \ Control your lights, heating, sockets, sprinkler etc.\n Also use a google
50
- calendar, for timers, log energy usage, and build a website.\n"
50
+ calendar, for timers, log energy usage, and build a website.\n And now optionally
51
+ logging to a google doc too.\n"
51
52
  email: pauly@clarkeology.com
52
53
  executables:
53
54
  - lightwaverf