Cannot send Serial data from python to Arduino Uno

I'm trying to send Serial Data from python to Arduino Uno. But I don't understand why it need add time.sleep(2), serial data will be send.
Code arduino uno:

#define LED_pin 12

void setup(){
  Serial.begin(9600);
  pinMode(LED_pin, OUTPUT);
  digitalWrite(LED_pin, HIGH);
  // Serial.setTimeout(1);
}

void loop(){

  if(Serial.available()>0){
    String msg=Serial.readString(); 
 
    if (msg =="ON"){
      digitalWrite(LED_pin, LOW);
      delay(5000);
      digitalWrite(LED_pin, HIGH);                
    }
  }
}

Code python
Case 1: Cannot send

import serial
import time

arduino = serial.Serial(port='COM4', baudrate=9600)        
command = "ON"
# time.sleep(2)

arduino.write(command.encode('utf-8'))

Case 2: Serial data is sent successfully.

import serial
import time

arduino = serial.Serial(port='COM4', baudrate=9600)        
command = "ON"
time.sleep(2)
arduino.write(command.encode('utf-8'))

Thanks

When a program opens the Serial port to the Uno it causes the Uno to reset so I suspect that adding the sleep() allows for the Uno to reset and be ready to receive data

1 Like

Thanks UKHeliBob,
Because time.sleep(2) will make my program delay. so I'm find way to don't use it.
Do you have any solution for it?

I agree with @UKHeliBob, IMHO that's the problem. The solution is to avoid opening the serial port every time. But I have some more advice to give to our friend.

After repeating again "never use String variables on Arduino UNO!", let me also say to the OP what I everytime say when dealing communications: if it's a communication between "programs" and not "humans", why use "human-like" strings?

Computers handle bytes more natively and easily, why send a "human readable string" with the letters "ON" instead of a byte as "command" (e.g. 1 for "turn LED on" and 0 for "LED off")?

Then, another common issue is the use of large delays, preventing Arduino from doing anything more in the meantime, start using millis() function.
And better use "const" instead of "#define", and constants should be in all uppercase for conventional code formatting (like "HIGH" and "LOW"...).

Thus, Arduino code can be simply:

const byte LED_PIN = 12;

unsigned long t0 = 0;

void setup(){
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
}

void loop(){
  if(Serial.available()>0){
    char cmd =Serial.read(); 
    if (cmd == 1){
      digitalWrite(LED_PIN, LOW);
      t0 = millis();
    }
  }
  if (t0 > 0 && millis()-t0 > 5000) {
      digitalWrite(LED_PIN, HIGH);
      t0 = 0;
  }
}

What is the real purpose of the project ?
What is the Python script really doing ?

It would be normal to open the serial interface as part of the script start up code and at some time in the future, send the serial data

If you really want to prevent the Uno from resetting when the Serial port is opened then take a look at Uno, prevent reset when open Serial monitor

@UKHeliBob Thanks a lot.
Actually, I'm develop API Server using FastAPI by Python.
My purpose that if I request API success, it will send data via serial to Arduino. I also try but still failed.
Case 1: If I use this code, Python script is working well and Arduino also working well but my program is delayed.

from fastapi import FastAPI
import uvicorn
import time
import serial
    
app = FastAPI()


@app.get("/")
async def root():
    arduino = serial.Serial(port='COM4', baudrate=9600, timeout=.5)
    time.sleep(2)
    command="ON"
    arduino.write(command.encode('utf-8'))
    return {"message": "Hello World"}


if __name__ == "__main__":
    uvicorn.run("APIServerTPR:app", host="192.168.30.39", port=5000, log_level="info")

Case 2: If I use this code, Python script is occured an error:

from fastapi import FastAPI


import uvicorn
import time

import serial
arduino = serial.Serial(port='COM4', baudrate=9600, timeout=.5)
time.sleep(2)
    
app = FastAPI()


@app.get("/")
async def root():
    command="ON"
    arduino.write(command.encode('utf-8'))
    return {"message": "Hello World"}


if __name__ == "__main__":
    uvicorn.run("APIServerTPR:app", host="192.168.30.39", port=5000, log_level="info")

Error:

Traceback (most recent call last):
  File "D:\TECHPRO\PythonLearning\TPR-DCS\APIServerTPR.py", line 22, in <module>
    uvicorn.run("APIServerTPR:app", host="192.168.30.39", port=5000, log_level="info")
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\site-packages\uvicorn\main.py", line 578, in run
    server.run()
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\site-packages\uvicorn\server.py", line 61, in run
    return asyncio.run(self.serve(sockets=sockets))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 650, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\site-packages\uvicorn\server.py", line 68, in serve
    config.load()
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\site-packages\uvicorn\config.py", line 473, in load
    self.loaded_app = import_from_string(self.app)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\site-packages\uvicorn\importer.py", line 21, in import_from_string
    module = importlib.import_module(module_str)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "D:\TECHPRO\PythonLearning\TPR-DCS\APIServerTPR.py", line 8, in <module>
    arduino = serial.Serial(port='COM4', baudrate=9600, timeout=.5)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\site-packages\serial\serialwin32.py", line 33, in __init__
    super(Serial, self).__init__(*args, **kwargs)
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\site-packages\serial\serialutil.py", line 244, in __init__
    self.open()
  File "C:\Users\toanh\AppData\Local\Programs\Python\Python311\Lib\site-packages\serial\serialwin32.py", line 64, in open
    raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError()))
serial.serialutil.SerialException: could not open port 'COM4': PermissionError(13, 'Access is denied.', None, 5)

Thanks

I know little or nothing about Python so I am unable to provide help with that error

I don't know Python enough to tell you why you get that error trace, but based on the code differences, I suppose you either need to import "pyserial" instead of "serial" (as far as I can remember, I have always seen "pyserial"!) or can't open a serial port that way (outside that "async def").
And this is probably not the cause, but also remember the OS could set a different COM port number when the USB is inserted in a different USB port...

EDIT: googling around I found this:

serial has nothing to do with serial buses. It does not coexist well with pyserial because they share the same import name. Do not install both in the same environment.

See HERE.
What is your environment and what are the installed libraries? Those are information a Python programmer should know to help you more than me (I can't go further with this topic).

@docdoc & UKHeliBob Thank you so much.
My problem is resolved.
I initialed a class to a file and then import it into main program.
It working well while could not explain why.
Thanks

Happy to read you solved the problem.
But, if you need or want to go on with Python I think you should try to understand why it's working correctly now, based on what you changed. And I haven't really got what you did, anyway, so maybe posting the working code could help others with similar problems to get a clue...

@docdoc Thanks
This is my code changed

  1. Arduino.py
import serial
import time

class Adruino:
    def __init__(self):
      self.ard = serial.Serial(port='COM4', baudrate=9600, timeout=.5)
      time.sleep(2)

arduino = Adruino()
  1. Main.py
from fastapi import FastAPI
import uvicorn
import time
from model.Arduino import arduino

app = FastAPI()

@app.get("/")
async def root():
    # arduino = serial.Serial(port='COM4', baudrate=9600, timeout=.5)
    # time.sleep(2)
    command="ON"
    arduino.ard.write(command.encode('utf-8'))
    return {"message": "Hello World"}
if __name__ == "__main__":
    uvicorn.run("APIServerTPR:app", host="192.168.30.39", port=5000, log_level="info")
  1. Arduino.io
#define LED_PIN 12

void setup(){
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  // Serial.setTimeout(1);
}

void loop(){

  if(Serial.available()>0){
    String msg=Serial.readString(); 
 
    if (msg =="ON"){
      digitalWrite(LED_PIN, LOW);
      delay(5000);
      digitalWrite(LED_PIN, HIGH);                
    }

  }

}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.