Arduino and Python

Good morning everyone, I've come across something particular that I can't solve and I need your help.
I'm using an arduino mega ADK and Python3 on my PC. I would like to have my solar system turned on remotely, I send a serial letter, Arduino detects it and performs an operation. So far so good.
Once this operation is done I would like to run another Python script that reads the system values such as, battery charge, maximum and minimum voltage and so on.
But I noticed that if my system is on and I go to read the values the Arduino program starts again as if I was recharging it again... this thing is very strange, I put some global variables that should remain saved so you can remember if the system is on or off but they erase every time you read them and start from 0 so I realized that the code is recharged every time... I put the Arduino and Python code so whoever wants to help me knows what I'm doing.... :confused:

#include <ModbusMaster.h>
#include <SimpleDHT.h>

#define MAX485_DE      10
#define MAX485_RE_NEG  11
float MaximumInputVoltPVToday = 0;
float MinimumInputVoltPVToday = 0;
float MaximumBatteryVoltToday = 0;
float MinimumBatteryVoltToday = 0;
float ConsumedEnergyToday = 0;
float GeneratedEnergyToday = 0;
float TotalConsumed = 0;
float TotalGenerated = 0;
String StatoCascina = "Spenta";
// instantiate ModbusMaster object
ModbusMaster node;

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}

int Switch = 3;
int pinDHT11 = 2;
SimpleDHT11 dht11(pinDHT11);
int Temp = 0;
int TempMax = 0;
int TempMin = 0;
int Umidita = 0;
int UmidMax = 0;
int Umidmin = 0;
int i = 0;
int Freddo = 10;
byte temperature = 0;
byte humidity = 0;
char Lettera = 'C';
char Dati;
int Detezione = 0;
String FreddoCaldo = "Freddo";

void setup() {
  Serial.begin(9600);
  pinMode(Switch, OUTPUT);
  digitalWrite(Switch, HIGH);
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);

  // Modbus communication runs at 115200 baud
  Serial1.begin(115200);
  Serial2.begin(9600);
  // Modbus slave ID 1
  node.begin(1, Serial1);
  // Callbacks allow us to configure the RS485 transceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}
void DatiPannello (void);
void Temperatura(void);
bool state = false;

void loop() {
  
  uint8_t result;
  uint16_t data[6];
  
  if (Serial.available() > 0) {
    Dati = Serial.read();
    }
    if (Dati == 'M') {
    Serial.println(Detezione);
    DatiPannello();
    Detezione = 1;
    Serial.println(Detezione);
    delay(50);
    }
    if (Dati == 'F') {
      state = true;
      result = node.writeSingleCoil(0x0002, state);
      delay(2000);
      digitalWrite(Switch, LOW);
      StatoCascina = "Accesa";
      Detezione = 2;
      Serial.println(Detezione);
    }
    if (Dati == 'L') {
      digitalWrite(Switch, HIGH);
      state = false;
      result = node.writeSingleCoil(0x0002, state);
      delay(500);
      StatoCascina = "Spenta";
      Detezione = 3;
    }
  delay(50);
  Temperatura ();
  delay(50);
}
void DatiPannello ()
{
    uint8_t resultMain;
    resultMain = node.readInputRegisters(0x3300,19);
  if (resultMain == node.ku8MBSuccess)
  {
    Serial.println(Lettera);
    //Serial.println("------------");
    Serial.print(F("Maximum input volt(PV) today: "));
    MaximumInputVoltPVToday = (node.getResponseBuffer(0x00)/100.0f);
    Serial.print(MaximumInputVoltPVToday);
    Serial.println(F(" V"));
    //-----------------------------------------------
    Serial.print(F("Minimum input volt(PV) today: "));
    MinimumInputVoltPVToday = (node.getResponseBuffer(0x01)/100.0f);
    Serial.print(MinimumInputVoltPVToday);
    Serial.println(F(" V"));
    //---------------------------------------------
    Serial.print(F("Maximum battery volt today: "));
    MaximumBatteryVoltToday = (node.getResponseBuffer(0x02)/100.0f);
    Serial.print(MaximumBatteryVoltToday);
    Serial.println(F(" V"));
    //-----------------------------------------------
    Serial.print(F("Minimum battery volt today: "));
    MinimumBatteryVoltToday = (node.getResponseBuffer(0x03)/100.0f);
    Serial.print(MinimumBatteryVoltToday);
    Serial.println(F(" V"));
    //----------------------------------------------- 
    Serial.print(F("Consumed energy today: "));
    ConsumedEnergyToday = (node.getResponseBuffer(0x04)/100.0f);
    Serial.print(ConsumedEnergyToday);
    Serial.println(F(" Kw"));
    //-----------------------------------------------
    Serial.print(F("Generated energy today: "));
    GeneratedEnergyToday = (node.getResponseBuffer(0x0C)/100.0f);
    Serial.print(GeneratedEnergyToday);
    Serial.println(F(" Kw"));
    //-----------------------------------------------
    Serial.print(F("Total consumed: "));
    TotalConsumed = (node.getResponseBuffer(0x0A)/100.0f);
    Serial.print(TotalConsumed);
    Serial.println(F(" Kw"));
    //-----------------------------------------------
    Serial.print(F("Total generated: "));
    TotalGenerated = (node.getResponseBuffer(0x12)/100.0f);
    Serial.print(TotalGenerated);
    Serial.println(F(" Kw"));
    //-----------------------------------------------
    Serial.print(F("Cascina: "));
    Serial.println(StatoCascina);
    //-----------------------------------------------
    Serial.print(F("Temperatura massima: "));
    Serial.print(TempMax);
    Serial.println(" *C");
    Serial.print(F("Temperatura minima: "));
    Serial.print(TempMin);
    Serial.println(" *C");
    Serial.print(F("Umidita massima: "));
    Serial.print(UmidMax);
    Serial.println(" H");
    Serial.print(F("Umidita minima: "));
    Serial.print(Umidmin);
    Serial.println(F(" H"));
    Serial.println(FreddoCaldo);
  }
}
void Temperatura (){
  // start working...
  Serial2.println("=================================");
  Serial2.println("Sample DHT11...");
  int err = SimpleDHTErrSuccess;
  if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
    Serial2.print("Read DHT11 failed, err="); Serial2.println(err);delay(1000);
    return;
  }
  Serial2.print((int)temperature);
  Temp =  (int)temperature;
  Serial2.print((int)humidity);
  Umidita = (int)humidity;
  // DHT11 sampling rate is 1HZ.
    if(i == 0)
  {
  TempMin = Temp;
  Umidmin = Umidita;
  i = 1;  
  }
    if(Temp > TempMax){
    TempMax = Temp;
  }
  if(Temp < TempMin){
    TempMin = Temp; 
    }
    FreddoCaldo = "Temperatura Normale";
      if(Freddo > TempMin){
     Lettera = 'A';
     FreddoCaldo = "Freddo Portatemi Giu";
     
    }
    if(Umidita > UmidMax){
    UmidMax = Umidita;
  }
  if(Umidita < Umidmin){
    Umidmin = Umidita; 
    }
}

Python:

import serial
import time
lista = []
ser = serial.Serial('COM8',baudrate=9600)#sudo ls /dev/tty*
for n in range(1):
    time.sleep(1)
    ser.write(b'M')
    time.sleep(1)

def getValues():
    arduinoData = ser.readline().decode('utf-8')
    return arduinoData
for n in range(17):
    lista.append(getValues())
                
for stringa in lista:
    print(stringa)
    
file1 = open("ValoriImpianto.txt","w")
for stringa in lista:
   file1.write(stringa)

file1.close()

What I read as a serial:

0

C

Maximum input volt(PV) today: 114.80 V

Minimum input volt(PV) today: 5.68 V

Maximum battery volt today: 13.02 V

Minimum battery volt today: 11.40 V

Consumed energy today: 0.12 Kw

Generated energy today: 0.09 Kw

Total consumed: 15.82 Kw

Total generated: 58.26 Kw

Cascina: Spenta

Temperatura massima: 17 *C

Temperatura minima: 17 *C

Umidita massima: 65 H

Umidita minima: 65 H

Temperatura Normale

1

and the second time I throw it out the same thing, I'd expect to read 1 at the beginning and 1 at the end...

Opening the serial port will reset the Arduino.

Oh, that's no good. A solution not to reset it? I need serial communication...
If I always leave the serial open, do I solve the problem?
But when do I open the Arduino serial or the Python?

If you keep the port open, no problem.
If you disable the auto-reset hardware, you have to remember to hit the reset switch when updating the software.

mozzini97:
Oh, that's no good. A solution not to reset it? I need serial communication...

It seems to me the simplest solution is just to have one Python program that performs two different functions. Then it can open the serial port and keep it open until it is completely finished with the Arduino.

...R

Thank you very much, I was thinking of merging the programs into one too, the only problem is that I'll always have to leave the terminal open to keep the program running inside... But if that's the only way I'm going to do it...

As Robin2 pointed out, you should use a single Python program to do it all. If you need a debug interface, you could use a UART to USB converter to view debug prints from the Arduino to the Serial Monitor.

Also, it would be much more reliable to interface Python with your Arduino using the compatible libraries: pySerialTransfer and SerialTransfer.h.

pySerialTransfer is pip-installable and cross-platform compatible. SerialTransfer.h runs on the Arduino platform and can be installed through the Arduino IDE's Libraries Manager.

Both of these libraries have highly efficient and robust packetizing/parsing algorithms with easy to use APIs.

Example Python Script:

import time
from pySerialTransfer import pySerialTransfer as txfer


if __name__ == '__main__':
    try:
        link = txfer.SerialTransfer('COM17')
        
        link.open()
        time.sleep(2) # allow some time for the Arduino to completely reset
        
        while True:
            send_size = 0
            
            ###################################################################
            # Send a list
            ###################################################################
            list_ = [1, 3]
            list_size = link.tx_obj(list_)
            send_size += list_size
            
            ###################################################################
            # Send a string
            ###################################################################
            str_ = 'hello'
            str_size = link.tx_obj(str_, send_size) - send_size
            send_size += str_size
            
            ###################################################################
            # Send a float
            ###################################################################
            float_ = 5.234
            float_size = link.tx_obj(float_, send_size) - send_size
            send_size += float_size
            
            ###################################################################
            # Transmit all the data to send in a single packet
            ###################################################################
            link.send(send_size)
            
            ###################################################################
            # Wait for a response and report any errors while receiving packets
            ###################################################################
            while not link.available():
                if link.status < 0:
                    if link.status == -1:
                        print('ERROR: CRC_ERROR')
                    elif link.status == -2:
                        print('ERROR: PAYLOAD_ERROR')
                    elif link.status == -3:
                        print('ERROR: STOP_BYTE_ERROR')
            
            ###################################################################
            # Parse response list
            ###################################################################
            rec_list_  = link.rx_obj(obj_type=type(list_),
                                     obj_byte_size=list_size,
                                     list_format='i')
            
            ###################################################################
            # Parse response string
            ###################################################################
            rec_str_   = link.rx_obj(obj_type=type(str_),
                                     obj_byte_size=str_size,
                                     start_pos=list_size)
            
            ###################################################################
            # Parse response float
            ###################################################################
            rec_float_ = link.rx_obj(obj_type=type(float_),
                                     obj_byte_size=float_size,
                                     start_pos=(list_size + str_size))
            
            ###################################################################
            # Display the received data
            ###################################################################
            print('SENT: {} {} {}'.format(list_, str_, float_))
            print('RCVD: {} {} {}'.format(rec_list_, rec_str_, rec_float_))
            print(' ')
    
    except KeyboardInterrupt:
        link.close()
    
    except:
        import traceback
        traceback.print_exc()
        
        link.close()

Example Arduino Sketch:

#include "SerialTransfer.h"


SerialTransfer myTransfer;


void setup()
{
  Serial.begin(115200);
  myTransfer.begin(Serial);
}


void loop()
{
  if(myTransfer.available())
  {
    // send all received data back to Python
    for(uint16_t i=0; i < myTransfer.bytesRead; i++)
      myTransfer.txBuff[i] = myTransfer.rxBuff[i];
    
    myTransfer.sendData(myTransfer.bytesRead);
  }
}

On the Arduino side, you can use myTransfer.txObj() and myTransfer.rxObj() to copy values to the library's RX buffer and parse multi-byte variables out of the library's TX buffer.

For theory behind robust serial communication, check out the tutorials Serial Input Basics and Serial Input Advanced.

Thanks a lot for the advice, I think my programming level is not so advanced to use these libraries... I was able to solve the problem to read the data, the only problem is that I can't synchronize the data sending from Arduino with the Python reading so I don't always have the complete information.
Is there a function like Serial.available() for Python? so when it starts receiving data I can write it in the text file :slight_smile:

mozzini97:
I think my programming level is not so advanced to use these libraries...

Being a beginner programmer is all the more reason to use the libraries!! The correct use of the libraries will easily solve your problem without making you muddle through learning advanced concepts of serial data handling....

The libraries automatically synchronize the Arduino and Python to each other.