Arduino Doesn't Communicate over Serial until I Run Serial Monitor "screen"

I am having a bit of a bizarre problem that I can now reliably replicate. I have an Arduino sketch that reads from the serial port, and based on the input, turns on/off or changes the color of the attached LED strip. The Arduino is attached to a Raspberry Pi 3, from which I send data on its serial port to the Arduino via /dev/Arduino, 9600baud.

When the Raspberry Pi boots, it doesn't matter how long I wait, the Arduino does not receive the message. I use the following snippet to write to the Pi's serial port. Each message is only 1 byte (a number, but represented as an ASCII character).

import serial
with serial.Serial('/dev/Arduino', 9600, timeout=1) as port:
    port.write(str(1).encode())

I have discovered that once I open a monitor to the serial port using "screen", I can issue commands to the Arduino and it lights the LED strip correctly. Everything works well until I reboot the Raspberry Pi.

It seems like some buffer needs to flushed or something and I have tried using port.flush() both before and after port.write() and it hasn't worked.

What are some things I can try?

A simplified version of my sketch is below:

#include "Wire.h"
#include "Adafruit_NeoPixel.h"
 
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_LEDS, PIN, NEO_RGBW + NEO_KHZ800);

void setup() {
	Serial.begin(9600);
	strip.begin();
	loop();
}

void loop() {

	char incomingByte;
	while(true) {    // strip.show() is run within each LED function
		if (Serial.available() > 0) {
			incomingByte = Serial.read();
			switch(incomingByte) {
				case '0':
					// Machine ready.
					glow_white();
					break;
				case '1':
					// Machine badness.
					glow_red();
					break;
				case '2':
					// Printing
					rainbow();
					break;
				case '3':
					// Machine done.
					glow_green();
					break;
				case '4':
					// Machine off
					led_off();
					break;
				default:
					glow_white();
					break;
			}
		}
		wait();
	}
}


static void wait() {
  delay(10);
}

I suspect you may need to enable DTR or RTS (or both) in your Python program

...R

void setup() {
	Serial.begin(9600);
	strip.begin();
	loop();
}

Why call loop() from setup when loop() is already slated to run after setup()?

You might want to experiment with a delay of some x amount of time after the serial begin, it takes a few moments of time to start serial. I'd set a GPIO to a state, high or low your choice, from the RPi to the Arduino to signify to the Arduino that there was data available. After the data was processed, I sent another GPIO signal to the RPi so it can clear the first state set and send new data.

What breaks the loop of while(true)? The breaks step out of the switch case but the while(true) loop does not stop running preventing loop() from doing its other thing do's.

What are you using for a level shifting?