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 +4 -4
- data/Gemfile.lock +1 -25
- data/README.md +8 -8
- data/ekm-omnimeter.gemspec +3 -1
- data/lib/ekm-omnimeter.rb +1 -0
- data/lib/ekm-omnimeter/crc16.rb +54 -0
- data/lib/ekm-omnimeter/meter.rb +64 -88
- data/lib/ekm-omnimeter/version.rb +1 -1
- metadata +2 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8683533fedec1693dfa676899772275fe0ae881a
|
4
|
+
data.tar.gz: 0e2a8333af1cdedd8e41a4e8f5313f49124cd104
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 732818ce1410339b035a8c070bc8aab692aec256b29c9ecb7d0f4f46e92b6689097a26147706585767d5e0d72296f52db39cb736ce412a0ac3f6cdcb313b3843
|
7
|
+
data.tar.gz: ff897d4aa8a55847833cb7c6775f0947347ca0e48b30e04580139174fd570d95c638f66fe8088667bed2d6d2402c5d830cc86a9ab22407c60c267dd9c20dc8de
|
data/Gemfile.lock
CHANGED
@@ -1,26 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ekm-omnimeter (0.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
|
89
|
-
m.power_factor_2
|
90
|
-
m.power_factor_3
|
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
|
data/ekm-omnimeter.gemspec
CHANGED
@@ -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
|
data/lib/ekm-omnimeter.rb
CHANGED
@@ -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
|
data/lib/ekm-omnimeter/meter.rb
CHANGED
@@ -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
|
36
|
-
@remote_address
|
37
|
-
@remote_port
|
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
|
-
|
82
|
+
@logger.debug "Elapsed time since last read #{et}"
|
84
83
|
if et > 250
|
85
|
-
@logger.info "More than 250 milliseconds have passed
|
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
|
-
|
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
|
-
[:
|
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
|
-
|
288
|
+
meter_timestamp = a.shift(14).join('') # 14 Bytes Current Time
|
333
289
|
a.shift(6) # 30 30 21 0D 0A 03
|
334
|
-
d[:
|
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
|
-
|
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)
|
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"
|
452
|
+
@logger.debug "Socket open"
|
477
453
|
|
478
454
|
# Send request to the meter
|
479
|
-
logger.debug "Request: #{request}"
|
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}"
|
485
|
-
logger.debug response
|
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")}"
|
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"
|
469
|
+
@logger.debug "Socket closed"
|
494
470
|
end
|
495
471
|
|
496
472
|
return response
|
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.
|
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
|