def request_b

      # 2F 3F 12 Bytes Address 30 31 21 0D 0A
      # /?00000000012301! then a CRLF
      request = "/?" + meter_number + "01!\r\n"
      read_bytes = 255
      @logger.debug "Socket write #{request}" unless logger.nil?
      response = get_remote_meter_data(request, read_bytes)
      if response.nil?
        @logger.error "No response to request_a from meter #{meter_number}"
        raise EkmOmnimeter, "No response from meter."
      end

      # Split the response string into an array and prepare a hash to store the values
      a = response.split('')
      d = {}

      # Return (255 Bytes total) :
      a.shift(1)                               # 02
      d[:meter_type] = a.shift(2)              # 2 Byte Meter Type
      d[:meter_firmware] = a.shift(1)          # 1 Byte Meter Firmware
      d[:address] = a.shift(12)                # 12 Bytes Address

      # Diff from request A start
      #d[:t1_t2_t3_t4_kwh] = a.shift(32)        # 32 Bytes T1, T2, T3, T4 kwh
      d[:total_kwh_t1] = a.shift(8)
      d[:total_kwh_t2] = a.shift(8)
      d[:total_kwh_t3] = a.shift(8)
      d[:total_kwh_t4] = a.shift(8)

      #d[:t1_t2_t3_t4_rev_kwh] = a.shift(32)    # 32 Bytes T1, T2, T3, T4 Rev kWh
      d[:reverse_kwh_t1] = a.shift(8)
      d[:reverse_kwh_t2] = a.shift(8)
      d[:reverse_kwh_t3] = a.shift(8)
      d[:reverse_kwh_t4] = a.shift(8)

      # Diff from request A end
      d[:volts_l1] = a.shift(4)                # 4 Bytes Volts L1
      d[:volts_l2] = a.shift(4)                # 4 Bytes Volts L2
      d[:volts_l3] = a.shift(4)                # 4 Bytes Volts L3
      d[:amps_l1] = a.shift(5)                 # 5 Bytes Amps L1
      d[:amps_l2] = a.shift(5)                 # 5 Bytes Amps L2
      d[:amps_l3] = a.shift(5)                 # 5 Bytes Amps L3
      d[:watts_l1] = a.shift(7)                # 7 Bytes Watts L1
      d[:watts_l2] = a.shift(7)                # 7 Bytes Watts L2
      d[:watts_l3] = a.shift(7)                # 7 Bytes Watts L3
      d[:watts_total] = a.shift(7)             # 7 Bytes Watts Total
      d[:power_factor_1] = a.shift(4)          # 4 Bytes Cosϴ L1
      d[:power_factor_2] = a.shift(4)          # 4 Bytes Cosϴ L2
      d[:power_factor_3] = a.shift(4)          # 4 Bytes Cosϴ L3
      # Diff from request A start
      d[:maximum_demand] = a.shift(8)                # 8 Bytes Maximum Demand
      d[:maximum_demand_period] = a.shift(1)         # 1 Byte Maximum Demand Time
      d[:pulse_1_ratio] = a.shift(4)                 # 4 Bytes Pulse Ratio 1
      d[:pulse_2_ratio] = a.shift(4)                 # 4 Bytes Pulse Ratio 2
      d[:pulse_3_ratio] = a.shift(4)                 # 4 Bytes Pulse Ratio 3
      d[:ct_ratio] = a.shift(4)                      # 4 Bytes CT Ratio
      d[:auto_reset_max_demand] = a.shift(1)         # 1 Bytes Auto Reset MD
      d[:settable_pulse_per_kwh_ratio] = a.shift(4)  # 4 Bytes Settable Imp/kWh Constant
      # Diff from request A end
      a.shift(56)                              # 56 Bytes Reserved
      meter_timestamp = a.shift(14).join('')   # 14 Bytes Current Time
      a.shift(6)                               # 30 30 21 0D 0A 03
      d[:checksum] = a.shift(2)                   # 2 Bytes CRC16

      # Smash arrays into strungs
      d.each {|k,v| d[k] = v.join('')}

      # Verify that the checksum is correct
      verify_checksum(response, d[:checksum])

      # Cast types
      d[:meter_type] = d[:meter_type].unpack('H*')[0]
      d[:meter_firmware] = d[:meter_firmware].unpack('H*')[0]
      d[:power_factor_1] = cast_power_factor(d[:power_factor_1])
      d[:power_factor_2] = cast_power_factor(d[:power_factor_2])
      d[:power_factor_3] = cast_power_factor(d[:power_factor_3])
      d[:meter_timestamp] = as_datetime(meter_timestamp)
      cast_response_to_correct_types(d)

      # Lookup mapped values
      d[:meter_type] = METER_TYPE_MAP[d[:meter_type]]
      d[:maximum_demand_period] = DEMAND_PERIOD_TIME_MAP[d[:maximum_demand_period]]
      d[:auto_reset_max_demand] = AUTO_RESET_MAX_DEMAND_MAP[d[:auto_reset_max_demand]]

      # Merge to values and reset time
      @values.merge!(d)
      @last_read_timestamp = Time.now

      # Calculate totals based on wiring configuration
      @values[:volts] = calculate_measurement(volts_l1, volts_l2, volts_l3)
      @values[:amps]  = calculate_measurement(amps_l1, amps_l2, amps_l3)
      @values[:watts] = calculate_measurement(watts_l1, watts_l2, watts_l3)

      # Return the values returned by just this call (different than values)
      return d

    end
def request_b

      # 2F 3F 12 Bytes Address 30 31 21 0D 0A
      # /?00000000012301! then a CRLF
      request = "/?" + meter_number + "01!\r\n"
      read_bytes = 255
      @logger.debug "Socket write #{request}" unless logger.nil?
      response = get_remote_meter_data(request, read_bytes)
      if response.nil?
        @logger.error "No response to request_a from meter #{meter_number}"
        raise EkmOmnimeter, "No response from meter."
      end

      # Split the response string into an array and prepare a hash to store the values
      a = response.split('')
      d = {}

      # Return (255 Bytes total) :
      a.shift(1)                               # 02
      d[:meter_type] = a.shift(2)              # 2 Byte Meter Type
      d[:meter_firmware] = a.shift(1)          # 1 Byte Meter Firmware
      d[:address] = a.shift(12)                # 12 Bytes Address

      # Diff from request A start
      #d[:t1_t2_t3_t4_kwh] = a.shift(32)        # 32 Bytes T1, T2, T3, T4 kwh
      d[:total_kwh_t1] = a.shift(8)
      d[:total_kwh_t2] = a.shift(8)
      d[:total_kwh_t3] = a.shift(8)
      d[:total_kwh_t4] = a.shift(8)

      #d[:t1_t2_t3_t4_rev_kwh] = a.shift(32)    # 32 Bytes T1, T2, T3, T4 Rev kWh
      d[:reverse_kwh_t1] = a.shift(8)
      d[:reverse_kwh_t2] = a.shift(8)
      d[:reverse_kwh_t3] = a.shift(8)
      d[:reverse_kwh_t4] = a.shift(8)

      # Diff from request A end
      d[:volts_l1] = a.shift(4)                # 4 Bytes Volts L1
      d[:volts_l2] = a.shift(4)                # 4 Bytes Volts L2
      d[:volts_l3] = a.shift(4)                # 4 Bytes Volts L3
      d[:amps_l1] = a.shift(5)                 # 5 Bytes Amps L1
      d[:amps_l2] = a.shift(5)                 # 5 Bytes Amps L2
      d[:amps_l3] = a.shift(5)                 # 5 Bytes Amps L3
      d[:watts_l1] = a.shift(7)                # 7 Bytes Watts L1
      d[:watts_l2] = a.shift(7)                # 7 Bytes Watts L2
      d[:watts_l3] = a.shift(7)                # 7 Bytes Watts L3
      d[:watts_total] = a.shift(7)             # 7 Bytes Watts Total
      d[:power_factor_1] = a.shift(4)          # 4 Bytes Cosϴ L1
      d[:power_factor_2] = a.shift(4)          # 4 Bytes Cosϴ L2
      d[:power_factor_3] = a.shift(4)          # 4 Bytes Cosϴ L3
      # Diff from request A start
      d[:maximum_demand] = a.shift(8)                # 8 Bytes Maximum Demand
      d[:maximum_demand_period] = a.shift(1)         # 1 Byte Maximum Demand Time
      d[:pulse_1_ratio] = a.shift(4)                 # 4 Bytes Pulse Ratio 1
      d[:pulse_2_ratio] = a.shift(4)                 # 4 Bytes Pulse Ratio 2
      d[:pulse_3_ratio] = a.shift(4)                 # 4 Bytes Pulse Ratio 3
      d[:ct_ratio] = a.shift(4)                      # 4 Bytes CT Ratio
      d[:auto_reset_max_demand] = a.shift(1)         # 1 Bytes Auto Reset MD
      d[:settable_pulse_per_kwh_ratio] = a.shift(4)  # 4 Bytes Settable Imp/kWh Constant
      # Diff from request A end
      a.shift(56)                              # 56 Bytes Reserved
      meter_timestamp = a.shift(14).join('')   # 14 Bytes Current Time
      a.shift(6)                               # 30 30 21 0D 0A 03
      d[:checksum] = a.shift(2)                   # 2 Bytes CRC16

      # Smash arrays into strungs
      d.each {|k,v| d[k] = v.join('')}

      # Verify that the checksum is correct
      verify_checksum(response, d[:checksum])

      # Cast types
      d[:meter_type] = d[:meter_type].unpack('H*')[0]
      d[:meter_firmware] = d[:meter_firmware].unpack('H*')[0]
      d[:power_factor_1] = cast_power_factor(d[:power_factor_1])
      d[:power_factor_2] = cast_power_factor(d[:power_factor_2])
      d[:power_factor_3] = cast_power_factor(d[:power_factor_3])
      d[:meter_timestamp] = as_datetime(meter_timestamp)
      cast_response_to_correct_types(d)

      # Lookup mapped values
      d[:meter_type] = METER_TYPE_MAP[d[:meter_type]]
      d[:maximum_demand_period] = DEMAND_PERIOD_TIME_MAP[d[:maximum_demand_period]]
      d[:auto_reset_max_demand] = AUTO_RESET_MAX_DEMAND_MAP[d[:auto_reset_max_demand]]

      # Merge to values and reset time
      @values.merge!(d)
      @last_read_timestamp = Time.now

      # Calculate totals based on wiring configuration
      @values[:volts] = calculate_measurement(volts_l1, volts_l2, volts_l3)
      @values[:amps]  = calculate_measurement(amps_l1, amps_l2, amps_l3)
      @values[:watts] = calculate_measurement(watts_l1, watts_l2, watts_l3)

      # Return the values returned by just this call (different than values)
      return d

    end
Request B
 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.