Week 12:
Networking
Soil Moisture and Python live plot
I am utilizing the soil moisture sensor and the esp32 board from previous weeks to do this assignment. I chose python just because this is a language that I am familiar with. The code is simple on both the arduino side and python side. Firstly, I have the esp32 to read raw data from my moisture sensor via one of the adc pins and transmit the data through serial to my laptop. On python, I used matplotlib and animation to execute a simple time series live plot. Here are the codes:
Arduino
const int sensor = 13;
#include
int n = 1;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("starting up");
delay(2000);
}
void loop() {
// put your main code here, to run repeatedly:
//Serial.print(n);Serial.print(": ");
Serial.println(analogRead(sensor));
n++;
delay(1000);
}
Python
import serial
import datetime as dt
import time
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
data= []
# Read and record the data
ser = serial.Serial('COM5',115200)
# comment this section out if not in use
b = ser.readline() # read a byte string
string_n = b.decode() # decode byte string into Unicode
string = string_n.rstrip() # remove \n and \r
flt = float(string) # convert string to float
data.append(flt) # add to the end of data list
time.sleep(0.1) # wait (sleep) 0.1 seconds
# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = []
ys = []
# This function is called periodically from FuncAnimation
def animate(i, xs, ys):
# Read temperature (Celsius) from TMP102
b = ser.readline()
string_n = b.decode() # decode byte string into Unicode
string = string_n.rstrip() # remove \n and \r
flt = float(string)
moisture = flt
# Add x and y to lists
xs.append(dt.datetime.now().strftime('%H:%M:%S'))
ys.append(moisture)
# Limit x and y lists to 20 items
xs = xs[-20:]
ys = ys[-20:]
# Draw x and y lists
ax.clear()
ax.plot(xs, ys)
# Format plot
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.title('DIY moisture sensor reading')
plt.ylabel('Raw reading')
# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig, animate, fargs=(xs, ys), interval=1000)
plt.show()
The only issue I ran into while running this code is about port management. I did not know that serial port can only talk to one application at a time. If the Arduino serial command window is on, python will throw an error like this:
serial.serialutil.SerialException: could not open port 'COM5'
Also, the sequence of opening the serial port, reading data, and closing port is important when embeding serial into a function. After trial and error, I think the best way to do it is to open serial port outside the recurring function and not closing it after reading it inside the recurring function. I ran into serial port open/close errors when the order of operations isn't correct. I got my program to work, it looks like this:
I have not gotten to calibrate this sensor, but I plan on adding a simple calibration function into my script and maybe two buttons for
Today I Learned:
1) One serial port, one application. Applications will fight for the port and throw errors. 2) Adding interacive features like buttons to my GUI is something I want to do in the future.