Christian
Published © GPL3+

Connect OLED Screens and I2C Sensors Over 100ft Away!

Use the IO Expander and accessories to connect OLED screens and I2C sensors over a 100ft away.

IntermediateFull instructions provided2 hours6,812

Things used in this project

Hardware components

IO Expander
×1
1-Wire to I2C
×5
1-Wire Junction
×4
Splitter
×3
Arduino Nano R3
Arduino Nano R3
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Connect OLED Screens and I2C Sensors Over 100ft Away

Code

Connect OLED Screens and I2C Sensors Over 100ft Away

C/C++
Connect an IO Expander to your Arduino, NodeMCU, Pi, PC, MAC and add Sensors the simple way!
/* IO Expander OLED sketch
 *  
 *  Make sure you increase the SERIAL_RX_BUFFER_SIZE in Arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h
 *  from 64 to 256.
 */
 
#define SERIAL_RX_BUFFER_SIZE   256

#include <SoftwareSerial.h>
#include <avr/wdt.h>
#include "IOExpander.h"

#define FAHRENHEIT

#define OLED_SCREENS            5
#define TEMP_SENSORS            4
#define HUMIDITY_SENSORS        2

#define ONEWIRE_TO_I2C_ROM1     "i4s51"
#define ONEWIRE_TO_I2C_ROM2     "i4s2e"
#define ONEWIRE_TO_I2C_ROM3     "i4s24"
#define ONEWIRE_TO_I2C_ROM4     "i4sc0"
#define ONEWIRE_TO_I2C_ROM5     "i2see"

#define ONEWIRE_TEMP_CONVERSION "t4s0;tt"
#define TEMP_SENSOR1            "t4r4c"
#define TEMP_SENSOR2            "t4r57"
#define TEMP_SENSOR3            "t4r76"
#define TEMP_SENSOR4            "t4r0300"
#define HUMIDITY_SENSOR1        "st8"
#define HUMIDITY_SENSOR2        "s6t5"

#define INIT_OLED_SSD1306_32    "st10;si128,32"
#define INIT_OLED_SSD1306_64    "st10;si128,64"
#define INIT_OLED_SSD1106       "st13;si128,64"
#define INIT_OLED_SSD1309       "g1o0,10;s2t10;si128,64"

#define SERIAL_DEBUG

#ifdef SERIAL_DEBUG
SoftwareSerial swSerial(8,7);
#endif

struct TS {
  bool update;
  float temp;
  bool error;  
};

struct HS {
  bool update;
  float temp;
  float humidity;
  bool error;
};

int led = 13;

#ifdef FAHRENHEIT
#define C2F(temp)   CelsiusToFahrenheit(temp)
float CelsiusToFahrenheit(float celsius)
{
  return ((celsius*9)/5)32;
}
#else
#define C2F(temp)   (temp)
#endif

bool init_oled[OLED_SCREENS] = {true, true, true, true, true};
TS ts[TEMP_SENSORS];
HS hs[HUMIDITY_SENSORS];

void ReadTempSensor(TS* ts, char* ts_read)
{
  float temp = ts->temp;
 
  SerialCmd(ts_read);
  ts->error = !SerialReadFloat(&ts->temp);
  SerialReadUntilDone();
  ts->temp = roundf(ts->temp * 10) / 10;
  ts->update = (temp != ts->temp);
}

void ReadHumiditySensor(HS* hs)
{
  float temp = hs->temp;
  float humidity = hs->humidity;
 
  SerialCmd("sr");
  hs->error = !(SerialReadFloat(&hs->temp) && SerialReadFloat(&hs->humidity));
  SerialReadUntilDone();
  hs->temp = roundf(hs->temp * 10) / 10;
  hs->humidity = roundf(hs->humidity * 10) / 10;
  hs->update = (temp != hs->temp || humidity != hs->humidity);
}

void SerialPrintDecimal(const char* str, float decimal, char error)
{
  Serial.print(str);
  if (error) Serial.print(F("NA"));
  else Serial.print(decimal, 1);
  Serial.print("\"");
}

void SerialPrintUnits(void)
{
  Serial.print(",248,\""
  #ifdef FAHRENHEIT
            "F"
  #else
            "C"
  #endif
    "\"");                      
}

void SerialDrawBorder(uint8_t height)
{
  if (height == 32) Serial.print(";sh0,0,128;sh0,31,128;sv0,1,30;sv127,1,30");
  else Serial.print(";sh0,0,128;sh0,63,128;sv0,1,62;sv127,1,62");
}

void setup() {
  Serial.begin(115200);
  Serial.setTimeout(5000);                // 5 sec delay between DHT22 reads
#ifdef SERIAL_DEBUG
  swSerial.begin(115200);
  swSerialEcho = &swSerial;
#endif  
  pinMode(led, OUTPUT);
  wdt_enable(WDTO_8S);
}

void loop() {
  uint8_t i;
  static uint32_t last_millis = 0;
  static TS ts[TEMP_SENSORS];
  static HS hs[HUMIDITY_SENSORS];
 
  while (Serial.available()) Serial.read(); // Flush RX buffer
  Serial.println();
  if (SerialReadUntilDone()) {
    // First do a 1-Wire temperature measurement on all DS18B20 sensors
    SerialCmdDone(ONEWIRE_TEMP_CONVERSION);

    // Read the Si7020 humidity sensor
    if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM4)) {
      if (SerialCmdDone(HUMIDITY_SENSOR1)) {
        ReadHumiditySensor(&hs[0]);
      }
    }
    else init_oled[3] = true;

    // Read DHT22 humidity sensor every 2 seconds
    if (millis() - last_millis >= 2000) {
      SerialCmdDone(HUMIDITY_SENSOR2);
      ReadHumiditySensor(&hs[1]);
      last_millis = millis();
    }

    // Read 1-Wire temperature sensors
    ReadTempSensor(&ts[0], TEMP_SENSOR1);
    ReadTempSensor(&ts[1], TEMP_SENSOR2);
    ReadTempSensor(&ts[2], TEMP_SENSOR3);
    ReadTempSensor(&ts[3], TEMP_SENSOR4);

    if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM1)) {
      if (init_oled[0]) {
        if (SerialCmdNoError(INIT_OLED_SSD1306_32)) {
          init_oled[0] = false;
          ts[0].update = true;
        }
      }
      if (!init_oled[0] && ts[0].update) {
        SerialPrintDecimal("st10;sc;sf1;sa2;sd63,8,\"", C2F(ts[0].temp), ts[0].error);
        if (!ts[0].error) SerialPrintUnits();
        SerialDrawBorder(32);
        SerialCmdDone(";sd");
        ts[0].update = false;
      }
    }
    else init_oled[0] = true;
 
    if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM2)) {
      if (init_oled[1]) {
        if (SerialCmdNoError(INIT_OLED_SSD1306_64)) {
          init_oled[1] = false;
          ts[1].update = true;
        }
      }
      if (!init_oled[1] && ts[1].update) {
        SerialPrintDecimal("st10;sc;sf2;sa2;sd63,19,\"", C2F(ts[1].temp), ts[1].error);
        if (!ts[1].error) SerialPrintUnits();
        SerialDrawBorder(64);
        SerialCmdDone(";sd");
        ts[1].update = false;
      }
    }
    else init_oled[1] = true;

    if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM3)) {
      if (init_oled[2]) {
        if (SerialCmdNoError(INIT_OLED_SSD1106)) {
          init_oled[2] = false;
          ts[2].update = true;
        }
      }
      if (!init_oled[2] && ts[2].update) {
        SerialPrintDecimal("st13;sc;sf2;sa2;sd63,19,\"", C2F(ts[2].temp), ts[2].error);
        if (!ts[2].error) SerialPrintUnits();
        SerialDrawBorder(64);
        SerialCmdDone(";sd");
        ts[2].update = false;
      }
    }
    else init_oled[2] = true;

    if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM4)) {
      if (init_oled[3]) {
        if (SerialCmdNoError(INIT_OLED_SSD1106)) {
          init_oled[3] = false;
          ts[3].update = true;
        }
      }
      if (!init_oled[3] && (ts[3].update || hs[0].update)) {
        SerialPrintDecimal("st13;sc;sf1;sa1;sd60,12,\"", C2F(hs[0].temp), hs[0].error);
        SerialPrintUnits();
        SerialPrintDecimal(";sd60,32,\"", hs[0].humidity, hs[0].error);
        Serial.print(",\"%\"");
        SerialPrintDecimal(";sd121,12,\"", C2F(ts[3].temp), ts[3].error);
        SerialPrintUnits();
        SerialDrawBorder(64);
        SerialCmdDone(";sd");
        ts[3].update = false;
        hs[0].update = false;
      }
    }
    else init_oled[3] = true;

    if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM5)) {
      if (init_oled[4]) {
        if (SerialCmdNoError(INIT_OLED_SSD1309)) {
          init_oled[4] = false;
          hs[1].update = true;
        }
      }
      if (!init_oled[4] && hs[1].update) {
        SerialPrintDecimal("st10;sc;sf1;sa2;sd63,12,\"", C2F(hs[1].temp), hs[1].error);
        SerialPrintUnits();
        SerialPrintDecimal(";sd63,32,\"", hs[1].humidity, hs[1].error);
        Serial.print(",\"%\"");
        SerialDrawBorder(64);
        SerialCmdDone(";sd");
        hs[1].update = false;
      }
    }
    else init_oled[4] = true;

#ifdef SERIAL_DEBUG
#endif  
  }
  else {
    digitalWrite(led, HIGH);                // blink Arduino led for IO Expander failure
    delay(500);
    digitalWrite(led, LOW);
    delay(500);

    for (i = 0; i < OLED_SCREENS; i++) init_oled[i] = true;
  }
  wdt_reset();
}

Credits

Christian

Christian

24 projects • 134 followers
Senior Embedded Engineer

Comments