require 'spec_helper'

require 'jfy/client'

describe Jfy::Client do
  describe 'API' do
    let(:serial_port) { double('Serial Port') }
    let(:client) { described_class.new }

    before do
      expect(SerialPort).to receive(:new).with('/dev/ttyUSB0', :baud => 9600).and_return(serial_port)

      expect(serial_port).to receive(:flush_output)
      expect(serial_port).to receive(:flush_input)
      expect(serial_port).to receive(:read_timeout=)

      expect(client).to receive(:wait)
    end

    it 'can register an inverter' do
      data = [0xA5, 0xA5, 0x01, 0x00, 0x30, 0x44, 0x00, 0xFE, 0x41, 0x0A, 0x0D].pack('c*')
      expect(serial_port).to receive(:syswrite).with(data)

      client.re_register
    end

    it 'can perform an offline query' do
      data = [0xA5, 0xA5, 0x01, 0x00, 0x30, 0x40, 0x00, 0xFE, 0x45, 0x0A, 0x0D].pack('c*')
      expect(serial_port).to receive(:syswrite).with(data)
      data = [
        0xA5, 0xA5, 0x01, 0x00, 0x30, 0xBF, 0x10, 0x35, 0x38, 0x31, 0x30, 0x31, 0x30, 0x31, 0x34,
        0x35, 0x31, 0x30, 0x30, 0x31, 0x33, 0x20, 0x20, 0xFA, 0xB8, 0x0A, 0x0D
      ]
      data.each do |byte|
        expect(serial_port).to receive(:getbyte).and_return(byte)
      end

      serial_num = client.offline_query

      expect(serial_num).to eq('58101014510013  ')
    end

    it 'can register the array' do
      data = [
        0xA5, 0xA5, 0x01, 0x00, 0x30, 0x41, 0x11, 0x35, 0x38, 0x31, 0x30, 0x31, 0x30, 0x31,
        0x34, 0x35, 0x31, 0x30, 0x30, 0x31, 0x33, 0x20, 0x20, 0x02, 0xFB, 0x33, 0x0A, 0x0D
      ].pack('c*')
      expect(serial_port).to receive(:syswrite).with(data)
      [0xA5, 0xA5, 0x02, 0x01, 0x30, 0xBE, 0x01, 0x06, 0xFD, 0xBE, 0x0A, 0x0D].each do |byte|
        expect(serial_port).to receive(:getbyte).and_return(byte)
      end

      client.register('58101014510013  ', 0x02)
    end

    it 'can read the description' do
      data = [0xA5, 0xA5, 0x01, 0x02, 0x31, 0x40, 0x00, 0xFE, 0x42, 0x0A, 0x0D].pack('c*')
      expect(serial_port).to receive(:syswrite).with(data)
      orig_desc = [
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
        0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x41, 0x42, 0x43, 0x78, 0x79, 0x81, 0x82,
        0xB8, 0xB9, 0xC1, 0xC2, 0xF8, 0xF9
      ]
      data = [0xA5, 0xA5, 0x02, 0x01, 0x31, 0xBF, 0x22]
      data += orig_desc
      data += [0xF4, 0x03, 0x0A, 0x0D]
      data.each do |byte|
        expect(serial_port).to receive(:getbyte).and_return(byte)
      end

      description = client.description(0x02)
      expect(description).to eq(orig_desc.pack('c*'))
    end

    it 'can read the rw description' do
      data = [0xA5, 0xA5, 0x01, 0x02, 0x31, 0x41, 0x00, 0xFE, 0x41, 0x0A, 0x0D].pack('c*')
      expect(serial_port).to receive(:syswrite).with(data)
      data = [
        0xA5, 0xA5, 0x02, 0x01, 0x31, 0xBE, 0x12,
        0x40, 0x41, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
        0xF8, 0x3D, 0x0A, 0x0D
      ]
      data.each do |byte|
        expect(serial_port).to receive(:getbyte).and_return(byte)
      end

      rw_description = client.rw_description(0x02)
      expect(rw_description).to eq('@ADEFGHIPQRSTUVWXY')
    end

    it 'can query the normal info' do
      data = [0xA5, 0xA5, 0x01, 0x02, 0x31, 0x42, 0x00, 0xFE, 0x40, 0x0A, 0x0D].pack('c*')
      expect(serial_port).to receive(:syswrite).with(data)
      data = [
        0xA5, 0xA5, 0x02, 0x01, 0x31, 0xBD, 0x44,
        0x01, 0xBE, 0x0B, 0x5E, 0x0A, 0xC6, 0x00, 0x00, 0x00, 0x15, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0xC9, 0xEC,
        0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x00, 0x01, 0x01, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x09, 0xB4, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
        0x09, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x09, 0x90, 0x00, 0x00, 0x00, 0x00,
        0xF5, 0xBE, 0x0A, 0x0D
      ]
      data.each do |byte|
        expect(serial_port).to receive(:getbyte).and_return(byte)
      end

      metrics = client.query_normal_info(0x02)
      expected = {
        :temperature => 44.6,
        :mode        => :normal,
        :voltage     => [291.0, 275.8, 0.0],
        :current     => [2.1, 1.1, 0.0],
        :hours       => 0,
        :power       => {
          :total => 5_169_200.0,
          :today => 2_940.0,
          :now   => 696,
        },
      }
      expect(metrics).to eq(expected)
    end

    it 'can query the inverter info' do
      data = [0xA5, 0xA5, 0x01, 0x02, 0x31, 0x43, 0x00, 0xFE, 0x3F, 0x0A, 0x0D].pack('c*')
      expect(serial_port).to receive(:syswrite).with(data)
      data = [
        0xA5, 0xA5, 0x02, 0x01, 0x31, 0xBC, 0x40,
        0x33, 0x20, 0x31, 0x30, 0x30, 0x30, 0x30, 0x4D, 0x31, 0x2E, 0x30, 0x31, 0x53, 0x55, 0x4E, 0x54, 0x52, 0x45,
        0x45, 0x20, 0x31, 0x30, 0x30, 0x30, 0x30, 0x54, 0x4C, 0x20, 0x31, 0x34, 0x30, 0x35, 0x32, 0x39, 0x2D, 0x31,
        0x34, 0x30, 0x36, 0x30, 0x36, 0x20, 0x20, 0x20, 0x35, 0x38, 0x31, 0x30, 0x31, 0x30, 0x31, 0x34, 0x35, 0x31,
        0x30, 0x30, 0x31, 0x33, 0x20, 0x20, 0x36, 0x35, 0x30, 0x30,
        0xF0, 0x82, 0x0A, 0x0D
      ]
      data.each do |byte|
        expect(serial_port).to receive(:getbyte).and_return(byte)
      end

      metrics = client.query_inverter_info(0x02)
      expected = {
        :manufacturer    => '140529-140606',
        :model           => 'SUNTREE 10000TL',
        :nominal_voltage => 650.0,
        :phases          => 3,
        :rating          => 10_000,
        :serial          => '58101014510013',
        :version         => 'M1.01',
      }
      expect(metrics).to eq(expected)
    end

    it 'can query the set info' do
      data = [0xA5, 0xA5, 0x01, 0x02, 0x31, 0x44, 0x00, 0xFE, 0x3E, 0x0A, 0x0D].pack('c*')
      expect(serial_port).to receive(:syswrite).with(data)
      # Size is +2 dues to bug in inverter
      data = [
        0xA5, 0xA5, 0x02, 0x01, 0x31, 0xBB, 0x20,
        0x09, 0xC4, 0x00, 0x3C, 0x08, 0x0C, 0x0A, 0x8C, 0x3D, 0xD3, 0x08, 0x0C, 0x0A, 0x8C, 0x12, 0x8E, 0x14, 0x1E,
        0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x0A, 0x01, 0x0E, 0x00,
        0xF0, 0x82, 0x0A, 0x0D
      ]
      data.each do |byte|
        expect(serial_port).to receive(:getbyte).and_return(byte)
      end

      metrics = client.query_set_info(0x02)
      expected = {
        :pv_voltage   => {
          :startup   => 250.0,
          :high_stop => 206.0,
          :low_stop  => 270.0,
        },
        :grid         => {
          :voltage   => {
            :min => 1582.7,
            :max => 206.0,
          },
          :frequency => {
            :min => 27.0,
            :max => 47.5,
          },
          :impedance => {
            :max   => 5.15,
            :delta => 3,
          },
        },
        :power_factor => 0.03,
        :connect_time => 60,
        :power_max    => 3,
      }
      expect(metrics).to eq(expected)
    end
  end
end
