ekm-omnimeter 0.2.3 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 81c9725bd9f827fc67d3b86adf622ba2cbd130a3
4
- data.tar.gz: 07f927b1852af3a02f5c5df84fcc78aa2fb791e6
3
+ metadata.gz: 8683533fedec1693dfa676899772275fe0ae881a
4
+ data.tar.gz: 0e2a8333af1cdedd8e41a4e8f5313f49124cd104
5
5
  SHA512:
6
- metadata.gz: cf5880321ac3ba5961df65c25ef49ad9339224de1a451ee34712e3e2cc55e00ede182a70253b183075da0199a1b903140066abf29b8f000beb0f15d3822a584d
7
- data.tar.gz: abd636ab283d8680a7256b3523f033be1370d70fd6d3f45c420bfaad0235335ee07c47de80cd4797bd67b97f80c4729d2fca8be3688ed623dd0be37b3eb638db
6
+ metadata.gz: 732818ce1410339b035a8c070bc8aab692aec256b29c9ecb7d0f4f46e92b6689097a26147706585767d5e0d72296f52db39cb736ce412a0ac3f6cdcb313b3843
7
+ data.tar.gz: ff897d4aa8a55847833cb7c6775f0947347ca0e48b30e04580139174fd570d95c638f66fe8088667bed2d6d2402c5d830cc86a9ab22407c60c267dd9c20dc8de
@@ -1,26 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ekm-omnimeter (0.2.2)
4
+ ekm-omnimeter (0.2.4)
5
5
  log4r (~> 1.1)
6
- xively-rb-connector (~> 0.1)
7
6
 
8
7
  GEM
9
8
  remote: https://rubygems.org/
10
9
  specs:
11
- bigdecimal (1.2.5)
12
10
  diff-lcs (1.2.5)
13
- httparty (0.13.0)
14
- json (~> 1.8)
15
- multi_xml (>= 0.5.2)
16
- json (1.8.1)
17
11
  log4r (1.1.10)
18
- mini_portile (0.5.3)
19
- multi_json (1.9.2)
20
- multi_xml (0.5.5)
21
- nokogiri (1.6.1)
22
- mini_portile (~> 0.5.0)
23
- ox (2.1.1)
24
12
  rake (10.2.2)
25
13
  rspec (2.14.1)
26
14
  rspec-core (~> 2.14.0)
@@ -30,18 +18,6 @@ GEM
30
18
  rspec-expectations (2.14.5)
31
19
  diff-lcs (>= 1.1.3, < 2.0)
32
20
  rspec-mocks (2.14.6)
33
- xively-rb (0.2.10)
34
- httparty (>= 0.10.0)
35
- multi_json (>= 1.3.6)
36
- multi_xml (>= 0.5.2)
37
- nokogiri (>= 1.5.6)
38
- ox (>= 1.5.9)
39
- yajl-ruby (>= 1.1.0)
40
- xively-rb-connector (0.1.3)
41
- bigdecimal (~> 1.2)
42
- log4r (~> 1.1)
43
- xively-rb (~> 0.2)
44
- yajl-ruby (1.2.0)
45
21
 
46
22
  PLATFORMS
47
23
  ruby
data/README.md CHANGED
@@ -49,16 +49,16 @@ m = EkmOmnimeter::Meter.new(
49
49
  :remote_port => 50000) # The port on which your iSerial device is listening
50
50
 
51
51
  # These values change based on the value of :power_configuration in the constructor
52
+ m.meter_number # 000300000234
53
+ m.remote_address # 192.168.0.125
54
+ m.remote_port # 50000
52
55
  m.volts # 248.7
53
56
  m.amps # 21.6
54
57
  m.watts # 2664
55
58
 
56
- # Warning: Dates seem off
57
- # My computer clock said 2014-04-03 3:32PM when these outputs came out
58
- m.meter_timestamp # 2014-04-03 05:15:32
59
- m.computer_timestamp # Time.now() = 2014-04-03 15:32:10 -0400
60
-
61
59
  # Read meter values
60
+ m.meter_timestamp # 2014-04-04 12:48:06
61
+ m.last_read_timestamp # 2014-04-04 12:48:17 -0400
62
62
  m.remote_address # 192.168.1.125
63
63
  m.remote_port # 50000
64
64
  m.meter_number # 000300000001
@@ -85,9 +85,9 @@ m.watts_l1 # 2276
85
85
  m.watts_l2 # 384
86
86
  m.watts_l3 # 0
87
87
  m.watts_total # 2664
88
- m.power_factor_1 # 1.0
89
- m.power_factor_2 # 0.0
90
- m.power_factor_3 # 0.0
88
+ m.power_factor_1 # 1.0
89
+ m.power_factor_2 # C0.99
90
+ m.power_factor_3 # C0.0
91
91
  m.maximum_demand # 22640.0
92
92
  m.maximum_demand_period # 15 (in minutes, can be 15, 30 or 60)
93
93
  m.ct_ratio # 400
@@ -25,7 +25,9 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  # Runtime dependencies
27
27
  spec.add_runtime_dependency "log4r", "~> 1.1"
28
- spec.add_runtime_dependency "xively-rb-connector", "~> 0.1"
29
28
 
29
+ #spec.add_runtime_dependency "xively-rb-connector", "~> 0.1"
30
+ #spec.add_runtime_dependency "trollop"
31
+ #spec.add_runtime_dependency "daemons"
30
32
 
31
33
  end
@@ -5,4 +5,5 @@ end
5
5
 
6
6
  require "ekm-omnimeter/version"
7
7
  require "ekm-omnimeter/logging"
8
+ require "ekm-omnimeter/crc16"
8
9
  require "ekm-omnimeter/meter"
@@ -0,0 +1,54 @@
1
+ module Crc16
2
+
3
+ # Returns boolean true or false if checksum of string s matches expected value
4
+ def self.check_crc16(s, expecting)
5
+ (Crc16.crc16(s) == expecting)
6
+ end
7
+
8
+ # Calculates CRC16 checksum of string buf
9
+ def self.crc16(buf)
10
+ crc = 0x00
11
+ buf.each_byte do |b|
12
+ crc = ((crc >> 8) & 0xff) ^ CRC_LOOKUP[(crc ^ b) & 0xff]
13
+ end
14
+ crc
15
+ end
16
+
17
+ private
18
+
19
+ CRC_LOOKUP = [
20
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
21
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
22
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
23
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
24
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
25
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
26
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
27
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
28
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
29
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
30
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
31
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
32
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
33
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
34
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
35
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
36
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
37
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
38
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
39
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
40
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
41
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
42
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
43
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
44
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
45
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
46
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
47
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
48
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
49
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
50
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
51
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
52
+ ]
53
+
54
+ end
@@ -13,7 +13,7 @@ module EkmOmnimeter
13
13
  VALID_POWER_CONFIGURATIONS = [:single_phase_2wire, :single_phase_3wire, :three_phase_3wire, :three_phase_4wire]
14
14
 
15
15
  # Initialization attributes
16
- attr_reader :meter_number, :remote_address, :remote_port, :power_configuration, :last_read_timestamp
16
+ attr_reader :meter_number, :remote_address, :remote_port, :verify_checksums, :power_configuration, :last_read_timestamp
17
17
 
18
18
  # Request A
19
19
  #attr_reader :meter_type, :meter_firmware, :address, :total_active_kwh, :total_kvarh, :total_rev_kwh, :three_phase_kwh, :three_phase_rev_kwh, :resettable_kwh, :resettable_reverse_kwh, :volts_l1, :volts_l2, :volts_l3, :amps_l1, :amps_l2, :amps_l3, :watts_l1, :watts_l2, :watts_l3, :watts_total, :cosϴ_l1, :cosϴ_l2, :cosϴ_l3, :var_l1, :var_l2, :var_l3, :var_total, :freq, :pulse_count_1, :pulse_count_2, :pulse_count_3, :pulse_input_hilo, :direction_of_current, :outputs_onoff, :kwh_data_decimal_places,
@@ -21,6 +21,9 @@ module EkmOmnimeter
21
21
  # Request B
22
22
  #attr_reader :t1_t2_t3_t4_kwh, :t1_t2_t3_t4_rev_kwh, :maximum_demand, :maximum_demand_time, :pulse_ratio_1, :pulse_ratio_2, :pulse_ratio_3, :ct_ratio, :auto_reset_md, :settable_imp_per_kWh_constant
23
23
 
24
+ # iSerial v4 Spec From http://documents.ekmmetering.com/Omnimeter-Pulse-v.4-Protocol.pdf
25
+ # %w(01 52 31 02 30 30 31 31 28 29 03 13 16).map{|a| a.to_i(16).chr}.join
26
+
24
27
  # Mix in the ability to log
25
28
  include Logging
26
29
 
@@ -32,16 +35,19 @@ module EkmOmnimeter
32
35
  @logger.info "Initializing Meter"
33
36
 
34
37
  # Prepend the meter number with the correct amount of leading zeros
35
- @meter_number = options[:meter_number].to_s.rjust(12, '0')
36
- @remote_address = options[:remote_address] || '192.168.0.125'
37
- @remote_port = options[:remote_port] || 50000
38
+ @meter_number = options[:meter_number].to_s.rjust(12, '0')
39
+ @remote_address = options[:remote_address] || '192.168.0.125'
40
+ @remote_port = options[:remote_port] || 50000
41
+ @verify_checksums = options[:verify_checksums] || false
38
42
  @logger.debug "meter_number: #{meter_number}"
39
43
  @logger.debug "remote_address: #{remote_address}"
40
44
  @logger.debug "remote_port: #{remote_port}"
45
+ @logger.debug "verify_checksums: #{verify_checksums}"
41
46
 
42
47
  # Collect the power configurations
43
48
  if VALID_POWER_CONFIGURATIONS.index(options[:power_configuration])
44
49
  @power_configuration = options[:power_configuration]
50
+ @logger.debug "power_configuration: #{@power_configuration}"
45
51
  else
46
52
  raise EkmOmnimeterError, "Invalid power configuration #{options[:power_configuration]}. Valid values are #{VALID_POWER_CONFIGURATIONS.join(', ')}"
47
53
  end
@@ -68,29 +74,21 @@ module EkmOmnimeter
68
74
  @values
69
75
  end
70
76
 
71
- # Formatted datetime reported by meter during last read
72
- def meter_timestamp
73
- "20#{current_time[0,2]}-#{current_time[2,2]}-#{current_time[4,2]} #{current_time[6,2]}:#{current_time[ 8,2]}:#{current_time[10,2]}"
74
- end
75
77
 
76
78
  # Attribute handler that delegates attribute reads to the values hash
77
79
  def method_missing(method_sym, *arguments, &block)
78
-
79
- #@logger.debug "method_missing #{method_sym.inspect}"
80
-
81
80
  # Only refresh data if its more than 0.25 seconds old
82
81
  et = @last_read_timestamp.nil? ? 0 : (Time.now - @last_read_timestamp)
83
- #logger.debug "Elapsed time since last read #{et}"
82
+ @logger.debug "Elapsed time since last read #{et}"
84
83
  if et > 250
85
- @logger.info "More than 250 milliseconds have passed, updating data"
84
+ @logger.info "More than 250 milliseconds have passed since last read. Triggering refresh."
86
85
  read()
87
86
  end
88
87
 
89
88
  if @values.include? method_sym
90
- #logger.debug "Found #{method_sym}"
91
89
  @values[method_sym]
92
90
  else
93
- #logger.debug "Didn't find #{method_sym}"
91
+ @logger.debug "method_missing failed to find #{method_sym} in the Meter.values cache"
94
92
  super
95
93
  end
96
94
  end
@@ -105,59 +103,6 @@ module EkmOmnimeter
105
103
  end
106
104
 
107
105
 
108
- ## Request A
109
- #d[:meter_type] # 2 Byte Meter Type
110
- #d[:meter_firmware] # 1 Byte Meter Firmware
111
- #d[:address] # 12 Bytes Address
112
- #d[:total_active_kwh] # 8 Bytes total Active kWh
113
- #d[:total_kvarh] # 8 Bytes Total kVARh
114
- #d[:total_rev_kwh] # 8 Bytes Total Rev.kWh
115
- #d[:three_phase_kwh] # 24 Bytes 3 phase kWh
116
- #d[:three_phase_rev_kwh] # 24 Bytes 3 phase Rev.kWh
117
- #d[:resettable_kwh] # 8 Bytes Resettable kWh
118
- #d[:resettable_reverse_kwh] # 8 bytes Resettable Reverse kWh
119
- #d[:volts_l1] # 4 Bytes Volts L1
120
- #d[:volts_l2] # 4 Bytes Volts L2
121
- #d[:volts_l3] # 4 Bytes Volts L3
122
- #d[:amps_l1] # 5 Bytes Amps L1
123
- #d[:amps_l2] # 5 Bytes Amps L2
124
- #d[:amps_l3] # 5 Bytes Amps L3
125
- #d[:watts_l1] # 7 Bytes Watts L1
126
- #d[:watts_l2] # 7 Bytes Watts L2
127
- #d[:watts_l3] # 7 Bytes Watts L3
128
- #d[:watts_total] # 7 Bytes Watts Total
129
- #d[:cosϴ_l1] # 4 Bytes Cosϴ L1
130
- #d[:cosϴ_l2] # 4 Bytes Cosϴ L2
131
- #d[:cosϴ_l3] # 4 Bytes Cosϴ L3
132
- #d[:var_l1] # 7 Bytes VAR L1
133
- #d[:var_l2] # 7 Bytes VAR L2
134
- #d[:var_l3] # 7 Bytes VAR L3
135
- #d[:var_total] # 7 Bytes VAR Total
136
- #d[:freq] # 4 Bytes Freq
137
- #d[:pulse_count_1] # 8 Bytes Pulse Count 1
138
- #d[:pulse_count_2] # 8 Bytes Pulse Count 2
139
- #d[:pulse_count_3] # 8 Bytes Pulse Count 3
140
- #d[:pulse_input_hilo] # 1 Byte Pulse Input Hi/Lo
141
- #d[:direction_of_current] # 1 Bytes direction of current
142
- #d[:outputs_onoff] # 1 Byte Outputs On/Off
143
- #d[:kwh_data_decimal_places] # 1 Byte kWh Data Decimal Places
144
-
145
- ## Request B
146
- #d[:t1_t2_t3_t4_kwh] # 32 Bytes T1, T2, T3, T4 kwh
147
- #d[:t1_t2_t3_t4_rev_kwh] # 32 Bytes T1, T2, T3, T4 Rev kWh
148
- #d[:maximum_demand] # 8 Bytes Maximum Demand
149
- #d[:maximum_demand_time] # 1 Byte Maximum Demand Time
150
- #d[:pulse_ratio_1] # 4 Bytes Pulse Ratio 1
151
- #d[:pulse_ratio_2] # 4 Bytes Pulse Ratio 2
152
- #d[:pulse_ratio_3] # 4 Bytes Pulse Ratio 3
153
- #d[:ct_ratio] # 4 Bytes CT Ratio
154
- #d[:auto_reset_md] # 1 Bytes Auto Reset MD
155
- #d[:settable_imp_per_kWh_constant] # 4 Bytes Settable Imp/kWh Constant
156
-
157
-
158
- # iSerial v4 Spec From http://documents.ekmmetering.com/Omnimeter-Pulse-v.4-Protocol.pdf
159
- # %w(01 52 31 02 30 30 31 31 28 29 03 13 16).map{|a| a.to_i(16).chr}.join
160
-
161
106
  # Returns the correct measurement for voltage, current, and power based on the corresponding power_configuration
162
107
  def calculate_measurement(m1, m2, m3)
163
108
  if power_configuration == :single_phase_2wire
@@ -185,6 +130,20 @@ module EkmOmnimeter
185
130
  end
186
131
  end
187
132
 
133
+ # Power factor values come back as C099 which need to be cast to C0.99
134
+ def cast_power_factor(s)
135
+ "#{s[0]}#{s[1,3].to_f / 100.0}"
136
+ end
137
+
138
+ # Formatted datetime reported by meter during last read.
139
+ # Raw string is formatted as YYMMDDWWHHMMSS where YY is year without century, and WW is week day with Sunday as the first day of the week
140
+ #"20#{current_time[0,2]}-#{current_time[2,2]}-#{current_time[4,2]} #{current_time[8,2]}:#{current_time[ 10,2]}:#{current_time[12,2]}"
141
+ def as_datetime(s)
142
+ DateTime.new("20#{s[0,2]}".to_i, s[2,2].to_i, s[4,2].to_i, s[8,2].to_i, s[10,2].to_i, s[12,2].to_i, '-4')
143
+ end
144
+
145
+ # All values are returned without decimals. This method loops over all
146
+ # the values and sets them to the correct precision
188
147
  def cast_response_to_correct_types(d)
189
148
 
190
149
  # Integers
@@ -224,10 +183,7 @@ module EkmOmnimeter
224
183
  end
225
184
 
226
185
  # Floats with precision 2
227
- [:power_factor_1,
228
- :power_factor_2,
229
- :power_factor_3,
230
- :frequency
186
+ [:frequency
231
187
  ].each do |k|
232
188
  logger.debug "Casting #{k}"
233
189
  d[k] = to_f_with_decimal_places(d[k], 2) if d.has_key?(k)
@@ -329,20 +285,31 @@ module EkmOmnimeter
329
285
  d[:outputs_onoff] = a.shift(1) # 1 Byte Outputs On/Off
330
286
  d[:kwh_data_decimal_places] = a.shift(1) # 1 Byte kWh Data Decimal Places
331
287
  a.shift(2) # 2 Bytes Reserved
332
- d[:current_time] = a.shift(14) # 14 Bytes Current Time
288
+ meter_timestamp = a.shift(14).join('') # 14 Bytes Current Time
333
289
  a.shift(6) # 30 30 21 0D 0A 03
334
- d[:CRC16] = a.shift(2) # 2 Bytes CRC16
290
+ d[:checksum] = a.shift(2) # 2 Bytes CRC16
335
291
 
336
292
  # Smash arrays into strungs
337
293
  d.each {|k,v| d[k] = v.join('')}
338
294
 
295
+ if verify_checksums
296
+ if Crc16.check_crc16(response, d[:checksum])
297
+ @logger.debug "Checksum matches"
298
+ else
299
+ @logger.error "CRC16 Checksum doesn't match. Expecting #{d[:checksum]} but was #{Crc16.crc16(response)}"
300
+ #raise EkmOmnimeterError, "Checksum doesn't match"
301
+ end
302
+ end
303
+
339
304
  # Cast types
340
305
  @values[:kwh_data_decimal_places] = d[:kwh_data_decimal_places].to_i
306
+ d[:power_factor_1] = cast_power_factor(d[:power_factor_1])
307
+ d[:power_factor_2] = cast_power_factor(d[:power_factor_2])
308
+ d[:power_factor_3] = cast_power_factor(d[:power_factor_3])
309
+ d[:meter_timestamp] = as_datetime(meter_timestamp)
341
310
  cast_response_to_correct_types(d)
342
311
 
343
312
  # Lookup mapped values
344
- puts "d[:pulse_input_hilo] = #{d[:pulse_input_hilo].inspect}"
345
-
346
313
  d[:pulse_1_input], d[:pulse_2_input], d[:pulse_3_input] = lookup_pulse_input_states(d[:pulse_input_hilo])
347
314
  d[:current_direction_l1], d[:current_direction_l2], d[:current_direction_l3] = lookup_direction_of_current(d[:direction_of_current])
348
315
  d[:output_1], d[:output_2] = lookup_output_states(d[:outputs_onoff])
@@ -352,7 +319,6 @@ module EkmOmnimeter
352
319
  @last_read_timestamp = Time.now
353
320
 
354
321
  # Calculate totals based on wiring configuration
355
- @values[:meter_timestamp] = meter_timestamp
356
322
  @values[:volts] = calculate_measurement(volts_l1, volts_l2, volts_l3)
357
323
  @values[:amps] = calculate_measurement(amps_l1, amps_l2, amps_l3)
358
324
  @values[:watts] = calculate_measurement(watts_l1, watts_l2, watts_l3)
@@ -364,7 +330,6 @@ module EkmOmnimeter
364
330
 
365
331
  end
366
332
 
367
-
368
333
  # Request B
369
334
  # TODO: Instead of pre-parsing and casting everything, refactor this so that only the response string gets saved, and parse out values that are accessed.
370
335
  def request_b
@@ -428,14 +393,27 @@ module EkmOmnimeter
428
393
  d[:settable_pulse_per_kwh_ratio] = a.shift(4) # 4 Bytes Settable Imp/kWh Constant
429
394
  # Diff from request A end
430
395
  a.shift(56) # 56 Bytes Reserved
431
- d[:current_time] = a.shift(14) # 14 Bytes Current Time
396
+ meter_timestamp = a.shift(14).join('') # 14 Bytes Current Time
432
397
  a.shift(6) # 30 30 21 0D 0A 03
433
- d[:checksum] = a.shift(2) # 2 Bytes CRC16
398
+ d[:checksum] = a.shift(2) # 2 Bytes CRC16
434
399
 
435
400
  # Smash arrays into strungs
436
401
  d.each {|k,v| d[k] = v.join('')}
437
402
 
403
+ if verify_checksums
404
+ if Crc16.check_crc16(response, d[:checksum])
405
+ @logger.debug "Checksum matches"
406
+ else
407
+ @logger.error "CRC16 Checksum doesn't match. Expecting #{d[:checksum]} but was #{Crc16.crc16(response)}"
408
+ #raise EkmOmnimeterError, "Checksum doesn't match"
409
+ end
410
+ end
411
+
438
412
  # Cast types
413
+ d[:power_factor_1] = cast_power_factor(d[:power_factor_1])
414
+ d[:power_factor_2] = cast_power_factor(d[:power_factor_2])
415
+ d[:power_factor_3] = cast_power_factor(d[:power_factor_3])
416
+ d[:meter_timestamp] = as_datetime(meter_timestamp)
439
417
  cast_response_to_correct_types(d)
440
418
 
441
419
  # Lookup mapped values
@@ -447,7 +425,6 @@ module EkmOmnimeter
447
425
  @last_read_timestamp = Time.now
448
426
 
449
427
  # Calculate totals based on wiring configuration
450
- @values[:meter_timestamp] = meter_timestamp
451
428
  @values[:volts] = calculate_measurement(volts_l1, volts_l2, volts_l3)
452
429
  @values[:amps] = calculate_measurement(amps_l1, amps_l2, amps_l3)
453
430
  @values[:watts] = calculate_measurement(watts_l1, watts_l2, watts_l3)
@@ -458,7 +435,6 @@ module EkmOmnimeter
458
435
  end
459
436
 
460
437
 
461
-
462
438
  # Gets remote EKM meter data using iSerial defaults
463
439
  # meter_number is the meters serial number. leading 0s not required.
464
440
  # remote_address is the IP address of the ethernet-RS485 converter
@@ -473,24 +449,24 @@ module EkmOmnimeter
473
449
  begin
474
450
 
475
451
  socket = TCPSocket.new(remote_address, remote_port)
476
- logger.debug "Socket open" unless logger.nil?
452
+ @logger.debug "Socket open"
477
453
 
478
454
  # Send request to the meter
479
- logger.debug "Request: #{request}" unless logger.nil?
455
+ @logger.debug "Request: #{request}"
480
456
  socket.write(request)
481
457
 
482
458
  # Receive a response of 255 bytes
483
459
  response = socket.read(read_bytes)
484
- logger.debug "Socket response #{response.length}" unless logger.nil?
485
- logger.debug response unless logger.nil?
460
+ @logger.debug "Socket response #{response.length}"
461
+ @logger.debug response
486
462
 
487
463
  rescue Exception => ex
488
- logger.error "Exception\n#{ex.message}\n#{ex.backtrace.join("\n")}" unless logger.nil?
464
+ @logger.error "Exception\n#{ex.message}\n#{ex.backtrace.join("\n")}"
489
465
  ensure
490
466
  # EKM Meter software sends this just before closing the connection, so we will too
491
467
  socket.write "\x0a\x03\x32\x3d"
492
468
  socket.close
493
- logger.debug "Socket closed" unless logger.nil?
469
+ @logger.debug "Socket closed"
494
470
  end
495
471
 
496
472
  return response
@@ -7,7 +7,7 @@ module EkmOmnimeter
7
7
  module VERSION #:nodoc:
8
8
  MAJOR = 0
9
9
  MINOR = 2
10
- PATCH = 3
10
+ PATCH = 4
11
11
 
12
12
  STRING = [MAJOR, MINOR, PATCH].join('.')
13
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ekm-omnimeter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Duggan
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.1'
69
- - !ruby/object:Gem::Dependency
70
- name: xively-rb-connector
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ~>
74
- - !ruby/object:Gem::Version
75
- version: '0.1'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ~>
81
- - !ruby/object:Gem::Version
82
- version: '0.1'
83
69
  description: Ruby interface to the EKM Omnimeter Pulse
84
70
  email:
85
71
  - Jordan.Duggan@gmail.com
@@ -96,6 +82,7 @@ files:
96
82
  - ekm-omnimeter.gemspec
97
83
  - lib/ekm-omnimeter.rb
98
84
  - lib/ekm-omnimeter/configuration.rb
85
+ - lib/ekm-omnimeter/crc16.rb
99
86
  - lib/ekm-omnimeter/logging.rb
100
87
  - lib/ekm-omnimeter/meter.rb
101
88
  - lib/ekm-omnimeter/version.rb