user-1: I had a problem communicating an nodeMCU with an Arduino Pro Mini with I2C.
To find the culprit, I finally wrote an Echo Server in Arduino: it receives a byte and responds the same byte. In the nodeMCU I wrote a test program: it sends bytes to the Echo Server and verifies the response, in addition to any error conditions in the Wire methods.
Both processors are connected GND-GND, VCC-VCC, SDA-SDA and SCL-SCL. SDA and SCL have 10K pull-up resistors. Both are connected via USB to my PC, and I have two serial monitors to trace the execution.
In the tester program line 38 there is a delay(1). If you comment it out, some requestFrom() fails randomly with return value != 1, but the Echo Server still received the byte.
As ATmega328 included TWI in the silicon, I can't understand what is failing here and why delay(1) seems to solve the problem. What I'm missing here?
The tester program
/*
 * Echo Server Test
 * Send one byte to the Echo Server and read it back.
 * Do it for bytes from 0x01 to 0xDD
 */
#include <Wire.h>

#define SLAVE_ADDRESS  42
byte car = 1; // car to be send to the Echo Server.

void setup() {
    Serial.begin(9600);
  // We have a nodeMCU con I2C on pins D5 and D6.
    Wire.begin(D5, D6);
    delay(1000);
  Serial.println("");
    Serial.println(" Echo Server Tester");
    Serial.println("---------------------");
    Serial.println("###  Sent   Received");
    delay(1000);    
}

/*
 * Send one byte in each loop().
 */
void loop() {
    byte status;

    if(car > 0) {
        do {
            Wire.beginTransmission(SLAVE_ADDRESS);
            int written = Wire.write(car);
            status = Wire.endTransmission();

            switch(status) {
            case 0:
        delay(1); // Comment this out and watch requestFrom() fails.
                if(Wire.requestFrom(SLAVE_ADDRESS, 1) == 1) {
                    byte r = Wire.read();
                    printChar(car, r);
                    car++;
                } else {
                    Serial.println("error in return");
                    status = 4;
                }

                break;

            case 1:
                Serial.println("Data too long");
                break;

            case 2:
                Serial.println("NACK on address");
                break;

            case 3:
                Serial.println("NACK on data");
                break;

            case 4:
                Serial.println("Some error");
                break;
            }
        }

        while(status != 0);
    }
}

/*
 * Utility: print in bytes sent and received 
 */
void printChar(byte s, byte r) {
    Serial.print(s);
    Serial.print(" ");
    printBits(s);
    Serial.print(' ');
    printBits(r);

    if(r != s) {
    //  Mark invalid responses.
        Serial.print(" *");
    }

    Serial.println();
}

/*
 * Print a simple byte in binary
 */
void printBits(int car) {
    byte bit = 0x80;

    for(int i = 0; i < 8; i++) {
        int digit = car & bit;
        Serial.print(digit ? '1' : '0');
        bit >>= 1;
    }
}

The Echo Server program
/*
 * I2C Echo Server
 * Receive one byte from Master, echo the same byte to Master.
 */
#define MY_ADDRESS  42

#include <Wire.h>

volatile byte received;
volatile int count = 0;

void setup() {
  Serial.begin(9600);

  Wire.begin(MY_ADDRESS);
  Serial.println("--- Echo Server ---");

  Wire.onReceive(receiveCommand);
  Wire.onRequest(sendAnswer);
}

void loop() {
  static int lastCount = 0;

  if (count != lastCount) {
    Serial.print(lastCount + 1); Serial.print(" ");
    printChar(received);
    lastCount++;
  }
}

/*  
 * Receive a byte from Master  
 */
void receiveCommand(int howMany) {
  received = Wire.read();
  count++;
}

/* 
 * Send a byte to Master 
 */
void sendAnswer() {
  Wire.write(received);
}

/*
 * Utility print byte received/sent
 */
void printChar(byte car) {
  Serial.print("Char ");
  byte bit = 0x80;
  for (int i = 0; i < 8; i++) {
    byte digit = car & bit;
    Serial.print(digit ? '1' : '0');
    bit >>= 1;
  }
  Serial.println();
}


user30198: The 1 millisecond is not needed, try delayMicroseconds with 50 or maybe 20 µs.
The Arduino as a slave is totally different than for example a sensor. The Arduino as a slave uses a combination of hardware and software. The onRequest and onReceive functions are executed while the Arduino keeps the SCL line low. That is called clock pulse stretching.  
With an Arduino Uno (ATmega328P microcontroller) connected to an Arduino Uno, this delay problem between a write and read on the I2C bus existed for a long time. A few years ago it was solved. It was a bug, a real bug. That delay is no longer needed.
There are still ways to make it unreliable, for example by disabling the interrupts for too long in the slave.
I read that is still exists with the Arduino Due. With the Due as a master and for example an ATmega328P (at 3.3V) as a slave, the Due still needs a delay.
The nodeMCU and the Raspberry Pi might still have some problems when an Arduino is used as a slave. The Arduino as a slave should at least run at 3.3V or a I2C level shifter should be used.
I don't know if the nodeMCU Wire library supports clock pulse stretching.
That delay might still be needed. Even then, I don't know how reliable the communication will be.
The Wire.endTransmission is the function that transmits the data (not the Wire.write). If that is followed too soon by a Wire.requestFrom and there is a bug in the Wire library, that can cause troubles.

-1: <p>I had a problem communicating an nodeMCU with an Arduino Pro Mini with I2C.</p>

<p>To find the culprit, I finally wrote an Echo Server in Arduino: it receives a byte and responds the same byte. In the nodeMCU I wrote a test program: it sends bytes to the Echo Server and verifies the response, in addition to any error conditions in the <code>Wire</code> methods.</p>

<p>Both processors are connected GND-GND, VCC-VCC, SDA-SDA and SCL-SCL. SDA and SCL have 10K pull-up resistors. Both are connected via USB to my PC, and I have two serial monitors to trace the execution.</p>

<p>In the tester program line 38 there is a <code>delay(1)</code>. If you comment it out, some <code>requestFrom()</code> fails randomly with return value != 1, but the Echo Server still received the byte.</p>

<p>As ATmega328 included TWI in the silicon, I can't understand what is failing here and why <code>delay(1)</code> seems to solve the problem. What I'm missing here?</p>

<p><strong>The tester program</strong></p>

<pre><code>/*
 * Echo Server Test
 * Send one byte to the Echo Server and read it back.
 * Do it for bytes from 0x01 to 0xDD
 */
#include &lt;Wire.h&gt;

#define SLAVE_ADDRESS  42
byte car = 1; // car to be send to the Echo Server.

void setup() {
    Serial.begin(9600);
  // We have a nodeMCU con I2C on pins D5 and D6.
    Wire.begin(D5, D6);
    delay(1000);
  Serial.println("");
    Serial.println(" Echo Server Tester");
    Serial.println("---------------------");
    Serial.println("###  Sent   Received");
    delay(1000);    
}

/*
 * Send one byte in each loop().
 */
void loop() {
    byte status;

    if(car &gt; 0) {
        do {
            Wire.beginTransmission(SLAVE_ADDRESS);
            int written = Wire.write(car);
            status = Wire.endTransmission();

            switch(status) {
            case 0:
        delay(1); // Comment this out and watch requestFrom() fails.
                if(Wire.requestFrom(SLAVE_ADDRESS, 1) == 1) {
                    byte r = Wire.read();
                    printChar(car, r);
                    car++;
                } else {
                    Serial.println("error in return");
                    status = 4;
                }

                break;

            case 1:
                Serial.println("Data too long");
                break;

            case 2:
                Serial.println("NACK on address");
                break;

            case 3:
                Serial.println("NACK on data");
                break;

            case 4:
                Serial.println("Some error");
                break;
            }
        }

        while(status != 0);
    }
}

/*
 * Utility: print in bytes sent and received 
 */
void printChar(byte s, byte r) {
    Serial.print(s);
    Serial.print(" ");
    printBits(s);
    Serial.print(' ');
    printBits(r);

    if(r != s) {
    //  Mark invalid responses.
        Serial.print(" *");
    }

    Serial.println();
}

/*
 * Print a simple byte in binary
 */
void printBits(int car) {
    byte bit = 0x80;

    for(int i = 0; i &lt; 8; i++) {
        int digit = car &amp; bit;
        Serial.print(digit ? '1' : '0');
        bit &gt;&gt;= 1;
    }
}
</code></pre>

<p><strong>The Echo Server program</strong></p>

<pre><code>/*
 * I2C Echo Server
 * Receive one byte from Master, echo the same byte to Master.
 */
#define MY_ADDRESS  42

#include &lt;Wire.h&gt;

volatile byte received;
volatile int count = 0;

void setup() {
  Serial.begin(9600);

  Wire.begin(MY_ADDRESS);
  Serial.println("--- Echo Server ---");

  Wire.onReceive(receiveCommand);
  Wire.onRequest(sendAnswer);
}

void loop() {
  static int lastCount = 0;

  if (count != lastCount) {
    Serial.print(lastCount + 1); Serial.print(" ");
    printChar(received);
    lastCount++;
  }
}

/*  
 * Receive a byte from Master  
 */
void receiveCommand(int howMany) {
  received = Wire.read();
  count++;
}

/* 
 * Send a byte to Master 
 */
void sendAnswer() {
  Wire.write(received);
}

/*
 * Utility print byte received/sent
 */
void printChar(byte car) {
  Serial.print("Char ");
  byte bit = 0x80;
  for (int i = 0; i &lt; 8; i++) {
    byte digit = car &amp; bit;
    Serial.print(digit ? '1' : '0');
    bit &gt;&gt;= 1;
  }
  Serial.println();
}
</code></pre>
 30198: <p>The 1 millisecond is not needed, try delayMicroseconds with 50 or maybe 20 µs.</p>

<p>The Arduino as a slave is totally different than for example a sensor. The Arduino as a slave uses a combination of hardware and software. The onRequest and onReceive functions are executed while the Arduino keeps the SCL line low. That is called clock pulse stretching.  </p>

<p>With an Arduino <strong>Uno</strong> (ATmega328P microcontroller) connected to an Arduino Uno, this delay problem between a write and read on the I2C bus existed for a long time. A few years ago it was solved. It was a bug, a real bug. That delay is no longer needed.<br>
There are still ways to make it unreliable, for example by disabling the interrupts for too long in the slave.</p>

<p>I read that is still exists with the Arduino <strong>Due</strong>. With the Due as a master and for example an ATmega328P (at 3.3V) as a slave, the Due still needs a delay.</p>

<p>The <strong>nodeMCU</strong> and the Raspberry Pi might still have some problems when an Arduino is used as a slave. The Arduino as a slave should at least run at 3.3V or a I2C level shifter should be used.<br>
I don't know if the nodeMCU Wire library supports clock pulse stretching.<br>
That delay might still be needed. Even then, I don't know how reliable the communication will be.</p>

<p>The Wire.endTransmission is the function that transmits the data (not the Wire.write). If that is followed too soon by a Wire.requestFrom and there is a bug in the Wire library, that can cause troubles.</p>
