currentcost 0.3.4
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.
- data/COPYING +19 -0
- data/README +46 -0
- data/bin/currentcost_tray_monitor.rb +383 -0
- data/examples/simple.rb +39 -0
- data/lib/currentcost.rb +6 -0
- data/lib/currentcost/exceptions.rb +7 -0
- data/lib/currentcost/meter.rb +79 -0
- data/lib/currentcost/reading.rb +129 -0
- data/lib/currentcost/version.rb +10 -0
- metadata +72 -0
data/COPYING
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2008 James Smith (james@floppy.org.uk)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
== CurrentCost-Ruby
|
2
|
+
|
3
|
+
A gem to provide a Ruby interface to the CurrentCost energy meter
|
4
|
+
(http://www.currentcost.com)
|
5
|
+
|
6
|
+
Licensed under the MIT license (See COPYING file for details)
|
7
|
+
|
8
|
+
Author: James Smith (james@floppy.org.uk / http://www.floppy.org.uk)
|
9
|
+
|
10
|
+
Homepage: http://github.com/Floppy/currentcost-ruby
|
11
|
+
|
12
|
+
Documentation: http://docs.github.com/Floppy/currentcost-ruby
|
13
|
+
|
14
|
+
== INSTALLATION
|
15
|
+
|
16
|
+
1) Enable gems from gemcutter, if you haven't already done so:
|
17
|
+
> sudo gem install gemcutter
|
18
|
+
> sudo gem tumble
|
19
|
+
|
20
|
+
2) Install gem
|
21
|
+
> sudo gem install currentcost
|
22
|
+
|
23
|
+
== REQUIREMENTS
|
24
|
+
|
25
|
+
rb232 >= 0.2.3
|
26
|
+
|
27
|
+
== USAGE
|
28
|
+
|
29
|
+
You can read data from the meter by creating an instance of the CurrentCost::Meter
|
30
|
+
class, and registering an observer which will receive readings. See examples/simple.rb
|
31
|
+
or the CurrentCost::Meter documentation for a simple example of how to do this.
|
32
|
+
|
33
|
+
== TRAY MONITOR
|
34
|
+
|
35
|
+
This gem includes the 'currentcost_tray_monitor.rb' application. This is a program
|
36
|
+
which will sit in your system tray and display a coloured icon based on your power
|
37
|
+
usage. To use the program, run:
|
38
|
+
|
39
|
+
currentcost_tray_monitor.rb -p your_serial_port_name
|
40
|
+
|
41
|
+
The program requires the Gtk2 libraries for Ruby (available from
|
42
|
+
http://ruby-gnome2.sourceforge.jp/). If the EEML gem (http://github.com/Floppy/eeml-ruby)
|
43
|
+
is installed, it can also serve your power data over an HTTP connection to a system like
|
44
|
+
Pachube (http://www.pachube.com).
|
45
|
+
|
46
|
+
For more details, see http://github.com/Floppy/currentcost-ruby/wikis/currentcosttraymonitor
|
@@ -0,0 +1,383 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
dir = File.dirname(__FILE__) + '/../lib'
|
4
|
+
$LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
|
5
|
+
|
6
|
+
require 'gtk2'
|
7
|
+
require 'rubygems'
|
8
|
+
require 'currentcost'
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
# If EEML is available, start a simple server which will serve power information
|
12
|
+
begin
|
13
|
+
require 'eeml'
|
14
|
+
require 'webrick'
|
15
|
+
$eeml_server_enabled = true
|
16
|
+
rescue LoadError
|
17
|
+
$eeml_server_enabled = false
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# Command-line options
|
22
|
+
options = {:port => '/dev/ttyS0'}
|
23
|
+
OptionParser.new do |opts|
|
24
|
+
opts.on("-p", "--serial_port SERIAL_PORT", "serial port") do |p|
|
25
|
+
options[:port] = p
|
26
|
+
end
|
27
|
+
if $eeml_server_enabled == true
|
28
|
+
opts.on("-h", "--http_port HTTP_PORT", "http port") do |h|
|
29
|
+
options[:http_port] = h
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end.parse!
|
33
|
+
|
34
|
+
# Pixbuf images - generated from PNG files with gdk-pixbuf-csource --raw
|
35
|
+
GREY =
|
36
|
+
# Pixbuf magic (0x47646b50)
|
37
|
+
"GdkP" <<
|
38
|
+
# length: header (24) + pixel_data (1024)
|
39
|
+
"\0\0\4\30" <<
|
40
|
+
# pixdata_type (0x1010002)
|
41
|
+
"\1\1\0\2" <<
|
42
|
+
# rowstride (64)
|
43
|
+
"\0\0\0@" <<
|
44
|
+
# width (16)
|
45
|
+
"\0\0\0\20" <<
|
46
|
+
# height (16)
|
47
|
+
"\0\0\0\20" <<
|
48
|
+
# pixel_data:
|
49
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\351\352\351J\360\360\360\262\353\353" <<
|
50
|
+
"\353\371\347\347\347\377\337\337\337\377\322\323\322\371\310\310\310" <<
|
51
|
+
"\262\267\267\267J\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\336" <<
|
52
|
+
"\336\336\30\366\366\366\270\371\370\370\377\360\360\360\377\350\350\347" <<
|
53
|
+
"\377\337\337\337\377\327\327\327\377\316\317\317\377\306\306\306\377" <<
|
54
|
+
"\275\275\276\377\260\257\257\270\232\232\232\30\0\0\0\0\0\0\0\0\0\0\0" <<
|
55
|
+
"\0\336\336\336\30\371\370\370\335\370\370\370\377\365\365\365\377\347" <<
|
56
|
+
"\347\350\377\337\337\337\377\327\327\327\377\317\316\316\377\306\306" <<
|
57
|
+
"\306\377\275\275\276\377\265\265\265\377\255\255\255\377\241\241\241" <<
|
58
|
+
"\335\213\214\214\30\0\0\0\0\0\0\0\0\366\366\366\270\370\370\370\377\366" <<
|
59
|
+
"\366\366\377\377\377\377\377\355\355\355\377\327\326\327\377\316\316" <<
|
60
|
+
"\316\377\306\306\306\377\275\275\275\377\265\265\265\377\255\255\254" <<
|
61
|
+
"\377\244\244\244\377\234\234\234\377\217\217\217\270\0\0\0\0\351\350" <<
|
62
|
+
"\350J\370\370\370\377\360\360\360\377\374\374\374\377\377\377\377\377" <<
|
63
|
+
"\365\366\366\377\316\316\316\377\306\306\306\377\275\275\275\377\265" <<
|
64
|
+
"\265\265\377\255\255\255\377\244\244\244\377\234\234\234\377\223\223" <<
|
65
|
+
"\223\377\213\213\213\377}||J\357\357\357\262\360\360\360\377\354\354" <<
|
66
|
+
"\354\377\377\377\377\377\377\377\377\377\377\377\377\377\314\314\314" <<
|
67
|
+
"\377\275\275\275\377\275\275\275\377\276\276\276\377\244\244\244\377" <<
|
68
|
+
"\234\233\233\377\223\223\223\377\213\213\213\377\202\202\203\377www\262" <<
|
69
|
+
"\352\352\352\371\347\347\347\377\364\364\364\377\377\377\377\377\377" <<
|
70
|
+
"\377\377\377\377\377\377\377\332\332\332\377\265\265\265\377\354\354" <<
|
71
|
+
"\354\377\377\377\377\377\275\274\275\377\267\267\267\377\261\261\261" <<
|
72
|
+
"\377\254\253\253\377\246\246\246\377\237\237\237\373\347\347\347\377" <<
|
73
|
+
"\342\342\342\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
74
|
+
"\377\377\377\356\356\356\377\276\276\277\377\377\377\377\377\377\377" <<
|
75
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
76
|
+
"\377\377\377\377\377\377\377\377\377\336\336\336\377\354\354\355\377" <<
|
77
|
+
"\377\377\377\377\377\377\377\377\323\323\323\377\377\377\377\377\377" <<
|
78
|
+
"\377\377\377\340\340\340\377\377\377\377\377\377\377\377\377\377\377" <<
|
79
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
80
|
+
"\377\377\377\377\377\325\325\325\372\371\371\371\377\377\377\377\377" <<
|
81
|
+
"\341\341\341\377\265\265\265\377\377\377\377\377\377\377\377\377\377" <<
|
82
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\322\322" <<
|
83
|
+
"\322\377qqr\377iii\377``a\377UUU\371\335\335\335\314\377\377\377\377" <<
|
84
|
+
"\377\377\377\377\275\275\275\377\254\254\254\377\352\352\352\377\377" <<
|
85
|
+
"\377\377\377\377\377\377\377\377\377\377\377\271\271\271\377\322\322" <<
|
86
|
+
"\322\377\200\200\200\377iih\377`aa\377XXX\377NNN\262\343\343\343\206" <<
|
87
|
+
"\377\377\377\377\356\356\356\377\254\254\254\377\244\243\243\377\274" <<
|
88
|
+
"\274\274\377\377\377\377\377\377\377\377\377\343\343\343\377yyy\377q" <<
|
89
|
+
"qq\377iii\377```\377XXX\377OOO\377GGGJ\377\377\377\34\351\351\351\347" <<
|
90
|
+
"\265\265\265\377\243\244\244\377\233\233\233\377\223\223\223\377\377" <<
|
91
|
+
"\377\377\377\377\377\377\377\246\246\245\377qqq\377iii\377```\377XXX" <<
|
92
|
+
"\377OOO\377EEE\270\0\0\0\0\0\0\0\0\224\223\224\30\237\237\237\335\233" <<
|
93
|
+
"\233\233\377\223\223\223\377\212\212\212\377\307\307\307\377\360\360" <<
|
94
|
+
"\360\377qqq\377ihh\377```\377XWX\377OPO\377EEE\335=>=\30\0\0\0\0\0\0" <<
|
95
|
+
"\0\0\0\0\0\0\204\205\205\30\214\215\214\270\212\212\212\377\201\202\202" <<
|
96
|
+
"\377yyy\377qqq\377hhh\377```\377XXX\377OOO\377EEE\270===\30\0\0\0\0\0" <<
|
97
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0yxyJuuu\262lll\371ggg\377^_^\377" <<
|
98
|
+
"TTS\371MMM\262EFFJ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
99
|
+
|
100
|
+
GREEN =
|
101
|
+
# Pixbuf magic (0x47646b50)
|
102
|
+
"GdkP" <<
|
103
|
+
# length: header (24) + pixel_data (1024)
|
104
|
+
"\0\0\4\30" <<
|
105
|
+
# pixdata_type (0x1010002)
|
106
|
+
"\1\1\0\2" <<
|
107
|
+
# rowstride (64)
|
108
|
+
"\0\0\0@" <<
|
109
|
+
# width (16)
|
110
|
+
"\0\0\0\20" <<
|
111
|
+
# height (16)
|
112
|
+
"\0\0\0\20" <<
|
113
|
+
# pixel_data:
|
114
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\352aJ7\3607\262\5\353\5\371\0\347\0" <<
|
115
|
+
"\377\0\337\0\377\4\323\4\371.\310.\262L\267LJ\0\0\0\0\0\0\0\0\0\0\0\0" <<
|
116
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0j\336j\30""5\3665\270\0\370\0\377\0\360\0\377" <<
|
117
|
+
"\0\350\0\377\0\337\0\377\0\327\0\377\0\317\0\377\0\306\0\377\0\275\0" <<
|
118
|
+
"\377&\257%\270I\232I\30\0\0\0\0\0\0\0\0\0\0\0\0j\336j\30\34\370\34\335" <<
|
119
|
+
"\0\370\0\377U\365U\377\0\347\0\377\0\337\0\377\0\327\0\377\0\316\0\377" <<
|
120
|
+
"\0\306\0\377\0\275\0\377\0\265\0\377\0\255\0\377\22\241\22\335B\214B" <<
|
121
|
+
"\30\0\0\0\0\0\0\0\0""5\3665\270\0\370\0\377q\366q\377\377\377\377\377" <<
|
122
|
+
"q\355q\377\0\326\0\377\0\316\0\377\0\306\0\377\0\275\0\377\0\265\0\377" <<
|
123
|
+
"\0\255\0\377\0\244\0\377\0\234\0\377\37\217\37\270\0\0\0\0a\350`J\0\370" <<
|
124
|
+
"\0\377\0\360\0\377\343\374\343\377\377\377\377\377\306\366\306\377\0" <<
|
125
|
+
"\316\0\377\0\306\0\377\0\275\0\377\0\265\0\377\0\255\0\377\0\244\0\377" <<
|
126
|
+
"\0\234\0\377\0\223\0\377\0\213\0\3774|3J7\3577\262\0\360\0\3779\3549" <<
|
127
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\34\314\34\377\0" <<
|
128
|
+
"\275\0\377\34\275\34\3779\2769\377\0\244\0\377\0\233\0\377\0\223\0\377" <<
|
129
|
+
"\0\213\0\377\0\202\0\377\33w\33\262\5\352\5\371\0\347\0\377\252\364\252" <<
|
130
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377q\332q\377\0\265" <<
|
131
|
+
"\0\377\306\354\306\377\377\377\377\377U\274U\377U\267U\377U\261U\377" <<
|
132
|
+
"U\253U\377U\246U\377W\237W\373\0\347\0\377\34\342\34\377\377\377\377" <<
|
133
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\306\356\306\377" <<
|
134
|
+
"9\2769\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
135
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
136
|
+
"\0\336\0\377\216\354\216\377\377\377\377\377\377\377\377\377U\323U\377" <<
|
137
|
+
"\377\377\377\377\377\377\377\377\252\340\252\377\377\377\377\377\377" <<
|
138
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
139
|
+
"\377\377\377\377\377\377\377\377\377\377\40\325\40\372\343\371\343\377" <<
|
140
|
+
"\377\377\377\377\216\341\216\377\0\265\0\377\377\377\377\377\377\377" <<
|
141
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
142
|
+
"\377\252\322\252\377\0q\0\377\0i\0\377\0`\0\377\2U\2\371\204\335\204" <<
|
143
|
+
"\314\377\377\377\377\377\377\377\377\34\275\34\377\0\254\0\377\306\352" <<
|
144
|
+
"\306\377\377\377\377\377\377\377\377\377\377\377\377\377q\271q\377\252" <<
|
145
|
+
"\322\252\377\34\200\34\377\0i\0\377\0a\0\377\0X\0\377\22N\22\262\274" <<
|
146
|
+
"\343\274\206\377\377\377\377\306\356\306\377\0\254\0\377\0\243\0\377" <<
|
147
|
+
"U\274U\377\377\377\377\377\377\377\377\377\306\343\306\377\0y\0\377\0" <<
|
148
|
+
"q\0\377\0i\0\377\0`\0\377\0X\0\377\0O\0\377\35G\35J\377\377\377\34\305" <<
|
149
|
+
"\351\305\347\34\265\34\377\0\244\0\377\0\233\0\377\0\223\0\377\377\377" <<
|
150
|
+
"\377\377\377\377\377\377U\246U\377\0q\0\377\0i\0\377\0`\0\377\0X\0\377" <<
|
151
|
+
"\0O\0\377\16E\16\270\0\0\0\0\0\0\0\0F\223F\30\22\237\22\335\0\233\0\377" <<
|
152
|
+
"\0\223\0\377\0\212\0\377\216\307\216\377\343\360\343\377\0q\0\377\0h" <<
|
153
|
+
"\0\377\0`\0\377\0W\0\377\0P\0\377\10E\10\335\35>\35\30\0\0\0\0\0\0\0" <<
|
154
|
+
"\0\0\0\0\0\77\205\77\30\36\215\36\270\0\212\0\377\0\202\0\377\0y\0\377" <<
|
155
|
+
"\0q\0\377\0h\0\377\0`\0\377\0X\0\377\0O\0\377\16E\16\270\35=\35\30\0" <<
|
156
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""2x2J\33u\33\262\2l\2" <<
|
157
|
+
"\371\0g\0\377\0_\0\377\1T\1\371\21M\21\262\34F\35J\0\0\0\0\0\0\0\0\0" <<
|
158
|
+
"\0\0\0\0\0\0\0"
|
159
|
+
|
160
|
+
RED =
|
161
|
+
# Pixbuf magic (0x47646b50)
|
162
|
+
"GdkP" <<
|
163
|
+
# length: header (24) + pixel_data (1024)
|
164
|
+
"\0\0\4\30" <<
|
165
|
+
# pixdata_type (0x1010002)
|
166
|
+
"\1\1\0\2" <<
|
167
|
+
# rowstride (64)
|
168
|
+
"\0\0\0@" <<
|
169
|
+
# width (16)
|
170
|
+
"\0\0\0\20" <<
|
171
|
+
# height (16)
|
172
|
+
"\0\0\0\20" <<
|
173
|
+
# pixel_data:
|
174
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\351aaJ\36077\262\353\5\5\371\347\0\0" <<
|
175
|
+
"\377\337\0\0\377\322\4\4\371\310..\262\267LLJ\0\0\0\0\0\0\0\0\0\0\0\0" <<
|
176
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\336jj\30\36655\270\371\0\0\377\360\0\0\377\350" <<
|
177
|
+
"\0\0\377\337\0\0\377\327\0\0\377\316\0\0\377\306\0\0\377\275\0\0\377" <<
|
178
|
+
"\260%%\270\232II\30\0\0\0\0\0\0\0\0\0\0\0\0\336jj\30\371\34\34\335\370" <<
|
179
|
+
"\0\0\377\365UU\377\347\0\0\377\337\0\0\377\327\0\0\377\317\0\0\377\306" <<
|
180
|
+
"\0\0\377\275\0\0\377\265\0\0\377\255\0\0\377\241\22\22\335\213BB\30\0" <<
|
181
|
+
"\0\0\0\0\0\0\0\36655\270\370\0\0\377\366qq\377\377\377\377\377\355qq" <<
|
182
|
+
"\377\327\0\0\377\316\0\0\377\306\0\0\377\275\0\0\377\265\0\0\377\255" <<
|
183
|
+
"\0\0\377\244\0\0\377\234\0\0\377\217\37\37\270\0\0\0\0\351``J\370\0\0" <<
|
184
|
+
"\377\360\0\0\377\374\343\343\377\377\377\377\377\365\306\306\377\316" <<
|
185
|
+
"\0\0\377\306\0\0\377\275\0\0\377\265\0\0\377\255\0\0\377\244\0\0\377" <<
|
186
|
+
"\234\0\0\377\223\0\0\377\213\0\0\377}33J\35777\262\360\0\0\377\35499" <<
|
187
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\314\34\34\377\275" <<
|
188
|
+
"\0\0\377\275\34\34\377\27699\377\244\0\0\377\234\0\0\377\223\0\0\377" <<
|
189
|
+
"\213\0\0\377\202\0\0\377w\33\33\262\352\5\5\371\347\0\0\377\364\252\252" <<
|
190
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\332qq\377\265\0" <<
|
191
|
+
"\0\377\354\306\306\377\377\377\377\377\275UU\377\267UU\377\261UU\377" <<
|
192
|
+
"\254UU\377\246UU\377\237WW\373\347\0\0\377\342\34\34\377\377\377\377" <<
|
193
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\356\306\306\377" <<
|
194
|
+
"\27699\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
195
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
196
|
+
"\336\0\0\377\354\216\216\377\377\377\377\377\377\377\377\377\323UU\377" <<
|
197
|
+
"\377\377\377\377\377\377\377\377\340\252\252\377\377\377\377\377\377" <<
|
198
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
199
|
+
"\377\377\377\377\377\377\377\377\377\377\325\40\40\372\371\343\343\377" <<
|
200
|
+
"\377\377\377\377\341\216\216\377\265\0\0\377\377\377\377\377\377\377" <<
|
201
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
202
|
+
"\377\322\252\252\377q\0\0\377i\0\0\377`\0\0\377U\2\2\371\335\204\204" <<
|
203
|
+
"\314\377\377\377\377\377\377\377\377\275\34\34\377\254\0\0\377\352\306" <<
|
204
|
+
"\306\377\377\377\377\377\377\377\377\377\377\377\377\377\271qq\377\322" <<
|
205
|
+
"\252\252\377\200\34\34\377i\0\0\377`\0\0\377X\0\0\377N\22\22\262\343" <<
|
206
|
+
"\274\274\206\377\377\377\377\356\306\306\377\254\0\0\377\244\0\0\377" <<
|
207
|
+
"\274UU\377\377\377\377\377\377\377\377\377\343\306\306\377y\0\0\377q" <<
|
208
|
+
"\0\0\377i\0\0\377`\0\0\377X\0\0\377O\0\0\377G\35\35J\377\377\377\34\351" <<
|
209
|
+
"\305\305\347\265\34\34\377\243\0\0\377\233\0\0\377\223\0\0\377\377\377" <<
|
210
|
+
"\377\377\377\377\377\377\246UU\377q\0\0\377i\0\0\377`\0\0\377X\0\0\377" <<
|
211
|
+
"O\0\0\377E\16\16\270\0\0\0\0\0\0\0\0\224FF\30\237\22\22\335\233\0\0\377" <<
|
212
|
+
"\223\0\0\377\212\0\0\377\307\216\216\377\360\343\343\377q\0\0\377i\0" <<
|
213
|
+
"\0\377`\0\0\377X\0\0\377O\0\0\377E\10\10\335=\35\35\30\0\0\0\0\0\0\0" <<
|
214
|
+
"\0\0\0\0\0\204\77\77\30\214\36\36\270\212\0\0\377\201\0\0\377y\0\0\377" <<
|
215
|
+
"q\0\0\377h\0\0\377`\0\0\377X\0\0\377O\0\0\377E\16\16\270=\35\35\30\0" <<
|
216
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0y22Ju\33\33\262l\2\2\371" <<
|
217
|
+
"g\0\0\377^\0\0\377T\1\1\371M\21\21\262E\35\35J\0\0\0\0\0\0\0\0\0\0\0" <<
|
218
|
+
"\0\0\0\0\0"
|
219
|
+
|
220
|
+
YELLOW =
|
221
|
+
# Pixbuf magic (0x47646b50)
|
222
|
+
"GdkP" <<
|
223
|
+
# length: header (24) + pixel_data (1024)
|
224
|
+
"\0\0\4\30" <<
|
225
|
+
# pixdata_type (0x1010002)
|
226
|
+
"\1\1\0\2" <<
|
227
|
+
# rowstride (64)
|
228
|
+
"\0\0\0@" <<
|
229
|
+
# width (16)
|
230
|
+
"\0\0\0\20" <<
|
231
|
+
# height (16)
|
232
|
+
"\0\0\0\20" <<
|
233
|
+
# pixel_data:
|
234
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\351\352aJ\360\3607\262\353\353\5\371" <<
|
235
|
+
"\347\347\0\377\337\337\0\377\322\323\4\371\310\310.\262\267\267LJ\0\0" <<
|
236
|
+
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\336\336j\30\366\3665\270" <<
|
237
|
+
"\371\370\0\377\360\360\0\377\350\350\0\377\337\337\0\377\327\327\0\377" <<
|
238
|
+
"\316\317\0\377\306\306\0\377\275\275\0\377\260\257%\270\232\232I\30\0" <<
|
239
|
+
"\0\0\0\0\0\0\0\0\0\0\0\336\336j\30\371\370\34\335\370\370\0\377\365\365" <<
|
240
|
+
"U\377\347\347\0\377\337\337\0\377\327\327\0\377\317\316\0\377\306\306" <<
|
241
|
+
"\0\377\275\275\0\377\265\265\0\377\255\255\0\377\241\241\22\335\213\214" <<
|
242
|
+
"B\30\0\0\0\0\0\0\0\0\366\3665\270\370\370\0\377\366\366q\377\377\377" <<
|
243
|
+
"\377\377\355\355q\377\327\326\0\377\316\316\0\377\306\306\0\377\275\275" <<
|
244
|
+
"\0\377\265\265\0\377\255\255\0\377\244\244\0\377\234\234\0\377\217\217" <<
|
245
|
+
"\37\270\0\0\0\0\351\350`J\370\370\0\377\360\360\0\377\374\374\343\377" <<
|
246
|
+
"\377\377\377\377\365\366\306\377\316\316\0\377\306\306\0\377\275\275" <<
|
247
|
+
"\0\377\265\265\0\377\255\255\0\377\244\244\0\377\234\234\0\377\223\223" <<
|
248
|
+
"\0\377\213\213\0\377}|3J\357\3577\262\360\360\0\377\354\3549\377\377" <<
|
249
|
+
"\377\377\377\377\377\377\377\377\377\377\377\314\314\34\377\275\275\0" <<
|
250
|
+
"\377\275\275\34\377\276\2769\377\244\244\0\377\234\233\0\377\223\223" <<
|
251
|
+
"\0\377\213\213\0\377\202\202\0\377ww\33\262\352\352\5\371\347\347\0\377" <<
|
252
|
+
"\364\364\252\377\377\377\377\377\377\377\377\377\377\377\377\377\332" <<
|
253
|
+
"\332q\377\265\265\0\377\354\354\306\377\377\377\377\377\275\274U\377" <<
|
254
|
+
"\267\267U\377\261\261U\377\254\253U\377\246\246U\377\237\237W\373\347" <<
|
255
|
+
"\347\0\377\342\342\34\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
256
|
+
"\377\377\377\377\377\356\356\306\377\276\2769\377\377\377\377\377\377" <<
|
257
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
258
|
+
"\377\377\377\377\377\377\377\377\377\377\336\336\0\377\354\354\216\377" <<
|
259
|
+
"\377\377\377\377\377\377\377\377\323\323U\377\377\377\377\377\377\377" <<
|
260
|
+
"\377\377\340\340\252\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
261
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
262
|
+
"\377\377\377\377\325\325\40\372\371\371\343\377\377\377\377\377\341\341" <<
|
263
|
+
"\216\377\265\265\0\377\377\377\377\377\377\377\377\377\377\377\377\377" <<
|
264
|
+
"\377\377\377\377\377\377\377\377\377\377\377\377\322\322\252\377qq\0" <<
|
265
|
+
"\377ii\0\377``\0\377UU\2\371\335\335\204\314\377\377\377\377\377\377" <<
|
266
|
+
"\377\377\275\275\34\377\254\254\0\377\352\352\306\377\377\377\377\377" <<
|
267
|
+
"\377\377\377\377\377\377\377\377\271\271q\377\322\322\252\377\200\200" <<
|
268
|
+
"\34\377ii\0\377`a\0\377XX\0\377NN\22\262\343\343\274\206\377\377\377" <<
|
269
|
+
"\377\356\356\306\377\254\254\0\377\244\243\0\377\274\274U\377\377\377" <<
|
270
|
+
"\377\377\377\377\377\377\343\343\306\377yy\0\377qq\0\377ii\0\377``\0" <<
|
271
|
+
"\377XX\0\377OO\0\377GG\35J\377\377\377\34\351\351\305\347\265\265\34" <<
|
272
|
+
"\377\243\244\0\377\233\233\0\377\223\223\0\377\377\377\377\377\377\377" <<
|
273
|
+
"\377\377\246\246U\377qq\0\377ii\0\377``\0\377XX\0\377OO\0\377EE\16\270" <<
|
274
|
+
"\0\0\0\0\0\0\0\0\224\223F\30\237\237\22\335\233\233\0\377\223\223\0\377" <<
|
275
|
+
"\212\212\0\377\307\307\216\377\360\360\343\377qq\0\377ih\0\377``\0\377" <<
|
276
|
+
"XW\0\377OP\0\377EE\10\335=>\35\30\0\0\0\0\0\0\0\0\0\0\0\0\204\205\77" <<
|
277
|
+
"\30\214\215\36\270\212\212\0\377\201\202\0\377yy\0\377qq\0\377hh\0\377" <<
|
278
|
+
"``\0\377XX\0\377OO\0\377EE\16\270==\35\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0" <<
|
279
|
+
"\0\0\0\0\0\0\0\0\0\0yx2Juu\33\262ll\2\371gg\0\377^_\0\377TT\1\371MM\21" <<
|
280
|
+
"\262EF\35J\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
281
|
+
|
282
|
+
$grey_pixbuf = Gdk::Pixbuf.new(GREY.unpack("C*"), true)
|
283
|
+
$green_pixbuf = Gdk::Pixbuf.new(GREEN.unpack("C*"), true)
|
284
|
+
$red_pixbuf = Gdk::Pixbuf.new(RED.unpack("C*"), true)
|
285
|
+
$yellow_pixbuf = Gdk::Pixbuf.new(YELLOW.unpack("C*"), true)
|
286
|
+
|
287
|
+
# build the UI
|
288
|
+
|
289
|
+
$tray = Gtk::StatusIcon.new
|
290
|
+
$tray.pixbuf = $grey_pixbuf
|
291
|
+
|
292
|
+
$menu = Gtk::Menu.new
|
293
|
+
about_item = Gtk::ImageMenuItem.new(Gtk::Stock::ABOUT)
|
294
|
+
quit_item = Gtk::ImageMenuItem.new(Gtk::Stock::QUIT)
|
295
|
+
$menu.append(about_item)
|
296
|
+
$menu.append(Gtk::SeparatorMenuItem.new)
|
297
|
+
$menu.append(quit_item)
|
298
|
+
$menu.show_all
|
299
|
+
|
300
|
+
about_item.signal_connect('activate') {
|
301
|
+
about = Gtk::AboutDialog.new
|
302
|
+
about.signal_connect('response') {
|
303
|
+
about.destroy
|
304
|
+
}
|
305
|
+
about.name = 'CurrentCost Tray Monitor'
|
306
|
+
about.version = '0.1'
|
307
|
+
about.copyright = '© 2008 James Smith'
|
308
|
+
about.comments = 'Heavily based on CCTrayRb: http://rubyforge.org/projects/cctrayrb/'
|
309
|
+
about.license = 'MIT License - see http://github.com/Floppy/currentcost-ruby/tree/master/COPYING'
|
310
|
+
about.website = 'http://github.com/Floppy/currentcost-ruby/wikis/currentcosttraymonitor'
|
311
|
+
about.authors = ['James Smith - james@floppy.org.uk']
|
312
|
+
about.show_all
|
313
|
+
}
|
314
|
+
|
315
|
+
quit_item.signal_connect('activate') {
|
316
|
+
$meter.close
|
317
|
+
$eeml_server.shutdown if $eeml_server_enabled && $eeml_server.status == :Running
|
318
|
+
Gtk.main_quit
|
319
|
+
}
|
320
|
+
|
321
|
+
$tray.signal_connect('popup_menu') { |icon, button, time|
|
322
|
+
if button == 3 # right mouse button
|
323
|
+
$menu.popup(nil, nil, button, time)
|
324
|
+
end
|
325
|
+
}
|
326
|
+
|
327
|
+
# Meter observer
|
328
|
+
class MeterObserver
|
329
|
+
def update(reading)
|
330
|
+
# Add all channels to get real figure
|
331
|
+
watts = 0
|
332
|
+
reading.channels.each { |c| watts += c[:watts] }
|
333
|
+
# Change icon colour based on power usage
|
334
|
+
case watts
|
335
|
+
when 0..349
|
336
|
+
$tray.pixbuf = $green_pixbuf
|
337
|
+
when 350..999
|
338
|
+
$tray.pixbuf = $yellow_pixbuf
|
339
|
+
else
|
340
|
+
$tray.pixbuf = $red_pixbuf
|
341
|
+
end
|
342
|
+
# Set tooltip
|
343
|
+
$tray.tooltip = "#{watts} watts"
|
344
|
+
# Update EEML data
|
345
|
+
if $eeml_server_enabled && $eeml_server.status == :Running
|
346
|
+
$eeml_environment[0].value = watts
|
347
|
+
$eeml_environment.set_updated!
|
348
|
+
end
|
349
|
+
rescue
|
350
|
+
$tray.pixbuf = $grey_pixbuf
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
# Create CurrentCost meter connection
|
355
|
+
$meter = CurrentCost::Meter.new(options[:port])
|
356
|
+
obs = MeterObserver.new
|
357
|
+
$meter.add_observer(obs)
|
358
|
+
|
359
|
+
# Create EEML HTTP server if options are set
|
360
|
+
if $eeml_server_enabled && options[:http_port]
|
361
|
+
# Create EEML environment
|
362
|
+
$eeml_environment = EEML::Environment.new
|
363
|
+
# Create data object
|
364
|
+
data = EEML::Data.new(0)
|
365
|
+
data.unit = EEML::Unit.new("Watts", :symbol => 'W', :type => :derivedSI)
|
366
|
+
$eeml_environment << data
|
367
|
+
# Create WEBrick server
|
368
|
+
$eeml_server = WEBrick::HTTPServer.new( :Port => options[:http_port] )
|
369
|
+
# Create a simple webrick servlet for index.eeml
|
370
|
+
class EEMLServlet < WEBrick::HTTPServlet::AbstractServlet
|
371
|
+
def do_GET(request, response)
|
372
|
+
response.status = 200
|
373
|
+
response['Content-Type'] = "text/xml"
|
374
|
+
response.body = $eeml_environment.to_eeml
|
375
|
+
end
|
376
|
+
end
|
377
|
+
$eeml_server.mount("/index.eeml", EEMLServlet)
|
378
|
+
trap("INT") {$eeml_server.shutdown}
|
379
|
+
Thread.new{$eeml_server.start}
|
380
|
+
end
|
381
|
+
|
382
|
+
# Go
|
383
|
+
Gtk.main
|
data/examples/simple.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
dir = File.dirname(__FILE__) + '/../lib'
|
4
|
+
$LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'currentcost/meter'
|
8
|
+
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
# Command-line options
|
12
|
+
options = {:port => '/dev/ttyS0'}
|
13
|
+
OptionParser.new do |opts|
|
14
|
+
opts.on("-p", "--serial_port SERIAL_PORT", "serial port") do |p|
|
15
|
+
options[:port] = p
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
# A simple observer class which will receive updates from the meter
|
20
|
+
class SimpleObserver
|
21
|
+
def update(reading)
|
22
|
+
# Add all channels to get real figure
|
23
|
+
watts = 0
|
24
|
+
reading.channels.each { |c| watts += c[:watts] }
|
25
|
+
# Print out measurement
|
26
|
+
puts "New reading received: #{watts} W"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Create meter
|
31
|
+
meter = CurrentCost::Meter.new(options[:port], :cc128 => true)
|
32
|
+
# Create observer
|
33
|
+
observer = SimpleObserver.new
|
34
|
+
# Register observer with meter
|
35
|
+
meter.add_observer(observer)
|
36
|
+
# Wait a while, let some readings come in
|
37
|
+
sleep(30)
|
38
|
+
# Close the meter object to stop it receiving data
|
39
|
+
meter.close
|
data/lib/currentcost.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'rb232'
|
2
|
+
require 'rb232/text_protocol'
|
3
|
+
require 'currentcost/meter'
|
4
|
+
require 'currentcost/reading'
|
5
|
+
require 'observer'
|
6
|
+
|
7
|
+
module CurrentCost
|
8
|
+
|
9
|
+
# A class to represent a physical CurrentCost meter attached to a serial port.
|
10
|
+
# This class is Observable (see Ruby documentation for details). Client code
|
11
|
+
# should create an observer class which defines an update(CurrentCost::Reading)
|
12
|
+
# function, and call Meter.add_observer(my_observer) to receive updates when
|
13
|
+
# new readings are received from the physical meter.
|
14
|
+
#
|
15
|
+
# For example:
|
16
|
+
#
|
17
|
+
# require 'currentcost/meter'
|
18
|
+
#
|
19
|
+
# class SimpleObserver
|
20
|
+
# def update(reading)
|
21
|
+
# puts "New reading received: #{reading.channels[0][:watts]} W"
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# meter = CurrentCost::Meter.new(:cc128 => true)
|
26
|
+
# observer = SimpleObserver.new
|
27
|
+
# meter.add_observer(observer)
|
28
|
+
# sleep(30) # wait a while, let some readings come in
|
29
|
+
# meter.close
|
30
|
+
|
31
|
+
|
32
|
+
class Meter
|
33
|
+
|
34
|
+
include Observable
|
35
|
+
|
36
|
+
# Constructor. 'port' is the name of the serial port that the physical
|
37
|
+
# meter is connected to.
|
38
|
+
# Connection is to a classic meter by default. To connect to a new-stlye
|
39
|
+
# CC128, pass :cc128 => true at the end
|
40
|
+
# This function will automatically start processing serial data on the
|
41
|
+
# specified port. To stop this processing, call close.
|
42
|
+
def initialize(port = '/dev/ttyS0', options = {})
|
43
|
+
@port = RB232::Port.new(port, :baud_rate => (options[:cc128] == true ? 57600 : 9600), :data_bits => 8, :stop_bits => 1, :parity => false)
|
44
|
+
@protocol = RB232::TextProtocol.new(@port, "\n")
|
45
|
+
@protocol.add_observer(self)
|
46
|
+
@protocol.start
|
47
|
+
end
|
48
|
+
|
49
|
+
# Internal use only, client code does not need to use this function. Informs
|
50
|
+
# the Meter object that a new message has been received by the serial port.
|
51
|
+
def update(message)
|
52
|
+
unless message.nil?
|
53
|
+
# Parse reading from message
|
54
|
+
@latest_reading = Reading.from_xml(message)
|
55
|
+
# Inform observers
|
56
|
+
changed
|
57
|
+
notify_observers(@latest_reading)
|
58
|
+
end
|
59
|
+
rescue CurrentCost::ParseError
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get the last Reading received. If no reading has been received yet,
|
64
|
+
# returns nil. If you have registered an observer with add_observer(),
|
65
|
+
# you will most likely not need this function as the reading will be
|
66
|
+
# delivered automatically to your observer's update() function.
|
67
|
+
def latest_reading
|
68
|
+
@latest_reading
|
69
|
+
end
|
70
|
+
|
71
|
+
# Stops serial data processing. Call this once you're done with the Meter
|
72
|
+
# object.
|
73
|
+
def close
|
74
|
+
@protocol.stop
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'currentcost/exceptions'
|
2
|
+
require 'rexml/document'
|
3
|
+
|
4
|
+
module CurrentCost
|
5
|
+
|
6
|
+
class Reading
|
7
|
+
|
8
|
+
# Creates a reading object from an XML string.
|
9
|
+
# Raises CurrentCost::ParseError if the XML is malformed or missing
|
10
|
+
# expected content.
|
11
|
+
def self.from_xml(xml)
|
12
|
+
# Parse XML
|
13
|
+
doc = REXML::Document.new(xml)
|
14
|
+
# Create reading object
|
15
|
+
r = Reading.new
|
16
|
+
# Check version
|
17
|
+
r.software_version = REXML::XPath.first(doc, "/msg/src/sver").text rescue nil
|
18
|
+
if r.software_version.nil?
|
19
|
+
r.software_version = REXML::XPath.first(doc, "/msg/src").text
|
20
|
+
end
|
21
|
+
# Extract basic data
|
22
|
+
if r.software_version.include? "CC128"
|
23
|
+
r.days_since_birth = REXML::XPath.first(doc, "/msg/dsb").text.to_i
|
24
|
+
r.hour, r.minute, r.second = REXML::XPath.first(doc, "/msg/time").text.split(':').map{|x| x.to_i}
|
25
|
+
r.id = REXML::XPath.first(doc, "/msg/id").text rescue nil
|
26
|
+
r.type = REXML::XPath.first(doc, "/msg/type").text rescue nil
|
27
|
+
r.temperature = REXML::XPath.first(doc, "/msg/tmpr").text.to_f rescue nil
|
28
|
+
r.sensor = REXML::XPath.first(doc, "/msg/sensor").text rescue nil
|
29
|
+
# Extract history data
|
30
|
+
if REXML::XPath.first(doc, "/msg/hist")
|
31
|
+
r.history = {}
|
32
|
+
REXML::XPath.each(doc, "/msg/hist/data") do |sensor|
|
33
|
+
sensor_num = sensor.elements['sensor'].text.to_i
|
34
|
+
sensor.elements.each do |item|
|
35
|
+
match = item.name.match "([hdm])([0-9][0-9][0-9])"
|
36
|
+
if match
|
37
|
+
case match[1]
|
38
|
+
when 'h'
|
39
|
+
type = :hours
|
40
|
+
when 'd'
|
41
|
+
type = :days
|
42
|
+
when 'm'
|
43
|
+
type = :months
|
44
|
+
end
|
45
|
+
r.history[type] ||= []
|
46
|
+
r.history[type][match[2].to_i] ||= []
|
47
|
+
r.history[type][match[2].to_i][sensor_num] = item.text.to_f
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
else
|
53
|
+
r.days_since_birth = REXML::XPath.first(doc, "/msg/date/dsb").text.to_i
|
54
|
+
r.hour = REXML::XPath.first(doc, "/msg/date/hr").text.to_i
|
55
|
+
r.minute = REXML::XPath.first(doc, "/msg/date/min").text.to_i
|
56
|
+
r.second = REXML::XPath.first(doc, "/msg/date/sec").text.to_i
|
57
|
+
r.name = REXML::XPath.first(doc, "/msg/src/name").text
|
58
|
+
r.id = REXML::XPath.first(doc, "/msg/src/id").text
|
59
|
+
r.type = REXML::XPath.first(doc, "/msg/src/type").text
|
60
|
+
r.temperature = REXML::XPath.first(doc, "/msg/tmpr").text.to_f
|
61
|
+
# Extract history data
|
62
|
+
if REXML::XPath.first(doc, "/msg/hist")
|
63
|
+
r.history = {}
|
64
|
+
r.history[:hours] = []
|
65
|
+
REXML::XPath.each(doc, "/msg/hist/hrs/*") do |node|
|
66
|
+
r.history[:hours][node.name.slice(1,2).to_i] = [node.text.to_f]
|
67
|
+
end
|
68
|
+
r.history[:days] = []
|
69
|
+
REXML::XPath.each(doc, "/msg/hist/days/*") do |node|
|
70
|
+
r.history[:days][node.name.slice(1,2).to_i] = [node.text.to_i]
|
71
|
+
end
|
72
|
+
r.history[:months] = []
|
73
|
+
REXML::XPath.each(doc, "/msg/hist/mths/*") do |node|
|
74
|
+
r.history[:months][node.name.slice(1,2).to_i] = [node.text.to_i]
|
75
|
+
end
|
76
|
+
r.history[:years] = []
|
77
|
+
REXML::XPath.each(doc, "/msg/hist/yrs/*") do |node|
|
78
|
+
r.history[:years][node.name.slice(1,2).to_i] = [node.text.to_i]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# Common information
|
83
|
+
r.channels = []
|
84
|
+
REXML::XPath.each(doc, "/msg/*/watts") do |node|
|
85
|
+
r.channels << { :watts => node.text.to_i }
|
86
|
+
end
|
87
|
+
# Done
|
88
|
+
return r
|
89
|
+
rescue
|
90
|
+
raise CurrentCost::ParseError.new("Couldn't parse XML data.")
|
91
|
+
end
|
92
|
+
|
93
|
+
# Number of days since the meter was turned on
|
94
|
+
attr_accessor :days_since_birth
|
95
|
+
# Current time - hour
|
96
|
+
attr_accessor :hour
|
97
|
+
# Current time - minute
|
98
|
+
attr_accessor :minute
|
99
|
+
# Current time - second
|
100
|
+
attr_accessor :second
|
101
|
+
# Name of the device - always "CC02".
|
102
|
+
attr_accessor :name
|
103
|
+
# ID number of the device
|
104
|
+
attr_accessor :id
|
105
|
+
# Type id of the device - "1" for a standard CurrentCost meter.
|
106
|
+
attr_accessor :type
|
107
|
+
# Version of the meter software
|
108
|
+
attr_accessor :software_version
|
109
|
+
# An array of channels. channels[x][:watts] contains the current power for that channel in watts. The figure shown on the meter is the sum of the wattage for all channels.
|
110
|
+
attr_accessor :channels
|
111
|
+
# Current temperature
|
112
|
+
attr_accessor :temperature
|
113
|
+
# Sensor number
|
114
|
+
attr_accessor :sensor
|
115
|
+
# Historical data, represented as a hash. There is a hash entry for days, weeks, months, and years. Each of these is an array of sensors, each of which contains an array of historical kWh data.
|
116
|
+
attr_accessor :history
|
117
|
+
|
118
|
+
# The sum of the current wattage for all channels, as shown on the meter
|
119
|
+
def total_watts
|
120
|
+
watts = 0
|
121
|
+
channels.each { |c| watts += c[:watts] }
|
122
|
+
return watts
|
123
|
+
rescue
|
124
|
+
0
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: currentcost
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Smith
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-15 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rb232
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.2.4
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: james@floppy.org.uk
|
27
|
+
executables:
|
28
|
+
- currentcost_tray_monitor.rb
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README
|
35
|
+
- COPYING
|
36
|
+
- lib/currentcost.rb
|
37
|
+
- lib/currentcost/meter.rb
|
38
|
+
- lib/currentcost/reading.rb
|
39
|
+
- lib/currentcost/version.rb
|
40
|
+
- lib/currentcost/exceptions.rb
|
41
|
+
- examples/simple.rb
|
42
|
+
- bin/currentcost_tray_monitor.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/Floppy/currentcost-ruby
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.5
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Ruby interface to the CurrentCost energy meter
|
71
|
+
test_files: []
|
72
|
+
|