lightwaverf 0.6.6 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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