green_eye_monitor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b004aae8d62d2f57551d0d4c1992c5e0f29fc9b1
4
+ data.tar.gz: a35b37d7b5ecd8b6b8399041d6d899743c905532
5
+ SHA512:
6
+ metadata.gz: d0b1086f78f255704bbb7595380d838986af7ec8214e0787783232cee6f83c1d7509398aab9776043adcb12822248545c763b13c836212b863fffee1a5d6592f
7
+ data.tar.gz: 45e9014c1ee81fdccca23b0706a7250034c1685513393890d13f782672d3d47a54cd435eb52c745ef2505aed5f1e6025f6481188a3aa4b1796a4b24e7b8128ae
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ /.bundle/
2
+ /Gemfile.lock
3
+ /coverage/
4
+ /pkg/
5
+ /spec/reports/
6
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,36 @@
1
+ require: rubocop-rspec
2
+
3
+ HashSyntax:
4
+ EnforcedStyle: hash_rockets
5
+
6
+ Style/Documentation:
7
+ Enabled: false
8
+
9
+ Style/Lambda:
10
+ Enabled: false
11
+
12
+ Style/TrailingCommaInLiteral:
13
+ Enabled: false
14
+
15
+ Metrics/LineLength:
16
+ Max: 120
17
+
18
+ # TODO: Cleanup
19
+ Metrics/ModuleLength:
20
+ Max: 200
21
+
22
+ # TODO: Cleanup
23
+ Metrics/ClassLength:
24
+ Max: 200
25
+
26
+ Metrics/MethodLength:
27
+ Max: 15
28
+
29
+ Style/ModuleFunction:
30
+ Enabled: false
31
+
32
+ Metrics/AbcSize:
33
+ Max: 20
34
+
35
+ AlignHash:
36
+ EnforcedHashRocketStyle: table
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ # 0.0.1 (20160412)
4
+
5
+ * Initial Release (@johnf)
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behaviour by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 John Ferlito
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # green_eye_monitor
2
+
3
+ [![Circle CI](https://circleci.com/gh/johnf/green_eye_monitor.svg?style=svg)](https://circleci.com/gh/johnf/green_eye_monitor)
4
+ [![Coverage Status](https://coveralls.io/repos/johnf/green_eye_monitor/badge.svg?branch=master&service=github)](https://coveralls.io/github/johnf/green_eye_monitor?branch=master)
5
+
6
+ Ruby library for communicating with Brultech GEM energy consumption monitor over a serial port
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'green_eye_monitor'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install green_eye_monitor
23
+
24
+ ## Usage
25
+
26
+ Do get a one off run output from your inverter run
27
+
28
+ $ green_eye_monitor
29
+
30
+ It also has some sample code on how to use the API
31
+
32
+ ## Development
33
+
34
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
35
+
36
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
37
+
38
+ ## Contributing
39
+
40
+ Bug reports and pull requests are welcome on GitHub at https://github.com/johnf/green_eye_monitor. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
41
+
42
+
43
+ ## License
44
+
45
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task :default => :spec
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+
3
+ set -euo pipefail
4
+ IFS=$'\n\t'
5
+
6
+ bundle install
data/circle.yml ADDED
@@ -0,0 +1,6 @@
1
+ test:
2
+ post:
3
+ - bundle exec rubocop
4
+ machine:
5
+ ruby:
6
+ version: 2.3.0
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib')
4
+
5
+ require 'green_eye_monitor/client'
6
+
7
+ require 'slop'
8
+ require 'awesome_print'
9
+
10
+ opts = Slop.parse do |o|
11
+ o.bool '-d', '--debug', 'enable debug mode'
12
+ o.on '--version', 'print the version' do
13
+ puts Slop::VERSION
14
+ exit
15
+ end
16
+ end
17
+
18
+ client = GreenEyeMonitor::Client.new(:baud => 115_200, :debug => opts[:debug])
19
+
20
+ # client.packet_format = :bin48_net_time
21
+ # client.enable_realtime
22
+
23
+ # exit
24
+
25
+ puts '# Direct'
26
+ puts "Serial: #{client.serial}"
27
+ puts "Hertz: #{client.hertz}"
28
+ puts "Temp: #{client.temperature(1)}"
29
+ # puts "Recent: #{client.recent_values}"
30
+ puts
31
+
32
+ puts '# List Format'
33
+ client.packet_format = :list
34
+ puts client.send_one_packet
35
+
36
+ puts
37
+ puts
38
+
39
+ puts '# Bin32 Net Format'
40
+ client.packet_format = :bin32_net
41
+ data = client.send_one_packet
42
+
43
+ # ap data.snapshot
44
+ puts "Serial: #{data.serial_number}"
45
+ puts "Voltage: #{data.voltage}"
46
+ puts
47
+ puts "ABS Watt Seconds #{data.abs_watt_seconds[0, 5]}"
48
+ puts "Polarised Watt Seconds #{data.polarised_watt_seconds[0, 5]}"
49
+ puts "Current: #{data.current[0, 5]}"
50
+
51
+ puts "Seconds: #{data.seconds}"
52
+ puts "Pulse: #{data.pulse}"
53
+ puts "Temperature: #{data.temperature}"
54
+
55
+ # client.shell
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'green_eye_monitor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'green_eye_monitor'
8
+ spec.version = GreenEyeMonitor::VERSION
9
+ spec.authors = ['John Ferlito']
10
+ spec.email = ['johnf@inodes.org']
11
+
12
+ spec.summary = 'Library to speak to Brultech GEM energy consumption monitor over a serial port'
13
+ spec.homepage = 'https://github.com/johnf/green_eye_monitor'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = 'exe'
18
+ spec.require_paths = ['lib']
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+
21
+ spec.add_dependency 'serialport'
22
+ spec.add_dependency 'bindata'
23
+ spec.add_dependency 'slop'
24
+ spec.add_dependency 'awesome_print'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.10'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec'
29
+ spec.add_development_dependency 'rubocop'
30
+ spec.add_development_dependency 'rubocop-rspec'
31
+ spec.add_development_dependency 'rspec_junit_formatter'
32
+ spec.add_development_dependency 'coveralls'
33
+ end
@@ -0,0 +1,4 @@
1
+ require 'green_eye_monitor/version'
2
+
3
+ module GreenEyeMonitor
4
+ end
@@ -0,0 +1,272 @@
1
+ require 'green_eye_monitor/errors'
2
+ require 'green_eye_monitor/packet'
3
+
4
+ require 'serialport'
5
+
6
+ module GreenEyeMonitor
7
+ class Client
8
+ PACKET_FORMATS = {
9
+ :list => 0,
10
+ :multi => 1,
11
+ :ascii => 2,
12
+ :http => 3,
13
+ :bin48_net_time => 4,
14
+ :bin48_net => 5,
15
+ :old_seg => 6,
16
+ :bin48_abs => 7,
17
+ :bin32_net => 8,
18
+ :bin32_abs => 9,
19
+ # 10
20
+ :universal => 11,
21
+ # 12
22
+ :cosm => 12,
23
+ :seg => 13,
24
+ }.freeze
25
+ PACKET_FORMATS_REV = PACKET_FORMATS.invert
26
+
27
+ IMPLEMENTED_FORMATS = %i(list bin48_net_time bin48_net bin48_abs bin32_net bin32_abs).freeze
28
+
29
+ BAUD_RATES = {
30
+ 19_200 => 0,
31
+ 115_200 => 1,
32
+ }.freeze
33
+
34
+ LONG_CRLF = /\r\n\r\n$/
35
+ CRLF = /\r\n$/
36
+
37
+ def initialize(options = {})
38
+ serial_port = options[:serial_port] || '/dev/ttyUSB0'
39
+ baud = options[:baud] || 115_200
40
+ @debug = options[:debug] || false
41
+
42
+ @serial = SerialPort.new(serial_port, 'baud' => baud)
43
+
44
+ @serial.read_timeout = 100
45
+
46
+ # We disable all the push so we can operate in pull mode
47
+ write('SYSOFF')
48
+ write('SYSKAI0')
49
+
50
+ # Wait for any last writes
51
+ sleep(0.1)
52
+
53
+ # Flush everything
54
+ @serial.flush_output
55
+ @serial.flush_input
56
+ end
57
+
58
+ def shell
59
+ old_command = ''
60
+
61
+ loop do
62
+ print 'Command: '
63
+ command = STDIN.readline
64
+ command.strip!
65
+ command = old_command if command.empty?
66
+ write(command)
67
+ puts read
68
+ old_command = command
69
+ end
70
+ end
71
+
72
+ def disable_realtime
73
+ write('SYSOFF')
74
+ read(:expect => /^OFF$/)
75
+ end
76
+
77
+ def enable_realtime
78
+ write('SYS_ON')
79
+ read(:expect => /^_ON$/)
80
+ end
81
+
82
+ def disable_keepalive
83
+ write('SYSKAI0')
84
+ read(:expect => /OK$/)
85
+ end
86
+
87
+ def enable_keepalive(seconds)
88
+ # 2**x == seconds we aproximate to closest
89
+
90
+ x = Math.log2(seconds).round
91
+ x = 7 if x > 7
92
+ x = 1 if x == 0
93
+
94
+ write("SYSKAI#{x}")
95
+ read(:expect => /^OK$/)
96
+ end
97
+
98
+ def packet_format
99
+ write('RQSRTF')
100
+ format = read(:expect => /^\d\d\r\n$/)
101
+
102
+ PACKET_FORMATS_REV[format.to_i]
103
+ end
104
+
105
+ def packet_format=(packet_format)
106
+ int_format = PACKET_FORMATS[packet_format] || raise(Errors::Argument, 'Unknown packet format')
107
+
108
+ write(format('SYSPKT%02d', int_format))
109
+ read(:expect => /^PKT\r\n$/)
110
+ end
111
+
112
+ def secondary_packet_format=(packet_format)
113
+ int_format = PACKET_FORMATS[packet_format] || raise(Errors::Argument, 'Unknown packet format')
114
+
115
+ write(format('SYSPKF%02d', int_format))
116
+ read(:expect => 'PKT')
117
+ end
118
+
119
+ def disable_secondary_packet_format
120
+ write('SYSPKF00')
121
+ read(:expect => 'PKT')
122
+ end
123
+
124
+ def packet_send_interval=(seconds)
125
+ raise(Errors::Argument, 'Invalid interval: must be between 1 and 256') unless seconds > 0 && seconds <= 256
126
+
127
+ write(format('SYSIVL%03d', seconds))
128
+ read(:expect => 'IVL')
129
+ end
130
+
131
+ def packet_chunk_size=(size)
132
+ raise(Errors::Argument, 'Invalid chunk size: must be between 80 and 65,000') unless size >= 80 && size <= 65_000
133
+
134
+ write("SYSPKS#{size}\n")
135
+ read(:expect => 'PKS')
136
+ end
137
+
138
+ def packet_chunk_interval=(secs)
139
+ raise(Errors::Argument, 'Invalid interval: must be between 16 and 65,000') unless secs >= 16 && secs <= 65_000
140
+
141
+ write("SYSPKI#{seconds}\n")
142
+ read(:expect => 'PKI')
143
+ end
144
+
145
+ def max_buffer_size=(size)
146
+ raise(Errors::Argument, 'Invalid buffer size: must be between 10 and 1,700') unless size >= 10 && size <= 1_700
147
+
148
+ write("SYSBFF#{size}\n")
149
+ read(:expect => 'BFF')
150
+ end
151
+
152
+ def com1_baud_rate=(rate)
153
+ int_rate = BAUD_RATES[rate] || raise(Errors::Argument, 'Unknown baud rate')
154
+
155
+ write("SYSBD1#{int_rate}")
156
+ read(:expect => 'OK')
157
+ end
158
+
159
+ def com2_baud_rate=(rate)
160
+ raise(Errors::Argument, 'COM2 can only operate at 19,200') if rate != 19_200
161
+
162
+ write('SYSBD20')
163
+ read(:expect => 'OK')
164
+ end
165
+
166
+ def hertz
167
+ write('RQSHZ')
168
+ read(:expect => /^[56]0Hz\r\n\r\n$/)
169
+ end
170
+
171
+ def serial
172
+ write('RQSSRN')
173
+ read(:expect => /^\d+\r\n$/)
174
+ end
175
+
176
+ def temperature(channel)
177
+ raise(Errors::Argument, 'Invalid temperature channel') unless channel >= 1 && channel <= 8
178
+
179
+ write("APITP#{channel}")
180
+ read(:expect => /\d\d\.\d$/)
181
+ end
182
+
183
+ def enable_temperature_channel(channel)
184
+ raise(Errors::Argument, 'Invalid temperature channel') unless channel >= 1 && channel <= 8
185
+
186
+ write("TMPEN#{channel}")
187
+ read('MOO')
188
+ end
189
+
190
+ def recent_values
191
+ write('APIVAL')
192
+ read(:expect => /VAL.*END\r\n$/)
193
+ end
194
+
195
+ # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
196
+ def send_one_packet
197
+ pf = packet_format
198
+ raise(Errors::NotImplemented, "Unimplemented packet format: #{pf}") unless IMPLEMENTED_FORMATS.include?(pf)
199
+
200
+ write('APISPK')
201
+
202
+ case pf
203
+ when :list
204
+ read(:expect => /^.*<EOP>$/, :wait => true)
205
+ when :bin48_net_time
206
+ packet = read(:length => 625, :wait => true)
207
+ Packet::Bin48NetTime.read(StringIO.new(packet))
208
+ when :bin48_net
209
+ packet = read(:length => 619, :wait => true)
210
+ Packet::Bin48Net.read(StringIO.new(packet))
211
+ when :bin48_abs
212
+ packet = read(:length => 379, :wait => true)
213
+ Packet::Bin48Abs.read(StringIO.new(packet))
214
+ when :bin32_net
215
+ packet = read(:length => 429, :wait => true)
216
+ Packet::Bin32Net.read(StringIO.new(packet))
217
+ when :bin32_abs
218
+ packet = read(:length => 269, :wait => true)
219
+ Packet::Bin32Abs.read(StringIO.new(packet))
220
+ end
221
+ end
222
+ # rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
223
+
224
+ private
225
+
226
+ def write(cmd)
227
+ puts "---> #{cmd}" if @debug
228
+ @serial.syswrite("^^^#{cmd}")
229
+ end
230
+
231
+ def read_expect(expect)
232
+ data = ''
233
+
234
+ loop do
235
+ byte = @serial.getbyte
236
+ puts "DEBUG: byte=#{byte ? byte.chr : byte}" if @debug
237
+
238
+ raise(Errors::TooShort, "Data too short #{data.inspect}") if byte.nil?
239
+
240
+ data << byte.chr
241
+
242
+ break if data =~ expect
243
+ end
244
+
245
+ data
246
+ end
247
+
248
+ def read(options = {})
249
+ wait if options[:wait]
250
+
251
+ # TODO: Make :expect an arg if w never need anything else
252
+ if options[:expect]
253
+ data = read_expect(options[:expect])
254
+ elsif options[:length]
255
+ data = @serial.read(options[:length])
256
+ raise(Errors::TooShort, "Data too short #{data.inspect}") if data.size != options[:length]
257
+ else
258
+ raise('Unsupported options')
259
+ end
260
+
261
+ puts "<--- #{data.inspect}" if @debug
262
+ data.strip!
263
+
264
+ data
265
+ end
266
+
267
+ def wait
268
+ byte = @serial.getbyte while byte.nil?
269
+ @serial.ungetbyte(byte)
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,8 @@
1
+ module GreenEyeMonitor
2
+ module Errors
3
+ class Argument < StandardError; end
4
+ class BadData < StandardError; end
5
+ class TooShort < StandardError; end
6
+ class NotImplemented < StandardError; end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ require 'green_eye_monitor/packet/bin32_abs'
2
+ require 'green_eye_monitor/packet/bin32_net'
3
+ require 'green_eye_monitor/packet/bin48_abs'
4
+ require 'green_eye_monitor/packet/bin48_net'
5
+ require 'green_eye_monitor/packet/bin48_net_time'
@@ -0,0 +1,12 @@
1
+ require 'green_eye_monitor/packet/bin_net_base'
2
+
3
+ module GreenEyeMonitor
4
+ module Packet
5
+ class Bin32Abs < BinNetBase
6
+ default_parameter :version => 0x08
7
+ default_parameter :num_channels => 32
8
+ default_parameter :polarised => false
9
+ default_parameter :has_time => false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'green_eye_monitor/packet/bin_net_base'
2
+
3
+ module GreenEyeMonitor
4
+ module Packet
5
+ class Bin32Net < BinNetBase
6
+ default_parameter :version => 0x07
7
+ default_parameter :num_channels => 32
8
+ default_parameter :polarised => true
9
+ default_parameter :has_time => false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'green_eye_monitor/packet/bin_net_base'
2
+
3
+ module GreenEyeMonitor
4
+ module Packet
5
+ class Bin48Abs < BinNetBase
6
+ default_parameter :version => 0x05
7
+ default_parameter :num_channels => 48
8
+ default_parameter :polarised => false
9
+ default_parameter :has_time => false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'green_eye_monitor/packet/bin_net_base'
2
+
3
+ module GreenEyeMonitor
4
+ module Packet
5
+ class Bin48Net < BinNetBase
6
+ default_parameter :version => 0x05
7
+ default_parameter :num_channels => 48
8
+ default_parameter :polarised => true
9
+ default_parameter :has_time => false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'green_eye_monitor/packet/bin_net_base'
2
+
3
+ module GreenEyeMonitor
4
+ module Packet
5
+ class Bin48NetTime < BinNetBase
6
+ default_parameter :version => 0x05
7
+ default_parameter :num_channels => 48
8
+ default_parameter :polarised => true
9
+ default_parameter :has_time => true
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,65 @@
1
+ require 'bindata'
2
+
3
+ module GreenEyeMonitor
4
+ module Packet
5
+ class BinNetBase < BinData::Record
6
+ uint8 :header_a, :asserted_value => 0xFE
7
+ uint8 :header_b, :asserted_value => 0xFF
8
+ uint8 :header_c, :asserted_value => :version
9
+
10
+ uint16be :raw_voltage
11
+
12
+ array :abs_watt_seconds, :type => :uint40le, :initial_length => :num_channels
13
+ array :polarised_watt_seconds, :type => :uint40le, :initial_length => :num_channels, :onlyif => :polarised
14
+
15
+ uint16be :serial
16
+ skip :length => 1
17
+ uint8 :device_id
18
+
19
+ array :raw_current, :type => :uint16le, :initial_length => :num_channels
20
+
21
+ uint24le :seconds
22
+
23
+ array :pulse, :type => :uint24le, :initial_length => 4
24
+ array :raw_temperature, :type => :uint16le, :initial_length => 8
25
+ skip :length => 2, :onlyif => lambda { num_channels == 32 }
26
+
27
+ struct :time, :onlyif => :has_time do
28
+ uint8 :year
29
+ uint8 :month
30
+ uint8 :day
31
+ uint8 :hour
32
+ uint8 :minute
33
+ uint8 :second
34
+ end
35
+
36
+ uint8 :footer_a, :asserted_value => 0xFF
37
+ uint8 :footer_b, :asserted_value => 0xFE
38
+
39
+ uint8 :checksum, :assert => lambda { calc_checksum(value) }
40
+
41
+ def calc_checksum(checksum)
42
+ calculated_checksum = (to_binary_s.bytes.inject(0, :+) - checksum) & 0xFF
43
+
44
+ # TODO: why are we off by one?
45
+ checksum == calculated_checksum + 1
46
+ end
47
+
48
+ def voltage
49
+ raw_voltage / 10.0
50
+ end
51
+
52
+ def current
53
+ raw_current.map { |v| v / 50.0 }
54
+ end
55
+
56
+ def temperature
57
+ raw_temperature.map { |v| v / 2.0 }
58
+ end
59
+
60
+ def serial_number
61
+ format('%03d%05d', device_id, serial)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module GreenEyeMonitor
2
+ VERSION = '0.0.1'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,224 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: green_eye_monitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - John Ferlito
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-04-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: serialport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bindata
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: slop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: awesome_print
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.10'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec_junit_formatter
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: coveralls
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description:
168
+ email:
169
+ - johnf@inodes.org
170
+ executables:
171
+ - green_eye_monitor
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - ".gitignore"
176
+ - ".rspec"
177
+ - ".rubocop.yml"
178
+ - CHANGELOG.md
179
+ - CODE_OF_CONDUCT.md
180
+ - Gemfile
181
+ - LICENSE.txt
182
+ - README.md
183
+ - Rakefile
184
+ - bin/setup
185
+ - circle.yml
186
+ - exe/green_eye_monitor
187
+ - green_eye_monitor.gemspec
188
+ - lib/green_eye_monitor.rb
189
+ - lib/green_eye_monitor/client.rb
190
+ - lib/green_eye_monitor/errors.rb
191
+ - lib/green_eye_monitor/packet.rb
192
+ - lib/green_eye_monitor/packet/bin32_abs.rb
193
+ - lib/green_eye_monitor/packet/bin32_net.rb
194
+ - lib/green_eye_monitor/packet/bin48_abs.rb
195
+ - lib/green_eye_monitor/packet/bin48_net.rb
196
+ - lib/green_eye_monitor/packet/bin48_net_time.rb
197
+ - lib/green_eye_monitor/packet/bin_net_base.rb
198
+ - lib/green_eye_monitor/version.rb
199
+ homepage: https://github.com/johnf/green_eye_monitor
200
+ licenses:
201
+ - MIT
202
+ metadata: {}
203
+ post_install_message:
204
+ rdoc_options: []
205
+ require_paths:
206
+ - lib
207
+ required_ruby_version: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - ">="
210
+ - !ruby/object:Gem::Version
211
+ version: '0'
212
+ required_rubygems_version: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ version: '0'
217
+ requirements: []
218
+ rubyforge_project:
219
+ rubygems_version: 2.4.5.1
220
+ signing_key:
221
+ specification_version: 4
222
+ summary: Library to speak to Brultech GEM energy consumption monitor over a serial
223
+ port
224
+ test_files: []