OK, why not, in for a penny, in for a pound!
The vast majority of I
2C devices have no pull-up - it is not part of the specification. The pull-up is provided externally.
It
happens however that a microprocessor - such as the ATmega - has both I
2C hardware
and as an independent feature of the processor, a pull-up function so you
can enable the pull-ups in your code. Apparently, the "wire" library does so unless modified.
However those pull-ups are quite weak, about 47k. The recommended pull-ups for I
2C are more in the range of 4.7k down to perhaps 1k. You use a lesser value of resistor for longer connecting wires which have more capacitance. So in general, you want to provide external pull-ups in your design.
Note that resistance value is the total value of any pullups connected anywhere on the same bus in parallel and resistors in parallel
reduce the total value. On a fairly long bus it is desirable to put a pullup at each end so that in parallel the resistance is about that 1 to 4.7k.
Now if you are using pre-made I
2C
modules such as the "backpack" for a LCD display or a "port expander", this often (if not always) includes pull-up resistors. If that is the only thing to which you connect your Arduino, that is fine and convenient. But if you connect - because they are all in parallel - a substantial number of such modules, then the parallel resistance of the pullups may drop very low. The Arduino (ATmega328) will happily pull down a 330 Ohm load (less than 20 mA) but slave devices
also are required to pull the lines down in order to exchange data and they generally have a lesser capability, so you need to keep the total pullup resistance above 1k by removing the pullups on all but a couple of the modules.
The final complication is mixing 5 V and 3.3 V devices (such as the 3.3. V ESPs). 5 V devices will generally operate at 3.3 V so you can connect your pullups to 3.3 V and not 5 V in this situation. If that does not work, you need to use a particular bi-directional level converter.
Did I miss anything?