Bogdan's Docs

Table of Contents

Table of Contents

  • Scurta introducere in Python
    • Ce e Python?
    • Ce este PIP?
    • Exemplu de Program #1
      • Ce este shebang?
      • Cum import module in Python?
      • Cum definesc o functie in Python?
      • Ce este un context?
      • Ce e un DataFrame?
      • Ce este Pathlib?
    • Exemplu de Program #2

Ideas

  • Artificial Intelligence
    • Bond Pricing
    • Kubernetes Inference
    • Knowledge Bot
    • Ready to Use Models
    • Satellite Damage Detection

Curs IoT si AI (ro) Resources

  • Links
    • Artificial Intelligence
  • Recipes
    • MacOS
Bogdan's Docs
Docs » iot-si-ai:scurta-introducere-in-python

Scurta introducere in Python

Ce e Python?

Python este un limbaj de programare interpretat, de nivel înalt, care a fost creat în anii 1990 de Guido van Rossum. Este un limbaj generalist, ceea ce înseamnă că poate fi utilizat pentru o gamă largă de aplicații, de la dezvoltarea de site-uri web și aplicații de desktop până la analiza datelor și inteligența artificială.

Python este un limbaj interpretat, ceea ce înseamnă că nu necesită compilare. În schimb, codul este interpretat direct de către un interpretor Python atunci când este rulat. Python are o sintaxă simplă și elegantă, ceea ce face ca codul să fie ușor de citit și de înțeles. De asemenea, Python are o vastă bibliotecă standard și o mulțime de module terțe disponibile, care îi permit să fie utilizat pentru o varietate de sarcini diferite.

Iată câteva particularități importante ale limbajului de programare Python:

  • Simplu și ușor de învățat: Python are o sintaxă simplă și concisă, ceea ce îl face ușor de învățat și de utilizat. De asemenea, are o bibliotecă standard bogată, ceea ce înseamnă că multe funcții și metode comune sunt deja disponibile în limbaj.
  • Interprelat: Python este un limbaj interpretat, ceea ce înseamnă că codul poate fi executat direct, fără a fi compilat în prealabil.
  • Orientat pe obiecte: Python este un limbaj orientat pe obiecte, ceea ce înseamnă că toate datele și funcțiile sunt puse în obiecte și metode.
  • Versatil: Python este utilizat într-o gamă largă de domenii, inclusiv dezvoltarea web, analiza datelor, inteligența artificială, automatizarea și multe altele.
  • Open source: Python este open source, ceea ce înseamnă că poate fi folosit gratuit și că codul sursă poate fi modificat și distribuit.
  • Portabil: Python rulează pe multe platforme, inclusiv Windows, macOS și Linux, și poate fi utilizat pentru dezvoltarea aplicațiilor desktop, web și mobile.
  • Comunitate activă: Python are o comunitate largă și activă de dezvoltatori și utilizatori, ceea ce înseamnă că există multe resurse disponibile pentru începători și experți.

Sintaxa limbajului de programare Python diferă semnificativ de cea din C++. Iată câteva exemple:

  • Python nu necesită acolade ({}) pentru a defini blocurile de cod. În schimb, Python folosește indentarea pentru a marca blocurile de cod. De exemplu, în C++ putem scrie:
if (x > 0) {
    cout << "x este pozitiv" << endl;
}

În Python, aceeași instrucțiune ar arăta astfel:

if x > 0:
    print("x este pozitiv")
  • Python nu necesită punct și virgulă la sfârșitul fiecărei instrucțiuni. În C++, fiecare instrucțiune trebuie să se termine cu un punct și virgulă (😉. În Python, o instrucțiune se termină atunci când ajunge la sfârșitul liniei. De exemplu, în C++ putem scrie:
x = 5;
y = 10;
cout << x + y << endl;

În Python, aceeași instrucțiune ar arăta astfel:

x = 5
y = 10
print(x + y)
  • În Python, variabilele nu trebuie să fie declarate înainte de a fi utilizate. În C++, trebuie să declarăm variabilele înainte de a le utiliza. De exemplu, în C++ putem scrie:
int x;
x = 5;

În Python, aceeași instrucțiune ar arăta astfel:

x = 5
  • Python este un limbaj de programare interpretat, ceea ce înseamnă că codul este interpretat linie cu linie, pe măsură ce este executat. În C++, codul este compilat înainte de a fi executat.

Acestea sunt doar câteva diferențe semnificative între sintaxa Python și cea din C++.

Ce este PIP?

PIP este un sistem de management al pachetelor pentru Python. El este folosit pentru a instala și gestiona pachete de cod Python care sunt disponibile în registrul pachetelor PyPI (Python Package Index).

Prin intermediul PIP, utilizatorii pot instala pachete Python într-un mod simplu și eficient, astfel încât acestea să poată fi utilizate în aplicațiile lor. PIP poate fi utilizat pentru a instala pachete, pentru a le actualiza, pentru a le dezinstala și pentru a lista toate pachetele instalate.

Pachetele Python sunt pachete de cod care conțin module, funcții și alte resurse care pot fi utilizate în aplicațiile Python. Există o mulțime de pachete Python disponibile în PyPI, care acoperă o gamă largă de domenii, inclusiv știință de date, dezvoltare web, automatizare, securitate și multe altele.

PIP se poate folosi la:

  • Instalarea unei biblioteci: PIP poate fi folosit pentru a instala biblioteci Python, precum NumPy sau Pandas. Pentru a instala NumPy, de exemplu, puteți folosi comanda pip install numpy.
  • Actualizarea unei biblioteci: PIP poate fi folosit pentru a actualiza biblioteci existente la versiuni mai recente. De exemplu, pentru a actualiza NumPy, puteți folosi comanda pip install –upgrade numpy.
  • Generarea unei liste de biblioteci instalate: PIP poate fi folosit pentru a genera o listă a bibliotecilor Python instalate pe sistemul dvs. cu comanda pip list.
  • Salvarea unei liste de biblioteci instalate: PIP poate fi folosit pentru a salva o listă a bibliotecilor instalate pe sistemul dvs. într-un fișier text cu comanda pip freeze > requirements.txt. Acest fișier poate fi ulterior folosit pentru a reinstala aceleași biblioteci pe un alt sistem.
  • Instalarea bibliotecilor dintr-un fișier de cerințe: PIP poate fi folosit pentru a instala toate bibliotecile specificate într-un fișier de cerințe cu comanda pip install -r requirements.txt. Această comandă va instala toate bibliotecile specificate în fișierul requirements.txt.

Exista o serie de biblioteci Python care pot fi instalate cu PIP si care sunt utilizate frecvent in dezvoltarea de aplicatii. Iata cateva exemple:

  • NumPy: este o biblioteca Python pentru calcul numeric, care permite utilizatorilor sa lucreze cu matrici si matrice multidimensionale. Este utilizata in analiza de date, machine learning si alte aplicatii de stiinta a datelor. pip install numpy
  • Pandas: este o biblioteca Python pentru analiza de date, care permite utilizatorilor sa lucreze cu date structurate in tabele si serii. Este utilizata in analiza de date si in alte aplicatii de stiinta a datelor. pip install pandas
  • Matplotlib: este o biblioteca Python pentru vizualizarea datelor, care permite utilizatorilor sa creeze grafice si diagrame. Este utilizata in analiza de date si in alte aplicatii de stiinta a datelor. pip install matplotlib
  • PyTorch: este o bibliotecă open source pentru mașină și învățare profundă (machine learning și deep learning) dezvoltată de Facebook. A fost lansată în 2016 și este scrisă în Python, cu suport pentru calculul pe GPU. pip install torch
  • Scikit-learn: este o biblioteca Python pentru machine learning, care permite utilizatorilor sa implementeze algoritmi de machine learning si sa creeze modele de machine learning. Este utilizata in dezvoltarea de aplicatii AI si machine learning. pip install scikit-learn

Exemplu de Program #1

#!/usr/bin/env python3
import argparse
import datetime
import time
from pathlib import Path
 
import pandas as pd
import serial
 
 
def read_serial_once(df: pd.DataFrame) -> pd.DataFrame:
    with serial.Serial("/dev/ttyUSB0", timeout=1) as fp:
        time.sleep(5)  # Arduino gets reset when port is opened
        fp.write("r".encode("ascii"))
        data = fp.readline().decode("ascii").strip()
    df.loc[len(df)] = [datetime.datetime.now()] + [float(value) for value in data.split(",")]
    return df
 
 
def read_serial_batch(path: Path, batch_length: int) -> None:
    df = pd.DataFrame(
        columns=[
            "datetime",
            "light_value",
            "sound_value",
            "temperature_1_value",
            "humidity_value",
            "temperature_2_value",
            "pressure_value",
            "altitude_value",
            "acceleration_x",
            "acceleration_y",
            "acceleration_z",
        ]
    )
 
    file_path = path / datetime.datetime.now().strftime("%Y%m%d-%H%M%S.csv")
    while len(df) < batch_length:
        _ = read_serial_once(df)
    df.to_csv(file_path, index=False)
 
 
def parse_args(args: list) -> argparse.Namespace:
    script_name = Path(__file__).stem
    parser = argparse.ArgumentParser(
        prog=script_name,
        description="Read data from Arduino",
        epilog=f"{script_name} --batch-length 12 --output-path /home/pi/weather",
    )
    parser.add_argument(
        "-b",
        "--batch-length",
        type=int,
        default=12,
        help="Number of records to read in a batch",
    )
 
    def validate_path(path: str) -> Path:
        path = Path(path)
        if path.exists() and not path.is_dir():
            raise argparse.ArgumentTypeError(f"Path {path} is not a directory")
        return path
 
    parser.add_argument(
        "-o",
        "--output-path",
        type=validate_path,
        default=Path("/home/pi/weather"),
        help="Path to write output files",
    )
    args = parser.parse_args(args)
    if not args.output_path.exists():
        args.output_path.mkdir(parents=True, exist_ok=True)
    return args
 
 
def main(args: list = None) -> None:
    args = parse_args(args)
    while True:
        read_serial_batch(path=args.output_path, batch_length=args.batch_length)
 
 
if __name__ == "__main__":
    main()

Ce este shebang?

#!/usr/bin/env python3

Linia #!/usr/bin/env python3 de la începutul unui script Python se numește shebang și este folosită pentru a indica sistemului de operare cum să ruleze scriptul.

În particular, #!/usr/bin/env este o indicație pentru sistemul de operare să folosească primul program disponibil în $PATH care se potrivește cu argumentul de după env. În acest caz, argumentul este python3, ceea ce înseamnă că sistemul de operare va căuta python3 în $PATH.

Acest shebang este folosit pentru a asigura faptul că scriptul este rulat cu Python 3, iar nu cu Python 2 sau altă versiune de Python care ar putea fi instalată pe sistem. De asemenea, acesta face scriptul portabil, deoarece sistemul de operare va căuta Python 3 în loc să folosească o cale absolută către interpretor.

Cum import module in Python?

import argparse

În Python, sintaxa import argparse indică importarea modulului argparse. Modulul argparse este o bibliotecă standard din Python care permite programatorilor să scrie programe cu argumente de linie de comandă. Aceasta oferă o metodă simplă și elegantă de a procesa argumente de linie de comandă în programele Python.

import datetime si import time

Modulele datetime și time din Python sunt folosite pentru a lucra cu date și timp.

Modulul datetime permite lucrul cu date și timp și include clase precum date, time, datetime, timedelta și altele. Acestea permit reprezentarea și manipularea datelor și timpului, inclusiv formatări, extragerea informațiilor precum ziua săptămânii sau numărul de săptămâni dintre două date, precum și aritmetică cu date și timp.

De exemplu, putem folosi modulul datetime pentru a crea un obiect datetime care reprezintă data și timpul curent:

import datetime
 
now = datetime.datetime.now()
print(now)

Acesta va afișa data și ora curentă în formatul YYYY-MM-DD HH:MM:SS.mmmmmm.

Modulul time este folosit pentru a măsura timpul, în special pentru a măsura durata de timp dintre două evenimente. Acesta include funcții precum time(), sleep(), perf_counter() și altele, care permit măsurarea timpului și crearea unor întârzieri.

De exemplu, putem folosi modulul time pentru a măsura timpul necesar pentru a executa o anumită bucată de cod:

import time
 
start_time = time.perf_counter()
 
# Bucată de cod care trebuie măsurată
time.sleep(1)
 
end_time = time.perf_counter()
 
print(f'Timpul necesar pentru executarea bucatii de cod este de {end_time - start_time:.2f} secunde.')

Acesta va afișa durata de timp necesară pentru execuția bucatii de cod în secunde, cu două zecimale.

from pathlib import Path

Linia from pathlib import Path in Python importă clasa Path din modulul pathlib în programul tău Python. Clasa Path este folosită pentru a lucra cu căi de fișiere și directoare într-un mod independent de platformă. Aceasta oferă o alternativă modernă și mai intuitivă la modulele mai vechi precum os și os.path pentru manipularea cailor de fișiere și directoare în Python. De exemplu, puteți utiliza clasa Path pentru a obține calea către directorul de lucru curent, pentru a verifica dacă un fișier există sau pentru a crea un nou fișier sau director.

import pandas as pd

Sintaxa import pandas as pd este utilizată în Python pentru a importa biblioteca Pandas și pentru a crea un alias “pd” pentru a se referi mai ușor la această bibliotecă în cod. Pandas este o bibliotecă populară în Python pentru analiza și manipularea datelor, iar utilizarea unui alias ușurează scrierea codului și îmbunătățește citibilitatea acestuia. De exemplu, în loc de a scrie pandas.DataFrame pentru a crea un DataFrame, putem scrie pd.DataFrame, care este mai scurt și mai ușor de citit.

import serial

Modulul pyserial (denumirea pe care o recunoaște PIP) este utilizat în Python pentru a permite comunicarea serială cu dispozitivele externe care utilizează porturi seriale. Acest modul oferă o modalitate convenabilă de a controla aceste dispozitive și de a efectua transmiterea și recepționarea de date prin portul serial.

În cadrul proiectelor Python care implică dispozitive externe, cum ar fi roboți, senzori, monitoare sau alte dispozitive, modulul pyserial poate fi utilizat pentru a comunica cu aceste dispozitive prin portul serial. Acesta permite utilizatorilor să trimită și să primească date prin portul serial folosind un set de metode simple și ușor de utilizat.

Cum definesc o functie in Python?

def read_serial_once(df: pd.DataFrame) → pd.DataFrame:

Linia def read_serial_once(df: pd.DataFrame) → pd.DataFrame: reprezinta o functie in Python. Mai exact, aceasta linie defineste o functie numita read_serial_once care primeste un parametru de tipul DataFrame din biblioteca pandas si returneaza un obiect DataFrame tot din biblioteca pandas.

Partea df: pd.DataFrame specifica ca parametrul functiei este numit df si este de tipul DataFrame din biblioteca pandas. Acest lucru poate ajuta la validarea tipului parametrului in interiorul functiei si poate oferi informatii utile cu privire la tipul asteptat de date pentru acest parametru.

Partea → pd.DataFrame specifica tipul de date returnat de functie, in acest caz un DataFrame din biblioteca pandas. Aceasta specificatie poate ajuta la validarea tipului de date returnat de functie si la furnizarea de informatii utile despre formatul datelor returnate.

Adnotările în Python sunt o metodă de a furniza informații suplimentare despre tipul de date așteptat pentru argumentele și valoarea returnată de o funcție. Acestea sunt scrise într-un stil de adnotare și sunt plasate după numele argumentelor și a valorii returnate.

De exemplu, o adnotare de funcție ar putea arăta astfel:

def add_numbers(a: int, b: int) -> int:
    return a + b

În acest exemplu, adnotarea a: int și b: int indică faptul că argumentele așteptate de funcție trebuie să fie de tip întreg. Adnotarea → int indică faptul că funcția va returna un întreg. Adnotările nu afectează comportamentul funcției, dar pot fi utile în documentarea codului și în validarea tipului de date.

Ce este un context?

with serial.Serial(“/dev/ttyUSB0”, timeout=1) as fp:

Un context in Python se refera la un mediu controlat pentru rularea codului, care asigura o anumita functionalitate pentru codul dintr-un bloc de cod specific. In mod obisnuit, contextul este creat folosind instructiunea with, care asigura ca toate resursele alocate in blocul de cod sunt gestionate corect.

Un exemplu de utilizare a contextului este in manipularea fisierelor. Cand se lucreaza cu un fisier, este important sa se asigure ca acesta este inchis la sfarsitul operatiunii pentru a preveni pierderea de date sau coruperea fisierului. Prin crearea unui context cu instructiunea with, se poate asigura automat inchiderea fisierului la finalul blocului de cod, indiferent de erori sau exceptii care pot aparea in timpul executiei.

Un alt exemplu de utilizare a contextului este in conexiunea la o baza de date. Crearea unui context cu o conexiune la baza de date poate asigura ca aceasta este inchisa automat la finalul blocului de cod si ca tranzactiile sunt gestionate corect.

Linia with serial.Serial(“/dev/ttyUSB0”, timeout=1) as fp: din Python creează un context în care se deschide o conexiune serială cu un dispozitiv conectat la portul /dev/ttyUSB0.

Modulul pyserial din Python permite comunicarea cu dispozitive seriale precum senzori, microcontrolere, Arduino și altele. Funcția Serial() din acest modul este utilizată pentru a inițializa o conexiune serială cu un dispozitiv. Argumentele acestei funcții sunt de obicei portul serial la care dispozitivul este conectat și alte setări precum viteza baud, numărul de biți de date, tipul de paritate și multe altele. În exemplul dat, se deschide o conexiune cu un dispozitiv conectat la portul /dev/ttyUSB0 cu un timeout (timpul maxim cât se așteaptă pentru conexiune să devină activă) de 1 secundă.

Prin utilizarea instrucțiunii with, conexiunea serială se va închide automat la sfârșitul blocului with, fără a mai fi nevoie să apelați explicit funcția close() pe obiectul de conexiune serială. Obiectul de conexiune serială este returnat și atribuit variabilei fp, ceea ce permite utilizarea ulterioară a acestuia pentru a citi și/sau scrie date de la/la dispozitivul conectat.

time.sleep(5)

Linia time.sleep(5) in Python determina procesul sa astepte timp de 5 secunde inainte de a continua executia codului. Aceasta functie din modulul time este folosita pentru a introduce o intarziere in executia unui program, ceea ce poate fi util in anumite situatii, cum ar fi asteptarea ca o operatie de retea sa se incheie sau pentru a controla rata de procesare a datelor.

fp.write(“r”.encode(“ascii”))

În Python, atunci când variabila fp reprezintă un port serial deschis cu ajutorul modulului pyserial, apelul metodei write() cu argumentul “r”.encode(“ascii”) va trimite un byte cu valoarea 0x72 (în codul ASCII), reprezentând caracterul r, prin portul serial. În general, metoda write() este folosită pentru a trimite date prin portul serial. Pentru a trimite alte date, se poate înlocui caracterul r cu orice alt caracter sau șir de caractere.

“r” reprezintă un caracter, iar metoda .encode() converteste caracterul dintr-un obiect de tip string într-un obiect de tip bytes, codificându-l în ascii. Acest lucru este necesar deoarece portul serial comunică în bytes, nu în caractere. Caracterul “r” reprezintă p comandă pentru a citi date de pe portul serial, iar trimițând această comandă în format bytes, aceasta va fi interpretată corect de către dispozitivul conectat la portul serial.

data = fp.readline().decode(“ascii”).strip()

Linia data = fp.readline().decode(“ascii”).strip() din Python citeste o linie de date de la portul serial deschis in variabila data. Mai exact, functia readline() citeste o linie de date de la portul serial, functia decode() transforma sirul de octeti (bytes) in sir de caractere, iar functia strip() elimina orice spatiu alb sau alte caractere de control de la inceputul si sfarsitul sirului.

In general, aceste functii sunt folosite pentru a prelucra si formata datele primite de la portul serial in formatul dorit. Functia decode() transforma datele primite, care sunt in format binar, in format text pentru a putea fi manipulate. Functia strip() este folosita pentru a elimina orice spatiu alb sau alte caractere de control, care pot aparea din diverse motive, cum ar fi erori de transmisie sau caractere de padding, si care nu sunt utile pentru procesare.

Ce e un DataFrame?

În Python, un DataFrame este o structură de date tabulară, similară cu o tabelă dintr-o bază de date sau o foaie de calcul din Excel. Este definit în biblioteca pandas și este unul dintre cele mai utilizate obiecte în analiza de date și știința datelor.

Un DataFrame este compus din rânduri și coloane, iar fiecare coloană poate avea un tip de date diferit. Se poate utiliza pentru a stoca date cu mai multe dimensiuni, cum ar fi o colecție de serii (obiecte pandas de tipul Series). pandas permite utilizatorilor să efectueze operații de analiză de date, cum ar fi agregarea, filtrele, transformarea, îmbinarea și vizualizarea datelor din DataFrame.

De exemplu, se poate utiliza un DataFrame pentru a stoca informații despre clienții unei companii, cum ar fi numele, adresa, venitul și data ultimei achiziții. Utilizând DataFrame, se pot aplica diverse operații de analiză pentru a descoperi modele și tendințe în datele clienților.

Pentru a crea un DataFrame cu aceste coloane, putem utiliza biblioteca pandas din Python. Mai intai, trebuie sa importam biblioteca folosind comanda import pandas as pd. Apoi, putem defini un dictionar in care cheile sunt numele coloanelor, iar valorile sunt listele cu valorile corespunzatoare pentru fiecare coloana. Acest dictionar poate fi convertit apoi intr-un DataFrame folosind functia pd.DataFrame().

Iata un exemplu de cod care creaza un DataFrame cu coloane potrivite datelor culese din Seeduino:

import pandas as pd
from datetime import datetime
 
# Definirea dictionarului cu date
data_dict = {
    "datetime": [datetime.now()],
    "light_value": [0.0],
    "sound_value": [0.0],
    "temperature_1_value": [0.0],
    "humidity_value": [0.0],
    "temperature_2_value": [0.0],
    "pressure_value": [0.0],
    "altitude_value": [0.0],
    "acceleration_x": [0.0],
    "acceleration_y": [0.0],
    "acceleration_z": [0.0]
}
 
# Convertirea dictionarului intr-un DataFrame
df = pd.DataFrame(data_dict)
 
# Afisarea DataFrame-ului
print(df)

Acest cod va afisa un DataFrame cu o singura linie, care contine data si ora curenta in coloana datetime, iar in celelalte coloane sunt valori initiale de 0.0. Aceste valori pot fi actualizate mai tarziu in program prin adaugarea de noi linii la DataFrame.

Revenind la programul pe care-l analizam,

df.loc[len(df)] = [datetime.datetime.now()] + [float(value) for value in data.split(“,”)]

Linia de cod df.loc[len(df)] = [datetime.datetime.now()] + [float(value) for value in data.split(“,”)] este utilizată pentru a adăuga o nouă intrare într-un obiect DataFrame din biblioteca pandas.

Mai exact, prima parte [datetime.datetime.now()] adaugă data și ora curentă a sistemului în coloana DataFrame-ului cu numele 0, iar a doua parte [float(value) for value in data.split(“,”)] adaugă datele care sunt trimise prin portul serial în DataFrame, fiecare valoare fiind convertită într-un float. Splitarea datelor se face folosind separatorul ,.

În mod specific, acest cod adaugă o nouă intrare în DataFrame folosind metoda .loc. Valoarea de la indexul nou introdus este [datetime.datetime.now()] + [float(value) for value in data.split(“,”)]. Prin adăugarea acestei noi intrări, DataFrame-ul nostru crește cu o nouă linie.

În linia anterioară, [float(value) for value in data.split(“,”)] este un exemplu de list comprehension in Python. List comprehension este o sintaxa concisa pentru a crea liste. Aceasta permite definirea unei liste intr-o singura linie de cod prin iterarea prin elementele unei alte liste sau a unui obiect iterabil, aplicand o expresie sau un filtru pe fiecare element si colectand rezultatele intr-o noua lista. Sintaxa generala este

[expression for item in iterable if condition]

expression este valoarea care se adauga la lista, item este elementul iterabil, iterable este obiectul iterabil din care se preiau elementele, iar condition este o expresie optionala care permite filtrarea elementelor.

In exemplul de cod mentionat, [float(value) for value in data.split(“,”)] inseamna ca se creeaza o lista de numere float, prin conversia fiecarui element din string-ul data in float. Mai exact, se sparge string-ul data in elemente separate folosind , drept separator, si apoi se itereaza prin fiecare element, transformandu-l in float. Rezultatul este o lista de numere float.

Mergând mai departe, funcția read_serial_batch creeaza un fisier CSV ce contine datele citite de la un port serial, inregistrandu-le sub forma unui DataFrame cu numele de coloane specificate si cu un numar de inregistrari specificat de parametrul batch_length. Pentru a realiza aceasta, functia va chema repetat functia read_serial_once() si va adauga datele citite in DataFrame-ul df pana cand acesta va avea lungimea specificata prin batch_length. Dupa ce DataFrame-ul este completat cu date, acesta va fi salvat intr-un fisier CSV cu numele si data curenta.

Linia

    df = pd.DataFrame(
        columns=[
            "datetime",
            "light_value",
            "sound_value",
            "temperature_1_value",
            "humidity_value",
            "temperature_2_value",
            "pressure_value",
            "altitude_value",
            "acceleration_x",
            "acceleration_y",
            "acceleration_z",
        ]
    )

crează un DataFrame gol cu coloanele specificate. Aceste coloane reprezintă datele pe care le citim de la portul serial și pe care le vom scrie în fișierul CSV ulterior. În acest caz, fiecare coloană reprezintă o anumită valoare:

  • datetime: data și ora la care s-a citit valoarea
  • light_value: valoarea citită a senzorului de lumină
  • sound_value: valoarea citită a senzorului de sunet
  • temperature_1_value: valoarea citită a primului senzor de temperatură
  • humidity_value: valoarea citită a senzorului de umiditate
  • temperature_2_value: valoarea citită a celui de-al doilea senzor de temperatură
  • pressure_value: valoarea citită a senzorului de presiune
  • altitude_value: valoarea citită a senzorului de altitudine
  • acceleration_x: valoarea citită a senzorului de accelerație pe axa X
  • acceleration_y: valoarea citită a senzorului de accelerație pe axa Y
  • acceleration_z: valoarea citită a senzorului de accelerație pe axa Z

Practic, această linie de cod definește structura DataFrame-ului și permite stocarea valorilor citite într-un format tabular ușor de prelucrat și analizat.

Ce este Pathlib?

Linia file_path = path / datetime.datetime.now().strftime(“%Y%m%d-%H%M%S.csv”) din functia read_serial_batch construieste calea catre fisierul CSV in care vor fi salvate datele citite de la portul serial.

Mai exact, se construieste un obiect Path (din modulul pathlib) care contine calea catre directorul specificat in variabila path, combinata cu o denumire de fisier care include data si ora curente in formatul YYYYMMDD-HHmmSS. Astfel, fiecare rulare a functiei va crea un fisier nou, cu un nume unic bazat pe data si ora curente.

Blocul

    while len(df) < batch_length:
        _ = read_serial_once(df)

este utilizat pentru a citi date din portul serial pana cand numarul de inregistrari din DataFrame-ul df ajunge la valoarea specificata de batch_length. De fiecare data cand se citesc date din portul serial, acestea sunt adaugate in DataFrame si numarul de inregistrari din DataFrame este verificat. Cand numarul de inregistrari din DataFrame ajunge la valoarea specificata de batch_length, se opreste citirea din portul serial si DataFrame-ul este scris intr-un fisier CSV. Aceasta abordare asigura ca toate datele necesare sunt colectate inainte de a scrie datele intr-un fisier CSV.

df.to_csv(file_path, index=False)

Linia df.to_csv(file_path, index=False) din functia read_serial_batch are rolul de a salva datele din DataFrame-ul df intr-un fisier CSV. Argumentul file_path specifica calea catre fisierul CSV care va fi creat, iar argumentul index=False specifica faptul ca nu se va salva si indexul DataFrame-ului in fisierul CSV.

In acest fel, datele colectate de la dispozitivul conectat la portul serial vor fi stocate intr-un fisier CSV, care poate fi ulterior folosit pentru a analiza datele sau pentru a genera grafice.

Exemplu de Program #2

#!/usr/bin/env python3
import argparse
import json
from pathlib import Path
 
import pandas as pd
import plotly
import plotly.express as px
from flask import Flask, render_template
 
app = Flask(__name__)
 
 
def parse_args(args: list = None) -> argparse.Namespace:
    script_name = Path(__file__).stem
    parser = argparse.ArgumentParser(
        prog=script_name,
        description="Read saved data and display it using Plotly",
        epilog=f"{script_name} --input-path /home/pi/weather",
    )
 
    def validate_path(path: str) -> Path:
        path = Path(path)
        if not path.exists() or not path.is_dir():
            raise argparse.ArgumentTypeError(f"Path {path} is not a directory")
        return path
 
    parser.add_argument(
        "-i",
        "--input-path",
        type=validate_path,
        default=Path("/home/pi/weather"),
        help="Path to read the data files from",
    )
    args = parser.parse_args(args)
    return args
 
 
@app.route("/")
def index():
    df = pd.concat([pd.read_csv(csv_path) for csv_path in app.config["input_path"].glob("*.csv")])
    df.sort_values(by="datetime", inplace=True)
    fig = px.line(df, x="datetime", y="temperature_1_value")
    graph = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
    return render_template("index.html", graph=graph)
 
 
if __name__ == "__main__":
    args = parse_args()
    app.config["input_path"] = args.input_path
    app.run(host="0.0.0.0")
Previous Next