Arduino Uno and NodeMCU Interfacing

I am trying to interface an arduino uno and a nodemcu and I am having issues. Essentially, I have a sensor that outputs an analog voltage. The Uno reads the analog voltage, and if it is high enough, it sets pin 12 to HIGH. Pin 12 is then connected to D5 of the NodeMCU. The nodeMCU then reads if D5 is high or low, and if it is high, it sends a message to a telegram bot through wifi. However, the NodeMCU constantly reads high from the pin, even if pin 12 is low. I also tried using a voltage divider from pin 12 of the uno to pin D5 of the nodemcu to level shift from 5V to 3.3V but that did not work either. I do not want to have to use serial communication because I am using the SDA and SCL pins to use an OLED screen. Is there any reason that the nodeMCU constantly reads HIGH from pin D5? I thought it would be less of an issue since it's essentially just reading a 1 or 0 but I guess that is not the case. I have attached a diagram and my codes below. Any help is greatly appreciated!

Arduino Code:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

int sensormode = 0;
float voltagelimit = 0.99;
const int buttonPin = 2;

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode(12, OUTPUT); 
  pinMode(buttonPin, INPUT);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000);
  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  // Display static text
  display.println("test");
  display.display();
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);

  if(sensormode == 0 && digitalRead(buttonPin)==HIGH)
  {
    sensormode = 1;
    voltagelimit = 1.5;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 10);
    display.println("Sensor Range: 2 foot");
    display.display();
  }

  if(sensormode == 1 && digitalRead(buttonPin)==HIGH)
  {
    sensormode = 2;
    voltagelimit = 2.2;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 10);
    display.println("Sensor Range: 1 foot");
    display.display();
  }

  if(sensormode == 2 && digitalRead(buttonPin)==HIGH)
  {
    sensormode = 0;
    voltagelimit = 0.99;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 10);
    display.println("Sensor Range: 3 foot");
    display.display();
  }


   if(voltage > voltagelimit)      //Check the sensor output
  {
    digitalWrite(12, HIGH);   // set the LED on
  }
  else
  {
    digitalWrite(12, LOW);    // set the LED off
  }
  delay(10);
}

NodeMCU code:

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>

// Replace with your network credentials
const char* ssid = "private";
const char* password = "private";

// Initialize Telegram BOT
#define BOTtoken "private"  // your Bot Token (Get from Botfather)

// Use @myidbot to find out the chat ID of an individual or a group
// Also note that you need to click "start" on a bot before it can
// message you
#define CHAT_ID "private"

X509List cert(TELEGRAM_CERTIFICATE_ROOT);
WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);


const int motionSensor = 14; // input from uno pin 12
bool motionDetected = false;

unsigned long startMillis;
bool timingFlag  = false;
const unsigned long period = 3000;

// Indicates when motion is detected
void ICACHE_RAM_ATTR detectsMovement() {
  //Serial.println("MOTION DETECTED!!!");
  motionDetected = true;
}

void setup() {
  Serial.begin(115200);
  configTime(0, 0, "pool.ntp.org");      // get UTC time via NTP
  client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org

  // PIR Motion Sensor mode INPUT
  pinMode(motionSensor, INPUT);

  // Attempt to connect to Wifi network:
  Serial.print("Connecting Wifi: ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  bot.sendMessage(CHAT_ID, "Bot started up", "");
}

void loop() {
  
  if (timingFlag == false && digitalRead(motionSensor)==LOW)
  {
    timingFlag = true;     //enable timing
    startMillis = millis();
  }

  //make sure there is still PIR detection
  if (timingFlag == true && millis() - startMillis < period && digitalRead(motionSensor)==HIGH)
  {
    //the PIR timed out with in the three seconds so cancel timing
    timingFlag = false;    //disable timing
    bot.sendMessage(CHAT_ID, "quick motion detected", "");
  }

  //when three seconds has gone by with consistant detection turn on buzzer
  if (timingFlag == true && millis() - startMillis >= period)
  {
    //There has now been three seconds of constant PIR detection
    timingFlag = false;    //disable timing
    bot.sendMessage(CHAT_ID, "Steady Motion detected!!", "");
    Serial.println("Motion Detected");
  }

  
}

A PIR motion sensor (digital, not analogue) and an SSD1306 (I2C).
Shouldn't you ditch the Uno for that?
Leo..

I know the code says PIR but the sensor is actually a GP2Y0A21YK0F, which outputs a range of analog voltages depending on how close an object is.

The Uno's 5V output shouldn't go to NodeMCU's 3V input.
Best/Better to voltage divide the Arduino output.
[You could use the Uno's onboard LED (pin 13 instead of pin 12) as a visible output status monitor.]

Touch D5 to GND or 3V to test the NodeMCU sketch on its own.

Two functions in one - voltage divider and output status.
image

Output voltage of that sensor seems to be 0.4volt to 3volt, which is perfect for the analogue input of the NodeMCU. Sensor power can be tapped from the NodeMCU's 5volt pin.
So I still don't see a need for an Uno/NodeMCU kludge.
Leo..

You are right, however I intend to add a total of 5 analog sensors to the system, hence the need for the uno. I am just testing it out with one sensor first.

Thank you for the idea, I appreciate it. However, I already tried it with the voltage divider and determined that that wasn't the issue. I have been using the uno's LED as a status light as well, which is why I know that the uno pin isn't the issue.

Depends on which sensors, but that can likely be solved with a port expander.
So I still don't see the need for a 2-processor kludge.
Leo..

I did consider this, however using a multiplexer seemed like it would be more work in terms of wiring, and in addition I believe that a multiplexer can only measure one channel at a time, while the system I am creating requires 5 sensors operating simultaneously. Props for the idea though. Currently I am considering using a softwareserial on the uno so that I could transmit data to the nodemcu while still using the SDA and SCL pins for the ssd1306, any thoughts on this?

So you must be using five Unos then.
Because an Uno, like a port expander, can only measure one analogue input at the time.
Leo..

Have you verified (re. my suggestion) that your NodeMCU sketch works?

Yes the nodeMCU sketch works by itself, I have tested it using a non-analog sensor on pin D5.

Wow I did not realize this. However even so the simultaneous aspect is not the most important to me; if there is a short delay between reading sensors that is fine. I am still concerned with how to get data from the uno to the nodemcu.

Upload a sketch to the Uno that does nothing but make pin12 output H 500msec, output L 500msec,...

Upload a sketch to the NodeMCU that does nothing but digitalRead D5 and turns On/Off one of the onboard LEDs (your choice) correspondingly.

Use these sketches to validate your circuitry and understanding.
I used the LED circuit noted previous (see #4)

// thaumic NodeMCU
//

const byte onb = D0;  // the big onboard LED
const byte inc = D5;
byte fromU;

void setup() 
{
  pinMode(onb, OUTPUT);
  digitalWrite(onb, HIGH);
}

void loop() 
{
  fromU = digitalRead(inc);
  if(fromU)
  {
    digitalWrite(onb, LOW);
  }
  else
  {
    digitalWrite(onb, HIGH);
  }
}
// thaumic Uno
//

const byte xmt = 12;

void setup() 
{
  pinMode (xmt, OUTPUT);
  pinMode (13, OUTPUT);  //
  digitalWrite(13,LOW);  //  turn off onboard LED
}

void loop() 
{
  digitalWrite(xmt, LOW);
  delay(1000);
  digitalWrite(xmt, HIGH);
  delay(1000);
}

Is it needed to set the direction of D5-line as input for the NodeMCU?

No - all I/O pins are INPUT by Default.

How are you sure that the init() function has not manipulated the direction of D5-line?

What are you talking about??

Thank you for this code, it helped me work out the issue. I still don't know what the issue was, but instead of measuring the sensor directly in the if statement, I first used an if statement to set a the onb variable to high or low, and then used that in the if statements instead.