Serial.read() vs. Serial.readBytes()?
readBytes is blocking until the determined length has been read, or it times out (see Serial.setTimeout()). Where read grabs what has come, if it has come in. Hence available is used to query if it has.

Note that it takes time for a message to go out and to receive either the echo or response. So simply checking the RX buffer immediately after sending something, is expected to be empty for some time. That is where readBytes sites and waits. And I bet the default setTimeout of 1s is sufficient, to get the response.

This is why you see the Serial.read() inside a while or if Serial.available. Hence I typically employ something like the following: Which emulates readBytes (for the most part).

    #define TIMEOUT = 3000;
    loop {
        char inData[20];
        unsigned long timeout = millis() + TIMEOUT;
        uint8_t inIndex = 0;
        while ( ((int32_t)(millis() - timeout) &lt; 0) &amp;&amp; (inIndex &lt; (sizeof(inData)/sizeof(inData[0])))) {
            if (Serial1.available() &gt; 0) {
                // read the incoming byte:
                inData[inIndex] = Serial.read();
                if ((c == '\n') || (c == '\r')) {
                    break;
                }
                Serial.write(inData[inIndex++]);
            }
        }
    }


Above code was quickly written and untested. But gets the idea across.