Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 98ef270

Browse files
Added Python Datalogger and Arduino Side Code to repo
1 parent ff5a9fa commit 98ef270

File tree

2 files changed

+354
-0
lines changed

2 files changed

+354
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Arduino side code for data acquisition
2+
// Assume Arduino connected to 4 Sensors ,On receiving appropriate characters,Arduino sends back Sensor values
3+
4+
// @ -> will trigger TransmitHumidityValue(); -> will send back humidity value
5+
// # -> will trigger TransmitSoilMoistureValue(); -> will send back Soil-Moisture value
6+
// $ -> will trigger Transmit_Temperature_Value(); -> will send back Temperature Value
7+
// & -> will trigger TransmitLightIntensityValue(); -> will send back Light Sensor Value
8+
9+
// Functions are standin and user is supposed to implement them according to their needs
10+
// For Demo, the functions send a random number.
11+
12+
13+
void setup()
14+
{
15+
Serial.begin(9600); //Data will be send to PC @9600bps
16+
}
17+
18+
void loop()
19+
{
20+
char ReceivedByte; //
21+
22+
if (Serial.available() > 0) //Wait for data reception
23+
{
24+
ReceivedByte = Serial.read();//Read data from Arduino Serial UART buffer
25+
26+
switch(ReceivedByte)
27+
{
28+
case '@': //Serial.print('@');
29+
//Serial.print("HumidityValue ->");
30+
TransmitHumidityValue();
31+
break;
32+
case '$': //Serial.print('$');
33+
//Serial.print("4TemperatureValues ->");
34+
Transmit_Temperature_Value();
35+
break;
36+
case '#': //Serial.print('#');
37+
//Serial.print("SoilMoistureValue ->");
38+
TransmitSoilMoistureValue();
39+
break;
40+
case '&': //Serial.print('&');
41+
//Serial.print("LightIntensityValue -> ");
42+
TransmitLightIntensityValue();
43+
break;
44+
default: Serial.println("Default Value");
45+
}//end of switch()
46+
}//end of if
47+
}//end of loop()
48+
49+
50+
51+
void TransmitHumidityValue(void)
52+
{
53+
//Send Dummy Values using Random number generator for now
54+
//Implement the code for talking with sensor here
55+
56+
long RandomNumber ;
57+
RandomNumber = random(40,90); //Generate Random number between 40 and 90
58+
Serial.println(RandomNumber); //Send Number followed by \n so python readline will exit on PC side
59+
60+
}
61+
62+
void TransmitSoilMoistureValue(void)
63+
{
64+
// Send Dummy Values using Random number generator for now
65+
// Implement the code for talking with sensor here
66+
long RandomNumber ;
67+
RandomNumber = random(30,50);// Generate Random number between 30 and 50
68+
Serial.println(RandomNumber);// Send Number followed by \n so python readline will exit on PC side
69+
}
70+
71+
void TransmitLightIntensityValue(void)
72+
{
73+
// Send Dummy Values using Random number generator for now
74+
// Implement the code for talking with sensor here
75+
76+
long RandomNumber ;
77+
RandomNumber = random(0,1024);// Generate Random number between 0 and 1024
78+
Serial.println(RandomNumber); // Send Number followed by \n so python readline will exit on PC side
79+
}
80+
81+
82+
void Transmit_Temperature_Value(void)
83+
{
84+
// Send Dummy Values using Random number generator for now
85+
// Implement the code for talking with sensor here
86+
87+
long RandomNumber ;
88+
RandomNumber = random(20,90);// Generate Random number between 20 and 90
89+
Serial.println(RandomNumber);// Send Number followed by \n so python readline will exit on PC side
90+
91+
}
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
#requires pyserial installed
2+
#requires ttkbootstrap installed
3+
4+
from tkinter import *
5+
import ttkbootstrap as ttkb
6+
from ttkbootstrap.dialogs import Messagebox
7+
from ttkbootstrap.scrolled import ScrolledText
8+
import tkinter as tk
9+
10+
11+
import serial
12+
import threading
13+
import time
14+
import csv
15+
import webbrowser
16+
import os
17+
18+
19+
baud_rate = 0
20+
21+
csv_delimiter = ','
22+
log_int = 0
23+
24+
25+
#create Dropdown options
26+
baudrates = [0,600,1200,2400,4800,9600,19200,38400]
27+
log_interval = [0,0.5,1,1.5,2,2.5,3,4,5,10,20,30,60,120]
28+
29+
tutorial_text = ''' Tutorial
30+
31+
Select Serial Port number like COM3 or COM12 in Windows
32+
Select Serial Port number like ttyUSB0 or ttyACM0 in Linux
33+
Select Baudrate from Drop Down Menu
34+
Select Logging interval from Drop Down Menu
35+
36+
Click Start Logging to start datalog
37+
Click Stop Logging to stop datalog
38+
39+
Data saved in disk\n'''
40+
41+
def acquire_arduino_data(serialport_name,baud_rate,logging_interval):
42+
43+
serialport_obj = None #declared here so accessible inside and outside try/catch
44+
log_count = 1
45+
46+
47+
48+
#Create the Serial port object
49+
try:
50+
serialport_obj = serial.Serial(serialport_name,baud_rate) #open the serial port
51+
text_log.insert(END,f'{serialport_name} selected,at {baud_rate} ,\n')
52+
text_log.insert(END,f'Logging Interval = {logging_interval} seconds,\n')
53+
text_log.insert(END,f'Wait for Arduino to Reset,\n')
54+
time.sleep(2) #Some time for Arduino board to reset
55+
text_log.insert(END,f'Arduino Ready Now ,\n\n')
56+
57+
except serial.SerialException as var : #In case of error
58+
text_log.insert(END,f'{var} ,\n')
59+
60+
log_file_name = create_filename_current_date_time()
61+
62+
63+
64+
csv_header =['No','Date','Time','Unix Time','Humidity','Soil Moisture','Temperature','Light Intensity']
65+
66+
with open(log_file_name,'a',newline ='') as File_obj:
67+
csvwriter_obj = csv.writer(File_obj, delimiter = csv_delimiter)
68+
csvwriter_obj.writerow(csv_header)
69+
70+
text_log.insert(END,f'Log file -> {log_file_name}\n\n')
71+
text_log.insert(END,f'Starting Logging @{logging_interval} interval\n\n')
72+
text_log.insert(END,f'{csv_header}\n')
73+
74+
csv_filename_loc.insert(END,f'{os.getcwd()}\n')
75+
csv_filename_loc.insert(END,f'{log_file_name}\n')
76+
77+
78+
while True:
79+
80+
#print(start_logging_event.is_set())
81+
if start_logging_event.is_set() == True:
82+
83+
arduino_sensor_data_list = read_arduino_sensors(serialport_obj)
84+
#print(arduino_sensor_data_list)
85+
unix_timestamp = int(time.time()) #get current unix time to time stamp data
86+
87+
log_time_date = time.localtime(unix_timestamp) #Convert epoch time to human readable time,date format
88+
log_time = time.strftime("%H:%M:%S",log_time_date) #hh:mm:ss
89+
log_date = time.strftime("%d %B %Y",log_time_date) #dd MonthName Year
90+
91+
92+
93+
arduino_sensor_data_list.insert(0,str(log_count))
94+
arduino_sensor_data_list.insert(1,str(log_date))
95+
arduino_sensor_data_list.insert(2,str(log_time))
96+
arduino_sensor_data_list.insert(3,str(unix_timestamp))
97+
98+
#print(arduino_sensor_data_list)
99+
text_log.insert(END,f'{arduino_sensor_data_list} ,\n')
100+
text_log.see(tk.END) #for auto scrolling
101+
102+
with open(log_file_name,'a',newline='') as File_obj:
103+
csvwriter_obj = csv.writer(File_obj, delimiter = csv_delimiter)
104+
csvwriter_obj.writerow(arduino_sensor_data_list)
105+
106+
#print('data acquiring')
107+
log_count = log_count + 1
108+
109+
time.sleep(logging_interval)
110+
111+
112+
elif start_logging_event.is_set() != True:
113+
serialport_obj.close()
114+
text_log.insert(END,f'+==================================================+ \n')
115+
text_log.insert(END,f'Logging Ended \n')
116+
break
117+
118+
119+
120+
121+
122+
123+
def read_arduino_sensors(serialport_obj):
124+
125+
return_list =[0,0,0,0]
126+
127+
polling_interval = 0.010 #In seconds,to give time for arduino to respond
128+
129+
serialport_obj.write(b'@')
130+
time.sleep(polling_interval)
131+
humidity_value = serialport_obj.readline()
132+
humidity_value = humidity_value.strip()
133+
134+
serialport_obj.write(b'#')
135+
time.sleep(polling_interval)
136+
soil_value = serialport_obj.readline()
137+
soil_value = soil_value.strip()
138+
139+
serialport_obj.write(b'$')
140+
time.sleep(polling_interval)
141+
temp_value = serialport_obj.readline()
142+
temp_value = temp_value.strip()
143+
144+
serialport_obj.write(b'&')
145+
time.sleep(polling_interval)
146+
light_value = serialport_obj.readline()
147+
light_value = light_value.strip()
148+
149+
#print(humidity_value,soil_value,temp_value,light_value)
150+
151+
return_list[0] = humidity_value.decode()
152+
return_list[1] = soil_value.decode()
153+
return_list[2] = temp_value.decode()
154+
return_list[3] = light_value.decode()
155+
156+
return return_list
157+
158+
def create_filename_current_date_time():
159+
# Generate file name using Current Date and Time
160+
current_local_time = time.localtime() #Get Current date time
161+
filename = time.strftime("%d_%B_%Y_%Hh_%Mm_%Ss",current_local_time)# 24hour clock format
162+
filename = 'ard_'+ filename + '_daq_log.csv'
163+
#print(f'\nCreated Log File -> {filename}')
164+
return filename
165+
166+
167+
def tutorial_btn_handler():
168+
webbrowser.open_new(r'https://www.xanthium.in/multithreading-serial-port-data-acquisition-to-csv-file-using-producer-consumer-pattern-python')
169+
170+
171+
172+
def start_log_btn_handler():
173+
start_logging_event.set()
174+
serialport_name = port_no_entry.get()
175+
t1 = threading.Thread(target = acquire_arduino_data,args=(serialport_name,baud_rate,log_int))
176+
t1.start()
177+
178+
179+
def stop_log_btn_handler():
180+
start_logging_event.clear()
181+
182+
183+
184+
def on_select_option_bind_baudrates(e):
185+
global baud_rate
186+
baud_rate = int(baud_rates_combo_box.get())
187+
#print(baud_rate)
188+
189+
def on_select_option_bind_log_interval(e):
190+
global log_int
191+
log_int = float(log_interval_combo_box.get())
192+
print(log_int)
193+
194+
195+
196+
197+
start_logging_event = threading.Event()
198+
199+
# Main Window Creation
200+
root = ttkb.Window(themename = 'superhero') # theme = superhero
201+
root.title('SerialPort Datalogging to CSV file')
202+
root.geometry('650x660') # Width X Height
203+
204+
#Labels for naming boxes
205+
head_label = ttkb.Label(text = 'Python Serial Port CSV Datalogger',font = ('Helvetica',15),bootstyle='light')
206+
head_label.place(x=95,y=10)
207+
208+
website_label = ttkb.Label(text = 'www.xanthium.in',font = ('Helvetica',10),bootstyle='warning')
209+
website_label.place(x=230,y=45)
210+
211+
serialport_label = ttkb.Label(text = 'Select Port',bootstyle = 'light')
212+
serialport_label.place(x=20,y=90)
213+
214+
baudrate_label = ttkb.Label(text = 'Baudrate',bootstyle = 'light')
215+
baudrate_label.place(x=220,y=90)
216+
217+
lograte_label = ttkb.Label(text = 'Log Interval (Seconds)',bootstyle = 'light')
218+
lograte_label.place(x=440,y=90)
219+
220+
#Create COM portEntry Widget
221+
port_no_entry = ttkb.Entry(root)
222+
port_no_entry.insert(0,'COMx')
223+
port_no_entry.place(x=20,y=120)
224+
225+
#create Combobox for baudrates
226+
baud_rates_combo_box = ttkb.Combobox(values = baudrates)
227+
baud_rates_combo_box.place(x=220,y=120)
228+
baud_rates_combo_box.current(0)#set the default value on combobox
229+
#bind the combobox
230+
baud_rates_combo_box.bind('<<ComboboxSelected>>',on_select_option_bind_baudrates)
231+
232+
#create Combobox for logging interval
233+
log_interval_combo_box = ttkb.Combobox(values = log_interval)
234+
log_interval_combo_box.place(x=440,y=120)
235+
log_interval_combo_box.current(0)#set the default value on combobox
236+
#bind the combobox
237+
log_interval_combo_box.bind('<<ComboboxSelected>>',on_select_option_bind_log_interval)
238+
239+
240+
#create button for controlling data acquisition and logging
241+
start_log_btn = ttkb.Button(text = 'Start Logging' ,command = start_log_btn_handler ).place(x=20, y=175)
242+
stop_log_btn = ttkb.Button(text = 'Stop Logging' ,command = stop_log_btn_handler ).place(x=220,y=175)
243+
tutorial_btn = ttkb.Button(text = 'Online Web Tutorial' ,command = tutorial_btn_handler ).place(x=440,y=175)
244+
245+
# Scrollable text box for CSV file name
246+
247+
file_loc_label = ttkb.Label(text = 'CSV file Name and Location',bootstyle = 'light').place(x=20,y=225)
248+
249+
csv_filename_loc = ScrolledText(root,height=2,width=74,wrap = WORD,autohide=False,)
250+
csv_filename_loc.place(x=20,y=250)
251+
252+
# Define the font family and font size
253+
font_family = 'Helvetica'
254+
font_size = 10
255+
256+
log_label = ttkb.Label(text = 'Logging',bootstyle = 'light').place(x=20,y=318)
257+
258+
text_log = ScrolledText(root,height=15,width=66,wrap = WORD,autohide=False,font=(font_family, font_size))
259+
text_log.place(x=20,y=340)
260+
text_log.insert(END,tutorial_text)
261+
262+
263+
root.mainloop()

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /