def request_a

      # 2F 3F 12 Bytes Address 30 30 21 0D 0A
      # /?00000000012300! then a CRLF
      request = "/?" + meter_number + "00!\r\n"
      read_bytes = 255
      @logger.debug "Socket write #{request}"
      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
      d[:total_kwh] = a.shift(8)               # 8 Bytes total Active kWh
      d[:reactive_kwh_kvarh] = a.shift(8)      # 8 Bytes Total kVARh
      d[:total_reverse_kwh] = a.shift(8)       # 8 Bytes Total Rev.kWh

      # 24 Bytes 3 phase kWh
      d[:total_kwh_l1] = a.shift(8)
      d[:total_kwh_l2] = a.shift(8)
      d[:total_kwh_l3] = a.shift(8)
      # 24 Bytes 3 phase Rev.kWh
      d[:reverse_kwh_l1] = a.shift(8)
      d[:reverse_kwh_l2] = a.shift(8)
      d[:reverse_kwh_l3] = a.shift(8)

      d[:resettable_total_kwh] = a.shift(8)    # 8 Bytes Resettable kWh
      d[:resettable_reverse_kwh] = a.shift(8)  # 8 bytes Resettable Reverse kWh
      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
      d[:reactive_power_1] = a.shift(7)        # 7 Bytes VAR L1
      d[:reactive_power_2] = a.shift(7)        # 7 Bytes VAR L2
      d[:reactive_power_3] = a.shift(7)        # 7 Bytes VAR L3
      d[:total_reactive_power] = a.shift(7)    # 7 Bytes VAR Total
      d[:frequency] = a.shift(4)               # 4 Bytes Freq
      d[:pulse_1_count] = a.shift(8)           # 8 Bytes Pulse Count 1
      d[:pulse_2_count] = a.shift(8)           # 8 Bytes Pulse Count 2
      d[:pulse_3_count] = a.shift(8)           # 8 Bytes Pulse Count 3
      d[:pulse_input_hilo] = a.shift(1)        # 1 Byte Pulse Input Hi/Lo
      d[:direction_of_current] = a.shift(1)    # 1 Bytes direction of current
      d[:outputs_onoff] = a.shift(1)           # 1 Byte Outputs On/Off
      d[:kwh_data_decimal_places] = a.shift(1) # 1 Byte kWh Data Decimal Places
      a.shift(2)                               # 2 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
      @values[:kwh_data_decimal_places] = d[:kwh_data_decimal_places].to_i
      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[:pulse_1_input], d[:pulse_2_input], d[:pulse_3_input] = PULSE_INPUT_STATE_MAP[d[:pulse_input_hilo]]
      d[:current_direction_l1], d[:current_direction_l2], d[:current_direction_l3] = DIRECTION_OF_CURRENT_MAP[d[:direction_of_current]]
      d[:output_1], d[:output_2] = OUTPUT_INDICATOR_MAP[d[:outputs_onoff]]

      # 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)
      @values[:total_forward_kwh] = total_kwh - total_reverse_kwh
      @values[:net_kwh] = total_forward_kwh - total_reverse_kwh

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

    end
def request_a

      # 2F 3F 12 Bytes Address 30 30 21 0D 0A
      # /?00000000012300! then a CRLF
      request = "/?" + meter_number + "00!\r\n"
      read_bytes = 255
      @logger.debug "Socket write #{request}"
      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
      d[:total_kwh] = a.shift(8)               # 8 Bytes total Active kWh
      d[:reactive_kwh_kvarh] = a.shift(8)      # 8 Bytes Total kVARh
      d[:total_reverse_kwh] = a.shift(8)       # 8 Bytes Total Rev.kWh

      # 24 Bytes 3 phase kWh
      d[:total_kwh_l1] = a.shift(8)
      d[:total_kwh_l2] = a.shift(8)
      d[:total_kwh_l3] = a.shift(8)
      # 24 Bytes 3 phase Rev.kWh
      d[:reverse_kwh_l1] = a.shift(8)
      d[:reverse_kwh_l2] = a.shift(8)
      d[:reverse_kwh_l3] = a.shift(8)

      d[:resettable_total_kwh] = a.shift(8)    # 8 Bytes Resettable kWh
      d[:resettable_reverse_kwh] = a.shift(8)  # 8 bytes Resettable Reverse kWh
      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
      d[:reactive_power_1] = a.shift(7)        # 7 Bytes VAR L1
      d[:reactive_power_2] = a.shift(7)        # 7 Bytes VAR L2
      d[:reactive_power_3] = a.shift(7)        # 7 Bytes VAR L3
      d[:total_reactive_power] = a.shift(7)    # 7 Bytes VAR Total
      d[:frequency] = a.shift(4)               # 4 Bytes Freq
      d[:pulse_1_count] = a.shift(8)           # 8 Bytes Pulse Count 1
      d[:pulse_2_count] = a.shift(8)           # 8 Bytes Pulse Count 2
      d[:pulse_3_count] = a.shift(8)           # 8 Bytes Pulse Count 3
      d[:pulse_input_hilo] = a.shift(1)        # 1 Byte Pulse Input Hi/Lo
      d[:direction_of_current] = a.shift(1)    # 1 Bytes direction of current
      d[:outputs_onoff] = a.shift(1)           # 1 Byte Outputs On/Off
      d[:kwh_data_decimal_places] = a.shift(1) # 1 Byte kWh Data Decimal Places
      a.shift(2)                               # 2 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
      @values[:kwh_data_decimal_places] = d[:kwh_data_decimal_places].to_i
      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[:pulse_1_input], d[:pulse_2_input], d[:pulse_3_input] = PULSE_INPUT_STATE_MAP[d[:pulse_input_hilo]]
      d[:current_direction_l1], d[:current_direction_l2], d[:current_direction_l3] = DIRECTION_OF_CURRENT_MAP[d[:direction_of_current]]
      d[:output_1], d[:output_2] = OUTPUT_INDICATOR_MAP[d[:outputs_onoff]]

      # 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)
      @values[:total_forward_kwh] = total_kwh - total_reverse_kwh
      @values[:net_kwh] = total_forward_kwh - total_reverse_kwh

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

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