iStats 0.0.4 → 0.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9bff6f43ceaf154fc22a175a84ab82d3f1230346
4
- data.tar.gz: bcd0dbe5bdbf052142511505b98d8f600d0c1703
3
+ metadata.gz: e4b51e404e967587290c2dffb093f7703ab1440f
4
+ data.tar.gz: d4c35add73857760cbcd18a1f3bd6c23f53f3373
5
5
  SHA512:
6
- metadata.gz: a640c65868a3f78e2f7fb2f9221ccb1de7f7f013e8c81ba5f83fb19d208468c5b1377648a1430323e1d36528ed31100d10bc12841b01e698277665b4d1947ab0
7
- data.tar.gz: 6d640b55b90680bdf895d685eff2b1ce2b17d3b3fc9e1d438f2dd980e10eade76cfcf87fe0eaf9fd4cb8b2ddcab7e8eae464c665ab2675daf2c8c52a5b7622cb
6
+ metadata.gz: 7d2a747930f420134915c961db00568d8bb17bc3b64bdad0ba7a371e7f4fc27460572c69a0a602202eb063d21caeb043375cdb48f89ebba3d0fd2f9feb1a9c4c
7
+ data.tar.gz: bcb29f420afbd849737bc859772a332df2e6d796c8f89184716ccb3be3a793035d19cd0011e577d4e902f62caf3d28ab48703de7d6ccf1b612fa726559b4cba6
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- iStats (0.0.3)
4
+ iStats (0.0.4)
5
5
  sparkr
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,33 +1,42 @@
1
- iStats
1
+ iStats [![Gem Version](https://badge.fury.io/rb/iStats.svg)](http://badge.fury.io/rb/iStats)
2
2
  ======
3
3
 
4
- Quick attempt at writing a Ruby wrapper for a small C library that interacts with the IOKit library (apple) to get the CPU temperature. Will expand to more hardware data and stats in the future.
4
+ Quick attempt at writing a Ruby wrapper for a small C library that interacts with the IOKit library (apple) to get the CPU temperature and fan speed. Will expand to more hardware data and stats in the future.
5
+
6
+ #### Warning
7
+ A [bug in Ruby](https://bugs.ruby-lang.org/issues/9624) and Apple XCode 5.1 onwards (new CLANG version) might make it impossible to install this gem if you are using Ruby from the Xcode command-line tools package. If you are using RVM or homebrew to manage your Ruby installation you should be fine.
5
8
 
6
9
  #### Tested on
7
10
  MacBook Pro 2012<br>
8
11
  OS X 10.9.2<br>
9
12
  Ruby: 1.9.3, 2.0.0, 2.1.1<br>
10
13
 
11
- ## Screenshot
12
- ![](http://i.imgur.com/ht2NZCL.gif)
13
-
14
14
  ## Installation
15
15
 
16
16
  $ gem install iStats
17
17
 
18
+ ## Screenshot
19
+ #### All Stats
20
+ ![](http://i.imgur.com/pNZwCmg.png)
21
+
22
+ #### Sparkline levels
23
+ ![](http://i.imgur.com/ht2NZCL.gif)
24
+
18
25
  ## Usage
19
26
 
20
27
  ```
21
- - iStats: help ---------------------------------------------------
28
+ - iStats: help ---------------------------------------------------
22
29
 
23
- istats --help This help text
24
- istats --version Print current version
30
+ istats --help This help text
31
+ istats --version Print current version
25
32
 
26
- istats all Print all stats
27
- istats cpu Print all CPU stats
28
- istats cpu [temp | temperature] Print CPU temperature
33
+ istats all Print all stats
34
+ istats cpu Print all CPU stats
35
+ istats cpu [temp | temperature] Print CPU temperature
36
+ istats fan Print all fan stats
37
+ istats fan [speed] Print fan speed
29
38
 
30
- for more help see: https://github.com/Chris911/iStats
39
+ for more help see: https://github.com/Chris911/iStats
31
40
  ```
32
41
 
33
42
  ## Contributing
@@ -2,7 +2,7 @@ require 'mkmf'
2
2
 
3
3
  extension_name = 'osx_stats'
4
4
 
5
- CONFIG['LDSHARED'] << ' -framework IOKit '
5
+ CONFIG['LDSHARED'] << ' -framework IOKit -framework CoreFoundation '
6
6
 
7
7
  # The destination
8
8
  dir_config(extension_name)
@@ -205,53 +205,152 @@ int SMCGetFanNumber(char *key)
205
205
  return _strtoul((char *)val.bytes, val.dataSize, 10);
206
206
  }
207
207
 
208
- // int main(int argc, char *argv[])
209
- // {
210
- // SMCOpen();
211
- // //printf("%0.1f°C\n", SMCGetTemperature(SMC_KEY_CPU_TEMP));
212
- // //printf("%0.1f\n", SMCGetFanSpeed(0));
213
- // //printf("%0.1f\n", SMCGetFanSpeed(3));
214
- // //printf("%i\n", SMCGetFanNumber(SMC_KEY_FAN_NUM));
215
- // SMCClose();
216
- //
217
- // return 0;
218
- // }
208
+ /* Battery info
209
+ * Ref: http://www.newosxbook.com/src.jl?tree=listings&file=bat.c
210
+ * https://developer.apple.com/library/mac/documentation/IOKit/Reference/IOPowerSources_header_reference/Reference/reference.html
211
+ */
212
+ void dumpDict (CFDictionaryRef Dict)
213
+ {
214
+ // Helper function to just dump a CFDictioary as XML
215
+ CFDataRef xml = CFPropertyListCreateXMLData(kCFAllocatorDefault, (CFPropertyListRef)Dict);
216
+ if (xml) { write(1, CFDataGetBytePtr(xml), CFDataGetLength(xml)); CFRelease(xml); }
217
+ }
219
218
 
220
- //
221
- // RUBY MODULE
222
- //
219
+ CFDictionaryRef powerSourceInfo(int Debug)
220
+ {
221
+ CFTypeRef powerInfo;
222
+ CFArrayRef powerSourcesList;
223
+ CFDictionaryRef powerSourceInformation;
224
+
225
+ powerInfo = IOPSCopyPowerSourcesInfo();
226
+
227
+ if(! powerInfo) return NULL;
228
+
229
+ powerSourcesList = IOPSCopyPowerSourcesList(powerInfo);
230
+ if(!powerSourcesList) {
231
+ CFRelease(powerInfo);
232
+ return NULL;
233
+ }
234
+
235
+ // Should only get one source. But in practice, check for > 0 sources
236
+ if (CFArrayGetCount(powerSourcesList))
237
+ {
238
+ powerSourceInformation = IOPSGetPowerSourceDescription(powerInfo, CFArrayGetValueAtIndex(powerSourcesList, 0));
239
+
240
+ if (Debug) dumpDict (powerSourceInformation);
241
+
242
+ //CFRelease(powerInfo);
243
+ //CFRelease(powerSourcesList);
244
+ return powerSourceInformation;
245
+ }
246
+
247
+ CFRelease(powerInfo);
248
+ CFRelease(powerSourcesList);
249
+ return NULL;
250
+ }
251
+
252
+ int getDesignCycleCount() {
253
+ CFDictionaryRef powerSourceInformation = powerSourceInfo(0);
254
+
255
+ if(powerSourceInformation == NULL)
256
+ return 0;
257
+
258
+ CFNumberRef designCycleCountRef = (CFNumberRef) CFDictionaryGetValue(powerSourceInformation, CFSTR("DesignCycleCount"));
259
+ uint32_t designCycleCount;
260
+ if ( ! CFNumberGetValue(designCycleCountRef, // CFNumberRef number,
261
+ kCFNumberSInt32Type, // CFNumberType theType,
262
+ &designCycleCount)) // void *valuePtr);
263
+ return 0;
264
+ else
265
+ return designCycleCount;
266
+ }
267
+
268
+ const char* getBatteryHealth() {
269
+ CFDictionaryRef powerSourceInformation = powerSourceInfo(0);
270
+
271
+ if(powerSourceInformation == NULL)
272
+ return "Unknown";
273
+
274
+ CFStringRef batteryHealthRef = (CFStringRef) CFDictionaryGetValue(powerSourceInformation, CFSTR("BatteryHealth"));
275
+
276
+ const char *batteryHealth = CFStringGetCStringPtr(batteryHealthRef, // CFStringRef theString,
277
+ kCFStringEncodingMacRoman); //CFStringEncoding encoding);
278
+ return batteryHealth;
279
+ }
280
+
281
+ /*
282
+ RUBY MODULES
283
+ */
223
284
  VALUE CPU_STATS = Qnil;
224
285
  VALUE FAN_STATS = Qnil;
286
+ VALUE BATTERY_STATS = Qnil;
287
+ /*
288
+ * Define Ruby modules and associated methods
289
+ * We never call this, Ruby does.
290
+ */
225
291
  void Init_osx_stats() {
226
- CPU_STATS = rb_define_module("CPU_STATS");
227
- rb_define_method(CPU_STATS, "get_cpu_temp", method_get_cpu_temp, 0);
292
+ CPU_STATS = rb_define_module("CPU_STATS");
293
+ rb_define_method(CPU_STATS, "get_cpu_temp", method_get_cpu_temp, 0);
294
+
295
+ FAN_STATS = rb_define_module("FAN_STATS");
296
+ rb_define_method(FAN_STATS, "get_fan_number", method_get_fan_number, 0);
297
+ rb_define_method(FAN_STATS, "get_fan_speed", method_get_fan_speed, 1);
228
298
 
229
- FAN_STATS = rb_define_module("FAN_STATS");
230
- rb_define_method(FAN_STATS, "get_fan_number", method_get_fan_number, 0);
231
- rb_define_method(FAN_STATS, "get_fan_speed", method_get_fan_speed, 1);
299
+ BATTERY_STATS = rb_define_module("BATTERY_STATS");
300
+ rb_define_method(BATTERY_STATS, "get_battery_health", method_get_battery_health, 0);
301
+ rb_define_method(BATTERY_STATS, "get_battery_design_cycle_count", method_get_battery_design_cycle_count, 0);
232
302
  }
233
303
 
234
304
  VALUE method_get_cpu_temp(VALUE self) {
235
- SMCOpen();
236
- double temp = SMCGetTemperature(SMC_KEY_CPU_TEMP);
237
- SMCClose();
305
+ SMCOpen();
306
+ double temp = SMCGetTemperature(SMC_KEY_CPU_TEMP);
307
+ SMCClose();
238
308
 
239
- return rb_float_new(temp);
309
+ return rb_float_new(temp);
240
310
  }
241
311
 
242
312
  VALUE method_get_fan_number(VALUE self) {
243
- SMCOpen();
244
- int num = SMCGetFanNumber(SMC_KEY_FAN_NUM);
245
- SMCClose();
313
+ SMCOpen();
314
+ int num = SMCGetFanNumber(SMC_KEY_FAN_NUM);
315
+ SMCClose();
246
316
 
247
- return INT2NUM(num);
317
+ return INT2NUM(num);
248
318
  }
249
319
 
250
320
  VALUE method_get_fan_speed(VALUE self, VALUE num) {
251
- uint fanNum = NUM2UINT(num);
252
- SMCOpen();
253
- float speed = SMCGetFanSpeed(fanNum);
254
- SMCClose();
321
+ uint fanNum = NUM2UINT(num);
322
+ SMCOpen();
323
+ float speed = SMCGetFanSpeed(fanNum);
324
+ SMCClose();
255
325
 
256
- return rb_float_new(speed);
326
+ return rb_float_new(speed);
257
327
  }
328
+
329
+ VALUE method_get_battery_health(VALUE self) {
330
+ const char* health = getBatteryHealth();
331
+ return rb_str_new2(health);
332
+ }
333
+
334
+ VALUE method_get_battery_design_cycle_count(VALUE self) {
335
+ int cc = getDesignCycleCount();
336
+ return INT2NUM(cc);
337
+ }
338
+
339
+ /* Main method used for test */
340
+ // int main(int argc, char *argv[])
341
+ // {
342
+ // //SMCOpen();
343
+ // //printf("%0.1f°C\n", SMCGetTemperature(SMC_KEY_CPU_TEMP));
344
+ // //printf("%0.1f\n", SMCGetFanSpeed(0));
345
+ // //printf("%0.1f\n", SMCGetFanSpeed(3));
346
+ // //printf("%i\n", SMCGetFanNumber(SMC_KEY_FAN_NUM));
347
+ // //SMCClose();
348
+ //
349
+ // int designCycleCount = getDesignCycleCount();
350
+ // const char* batteryHealth = getBatteryHealth();
351
+ //
352
+ // if (designCycleCount) printf ("%i\n", designCycleCount);
353
+ // if (batteryHealth) printf ("%s\n", batteryHealth);
354
+ //
355
+ // return 0;
356
+ // }
@@ -20,6 +20,7 @@
20
20
  #ifndef __SMC_H__
21
21
  #define __SMC_H__
22
22
  #include "ruby.h"
23
+ #include <CoreFoundation/CoreFoundation.h>
23
24
  #endif
24
25
 
25
26
  #define VERSION "0.01"
@@ -90,14 +91,20 @@ typedef struct {
90
91
  SMCBytes_t bytes;
91
92
  } SMCVal_t;
92
93
 
93
-
94
94
  // prototypes
95
95
  float SMCGetFanSpeed(int fanNum);
96
96
  int SMCGetFanNumber(char *key);
97
97
  double SMCGetTemperature(char *key);
98
+ const char* getBatteryHealth();
99
+ int getDesignCycleCount();
100
+ CFTypeRef IOPSCopyPowerSourcesInfo(void);
101
+ CFArrayRef IOPSCopyPowerSourcesList(CFTypeRef blob);
102
+ CFDictionaryRef IOPSGetPowerSourceDescription(CFTypeRef blob, CFTypeRef ps);
98
103
 
99
104
  // Ruby modules
100
105
  void Init_osx_stats();
101
106
  VALUE method_get_cpu_temp(VALUE self);
102
107
  VALUE method_get_fan_speed(VALUE self, VALUE num);
103
108
  VALUE method_get_fan_number(VALUE self);
109
+ VALUE method_get_battery_health(VALUE self);
110
+ VALUE method_get_battery_design_cycle_count(VALUE self);
@@ -12,6 +12,7 @@ require 'iStats/symbols'
12
12
  require 'iStats/command'
13
13
  require 'iStats/cpu'
14
14
  require 'iStats/fan'
15
+ require 'iStats/battery'
15
16
 
16
17
  module IStats
17
18
  def self.options
@@ -0,0 +1,79 @@
1
+ # Fan Stats
2
+ # Extend BATTERY_STATS C module (ext/osx_stats/smc.c)
3
+ #
4
+ module IStats
5
+ class Battery
6
+ extend BATTERY_STATS
7
+ class << self
8
+ include IStats::Color
9
+
10
+ # Delegate CLI command to function
11
+ #
12
+ def delegate(stat)
13
+ case stat
14
+ when 'all'
15
+ all
16
+ when 'health'
17
+ battery_health
18
+ when 'cycle_count', 'cc'
19
+ cycle_count
20
+ else
21
+ Command.help "Unknown stat for Battery: #{stat}"
22
+ end
23
+ end
24
+
25
+ # Call all functions (stats)
26
+ #
27
+ def all
28
+ battery_health
29
+ cycle_count
30
+ end
31
+
32
+ # Prints the battery cycle count info
33
+ #
34
+ def cycle_count
35
+ data = %x( ioreg -l | grep Capacity )
36
+ cycle_count = data[/"Cycle Count"=([0-9]*)/, 1]
37
+ if cycle_count == nil
38
+ puts "Cycle count: unknown"
39
+ else
40
+ max_cycle_count = design_cycle_count
41
+ percentage = (cycle_count.to_f/max_cycle_count.to_f)*100
42
+
43
+ list = [0, 30, 55, 80, 100, 130]
44
+ sparkline = Sparkr.sparkline(list) do |tick, count, index|
45
+ if index.between?(0, 5) and percentage > 95
46
+ flash_red(tick)
47
+ elsif index.between?(0, 1)
48
+ green(tick)
49
+ elsif index.between?(2, 3) and percentage > 45
50
+ light_yellow(tick)
51
+ elsif index == 4 and percentage > 65
52
+ yellow(tick)
53
+ elsif index == 5 and percentage > 85
54
+ red(tick)
55
+ else
56
+ tick
57
+ end
58
+ end
59
+ puts "Cycle count: #{cycle_count} " + sparkline
60
+ puts "Max cycle count: #{max_cycle_count}"
61
+ end
62
+ end
63
+
64
+ # Get the battery health
65
+ # Calls a C method from BATTERY_STATS module
66
+ #
67
+ def battery_health
68
+ puts "Battery health: #{get_battery_health}"
69
+ end
70
+
71
+ # Get the battery design cycle count
72
+ # Calls a C method from BATTERY_STATS module
73
+ #
74
+ def design_cycle_count
75
+ get_battery_design_cycle_count
76
+ end
77
+ end
78
+ end
79
+ end
@@ -4,6 +4,10 @@ module IStats
4
4
  class << self
5
5
  include IStats::Color
6
6
 
7
+ # Executes a command
8
+ #
9
+ # args - Command line arguments
10
+ #
7
11
  def execute(*args)
8
12
  # Default command is 'all'
9
13
  category = args.empty? ? 'all' : args.shift
@@ -13,6 +17,11 @@ module IStats
13
17
  delegate(category, stat)
14
18
  end
15
19
 
20
+ # Delegate command to proper class
21
+ #
22
+ # category - Hardware we are targeting (CPU, fan, etc.)
23
+ # stat - The stat we want
24
+ #
16
25
  def delegate(category, stat)
17
26
  case category
18
27
  when 'all'
@@ -21,17 +30,22 @@ module IStats
21
30
  Cpu.delegate stat
22
31
  when 'fan'
23
32
  Fan.delegate stat
33
+ when 'battery'
34
+ Battery.delegate stat
24
35
  else
25
36
  help("Unknown category: #{category}")
26
37
  end
27
38
  end
28
39
 
40
+ # Execute all the stats methodes for all modules
41
+ #
29
42
  def all
30
- # Exec all
31
43
  puts "--- CPU Stats ---\n"
32
44
  Cpu.all
33
45
  puts "\n--- Fan Stats ---\n"
34
46
  Fan.all
47
+ puts "\n--- Battery Stats ---\n"
48
+ Battery.all
35
49
  end
36
50
 
37
51
  # Public: Parse extra options
@@ -75,6 +89,8 @@ module IStats
75
89
  istats cpu [temp | temperature] Print CPU temperature
76
90
  istats fan Print all fan stats
77
91
  istats fan [speed] Print fan speed
92
+ istats battery [health] Print battery health
93
+ istats battery [cycleCount | cc] Print battery cycle count info
78
94
 
79
95
  for more help see: https://github.com/Chris911/iStats
80
96
  ".gsub(/^ {8}/, '') # strip the first eight spaces of every line
@@ -1,11 +1,14 @@
1
+ # CPU Stats
2
+ # Extend CPU_STATS C module (ext/osx_stats/smc.c)
3
+ #
1
4
  module IStats
2
- # CPU Stats
3
- # Extend CPU_STATS C module (ext/osx_stats/smc.c)
4
5
  class Cpu
5
6
  extend CPU_STATS
6
7
  class << self
7
8
  include IStats::Color
8
9
 
10
+ # Delegate CLI command to function
11
+ #
9
12
  def delegate(stat)
10
13
  case stat
11
14
  when 'all'
@@ -17,10 +20,15 @@ module IStats
17
20
  end
18
21
  end
19
22
 
23
+ # Call all functions (stats)
24
+ #
20
25
  def all
21
26
  cpu_temperature
22
27
  end
23
28
 
29
+ # Print CPU temperature with sparkline
30
+ # TODO: Move sparkline function to printer class
31
+ #
24
32
  def cpu_temperature
25
33
  t = get_cpu_temp
26
34
  message = "CPU temp: #{t}#{Symbols.degree}C "
@@ -1,11 +1,14 @@
1
+ # Fan Stats
2
+ # Extend FAN_STATS C module (ext/osx_stats/smc.c)
3
+ #
1
4
  module IStats
2
- # Fan Stats
3
- # Extend FAN_STATS C module (ext/osx_stats/smc.c)
4
5
  class Fan
5
6
  extend FAN_STATS
6
7
  class << self
7
8
  include IStats::Color
8
9
 
10
+ # Delegate CLI command to function
11
+ #
9
12
  def delegate(stat)
10
13
  case stat
11
14
  when 'all'
@@ -19,20 +22,28 @@ module IStats
19
22
  end
20
23
  end
21
24
 
25
+ # Call all functions (stats)
26
+ #
22
27
  def all
23
28
  print_fan_number
24
29
  fans_speed
25
30
  end
26
31
 
32
+ # Get the number of fans on system
33
+ # Calls a C method from FAN_STATS module
34
+ #
27
35
  def fan_number
28
- # C method
29
36
  get_fan_number
30
37
  end
31
38
 
39
+ # Print number of fan(s)
40
+ #
32
41
  def print_fan_number
33
- puts "Total fans on system: #{fan_number}"
42
+ puts "Total fans in system: #{fan_number}"
34
43
  end
35
44
 
45
+ # Get and print the speed of each fan
46
+ #
36
47
  def fans_speed
37
48
  fanNum = fan_number
38
49
  (0..(fanNum-1)).each do |n|
@@ -41,6 +52,12 @@ module IStats
41
52
  end
42
53
  end
43
54
 
55
+ # Actually print fan speed with Sparkline
56
+ # TODO: Move sparkline function to printer class
57
+ #
58
+ # fanNum - The fan number
59
+ # speed - Fan speed in RPM
60
+ #
44
61
  def print_fan_speed(fanNum, speed)
45
62
  message = "Fan #{fanNum} speed: #{speed} RPM "
46
63
  list = [0, 30, 55, 80, 100, 130]
@@ -1,3 +1,3 @@
1
1
  module IStats
2
- VERSION = '0.0.4'
2
+ VERSION = '0.0.5'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iStats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris911
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-14 00:00:00.000000000 Z
11
+ date: 2014-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sparkr
@@ -87,6 +87,7 @@ files:
87
87
  - ext/osx_stats/smc.h
88
88
  - iStats.gemspec
89
89
  - lib/iStats.rb
90
+ - lib/iStats/battery.rb
90
91
  - lib/iStats/color.rb
91
92
  - lib/iStats/command.rb
92
93
  - lib/iStats/cpu.rb