Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
20cca21
Update control.py
limbotempo Feb 24, 2021
77985ab
Delete control_phpump.py
limbotempo Mar 1, 2021
b681e36
Update control.py
limbotempo Mar 1, 2021
62571c3
Update control.py
limbotempo Mar 1, 2021
194a2fd
Update control.py
limbotempo Mar 1, 2021
930133e
Update control.py
limbotempo Mar 1, 2021
7eca15f
Update control.py
limbotempo Mar 1, 2021
20f13b4
Update control.py
limbotempo Mar 3, 2021
9a0837e
Update control.py
limbotempo Mar 3, 2021
a9b0779
Update control.py
limbotempo Mar 3, 2021
0ff6716
Update control.py
limbotempo Mar 3, 2021
818126c
Update control.py
limbotempo Mar 3, 2021
f223974
Update control.py
limbotempo Mar 3, 2021
7e4bf2e
Update control.py
limbotempo Mar 3, 2021
71bf83c
Update control.py
limbotempo Mar 3, 2021
f466cae
Update control.py
limbotempo Mar 3, 2021
7433728
Update control.py
limbotempo Mar 4, 2021
d93df0c
Update control.py
limbotempo Mar 4, 2021
b1e98ea
Update control.py
limbotempo Mar 4, 2021
69c5f5f
Update control.py
limbotempo Mar 4, 2021
33697e1
Update control.py
limbotempo Mar 4, 2021
3b34878
Update control.py
limbotempo Mar 4, 2021
74893dd
Update control.py
limbotempo Mar 4, 2021
b60fc14
Update control.py
limbotempo Mar 4, 2021
ec362bd
Update control.py
limbotempo Mar 4, 2021
b07d4ac
Update control.py
limbotempo Mar 4, 2021
86ecabc
Create test.py
limbotempo Mar 4, 2021
7945c3f
Update test.py
limbotempo Mar 4, 2021
a9bbfc8
Update test.py
limbotempo Mar 4, 2021
8f4dcd8
Update control.py
limbotempo Mar 4, 2021
59a08ef
Update control.py
limbotempo Mar 4, 2021
76753c3
Update control.py
limbotempo Mar 4, 2021
79ad909
Update control.py
limbotempo Mar 4, 2021
814be13
Update control.py
limbotempo Mar 4, 2021
3d5bb2b
Update control.py
limbotempo Mar 4, 2021
bf5086d
Update control.py
limbotempo Mar 5, 2021
53dd5af
changed pins
LynesChan Mar 5, 2021
0bcb78d
changed pins
LynesChan Mar 5, 2021
53f1c03
Update control.py
limbotempo Mar 5, 2021
381f790
Update control.py
limbotempo Mar 5, 2021
af6a823
Update control.py
limbotempo Mar 5, 2021
0967cda
Update control.py
limbotempo Mar 5, 2021
ee49ede
Update control.py
limbotempo Mar 5, 2021
35a5f50
Update control.py
limbotempo Mar 5, 2021
aa983d9
Update control.py
limbotempo Mar 5, 2021
20b8b7f
Update control.py
limbotempo Mar 5, 2021
7156d02
Update control.py
limbotempo Mar 5, 2021
d7434e1
Update control.py
limbotempo Mar 5, 2021
97d31b6
Update control.py
limbotempo Mar 5, 2021
08529df
Update control.py
limbotempo Mar 5, 2021
ebbf598
Update control.py
limbotempo Mar 5, 2021
6e67b7b
Update control.py
limbotempo Mar 5, 2021
21de782
Update control.py
limbotempo Mar 5, 2021
02d9df3
Update control.py
limbotempo Mar 5, 2021
899bf4f
Update control.py
limbotempo Mar 5, 2021
888e77b
calibrated ph sensor
LynesChan Mar 5, 2021
9488f7a
Update control.py
limbotempo Mar 5, 2021
25e2b8b
Update control.py
limbotempo Mar 5, 2021
ca7626c
Update control.py
limbotempo Mar 10, 2021
191e79e
Update control.py
LynesChan Mar 14, 2021
c9286ea
Update control.py
LynesChan Mar 14, 2021
f98237c
Update control.py
limbotempo Mar 16, 2021
343855f
added Calibration function
cbrrrry Mar 17, 2021
3316656
Update control.py
LynesChan Mar 19, 2021
8c20930
Update control.py
LynesChan Mar 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/adc.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,22 @@ def init_leak(self):
self.leak_sensor= AnalogIn(self.ads,ADS.P0)

def init_ph(self):
self.pH_sensor= AnalogIn(self.ads,ADS.P1)
self.pH_sensor= AnalogIn(self.ads,ADS.P2)

def init_pH(self):
self.pH_sensor= AnalogIn(self.ads,ADS.P1)
self.pH_sensor= AnalogIn(self.ads,ADS.P2)

def read_leak(self):
return self.leak_sensor.voltage

def read_pH(self):
pH_voltage = self.pH_sensor.voltage
pH = 7.7 +(pH_voltage-1.65)*(-3.3)
pH = 4.7 +(pH_voltage-1.65)*(-3.3)
return pH

def read_ph(self):
pH_voltage = self.pH_sensor.voltage
pH = 7.7 +(pH_voltage-1.65)*(-3.3)
pH = 4.7 +(pH_voltage-1.65)*(-3.3)
return pH


204 changes: 139 additions & 65 deletions src/control.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,132 @@
#Python script to read analog voltage values from ADS1115 16bit ADC with PGA
#Author: Carson Berry
#Date: February 2nd, 2021
#usage:
# python3
# import src.adc as adc
# sensors = adc.adc_sensors()
# sensors.read_leak()
# sensors.read_pH()
# Reference provided at: https://learn.adafruit.com/adafruit-4-channel-adc-breakouts/python-circuitpython

#----------------------------------------------Template--------------------------------------------------#
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this Template description! Would you please be able to add all of the example code together at the end of it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

# This is a brief template on creating *new threading modules*
# 1. Create a class, for example: class ph_control(object):
# 2. Copy all the exiting initialization functions for sensors
# 3. Add the new initialization function for the new sensor/device
# 4. Set up the threading module at the end of this file, this includes:
# 4.1. Define your class, for example: VARIABLE_NAME = NAME_OF_THE_CLASS()
# 4.2. Create the thread module, for example: NAME_OF_THREAD = Thread(target = VARIABLE_NAME.FUNCTION_NAME)
# Notice that the FUNCTION_NAME should be the function in the class (defined before), and is the one that you would like it to iterate
# 4.3. Start the thread, for example: NAME_OF_THREAD.start()
#-----------------------------------------------CODE COMPLETE---------------------------------------------#
# class ph_control(object):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't ph_control() already defined as a class? Correct me if I'm wrong, but don't we need to instantiate an object of this class similar to you do below. I'm guessing an example might look like this:
import src.control as control pH_controller = control.ph_control() pH_thread = Thread(target = pH_controller.test()) pH_thread.start()
I like that you've made your example more general than mine, I just wanted to try and show the most important use case.

Do threads only work for single functions?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the aim of define ph_control(object) should just be an example for the users indicate that they should create a class. I will edit and try to make my sample code more obvious.
For your last question, I think yes, I test before and the threads can only work for one single function within one class

# VARIABLE_NAME = NAME_OF_THE_CLASS()
# NAME_OF_THREAD = Thread(target = VARIABLE_NAME.FUNCTION_NAME)
# NAME_OF_THREAD.start()




import RPi.GPIO as GPIO
import time
import board
import threading
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
from threading import Thread
import RPi.GPIO as GPIO
import time
import src.pins



# Add timers for different outputs ex. ph_timer, water_level_timer, temp_timer
class ph_control(object):
def __init__(self):
self.ads=0
self.init_i2c()

class adc_sensors(object):
self.pH_sensor = 0
self.init_pH()
self.pH_intercept = 7
self.pH_offset = 1.65
self.pH_slope = -3.3
self.desired_ph = 7

def init_i2c(self):
#define i2c object
i2c = busio.I2C(board.SCL, board.SDA)
#create object
self.ads = ADS.ADS1115(i2c)

def init_ph(self):
self.pH_sensor= AnalogIn(self.ads,ADS.P2)



def init_pH(self):
self.pH_sensor= AnalogIn(self.ads,ADS.P2)

def read_pH(self):
pH_voltage = self.pH_sensor.voltage
pH = self.pH_intercept +(pH_voltage-self.pH_offset)*(self.pH_slope)
return pH

def read_ph(self):
pH_voltage = self.pH_sensor.voltage
pH = self.pH_intercept +(pH_voltage-self.pH_offset)*(self.pH_slope)
return pH

# Calibration function
# Intended to assist with the calibration of the pH_probe at regular (eg. monthly) intervals
#
# REQUIRES USER ENGAGEMENT - THEY MUST CHANGE THE pH PROBE SOLUTION WHEN PROMPTED
# total process will take about 3 minutes.
#
# inputs: self, pH of calibration solution 1 (eg 7), pH of calibration solution 2 (eg. 4)
# updates: self.pH_slope, self.pH_intercept
#use: ph_control.calibrate(self,7,4)
def calibrate(self, calibration_pH_1, calibration_pH_2):
#this function constructs a linear function of the form:
# y = m(x-offset)+b
# or
# pH = (slope)*(voltage-offset_voltage)+ pH_at_offset_voltage

print('Please place the pH probe in the first solution with pH ',calibration_pH_1,', and mix the solution with the probe. Wait 60 seconds.')
#should we wait for confirmation? From testing, 1 minute is not enough
for _ in range(60):
time.sleep(1)
print('.')
print('Reading now')
v1 = self.pH_sensor.voltage # read the pH meter's voltage in the known solution

print('Please place the pH probe in the second solution with pH ',calibration_pH_2,', and mix the solution with the probe. Wait 60 seconds.')
#should we wait for confirmation? From testing, 1 minute is not enough
for _ in range(60):
time.sleep(1)
print('.')
print('Reading now')
v2 = self.pH_sensor.voltage # read the pH meter's voltage in the known solution

#calculate slope of pH-voltage curve (should be negative)
self.pH_slope = (calibration_pH_1-calibration_pH_2)/(v1-v2)

#pH curve 'intercept' anchored around first datapoint
self.pH_intercept = calibration_pH_1
self.pH_offset = v1






def test_ph(self):
print('init start')
print('the value of x is', end=' ') # sorry these are test code that I use. Will clean this up
self.pH_sensor= AnalogIn(self.ads,ADS.P2)
pH_voltage = self.pH_sensor.voltage
pH = self.pH_intercept +(pH_voltage-self.pH_offset)*(self.pH_slope) #test self.x here
while True:
time.sleep(2)
print('loop start')
self.pH_sensor= AnalogIn(self.ads,ADS.P2)
pH = self.read_pH()
if (pH<=self.desired_pH): #test self.desired_ph here
print('pump opened')
GPIO.setup(26,GPIO.OUT)
GPIO.output (26,GPIO.HIGH)
time.sleep(2)
GPIO.output (26,GPIO.LOW)
time.sleep(2)

class wl_control(object): #It turns out to be a bug when there's no (object)
def __init__(self):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also remove unnecessary fields

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, all I meant by unnecessary fields was that instantiating/pointing to the pH channel on the adc in the water_level control object is unnecessary because it exists elsewhere.


self.ads=0
self.init_i2c()
self.leak_sensor = 0
Expand All @@ -45,61 +142,38 @@ def init_i2c(self):

def init_leak(self):
self.leak_sensor= AnalogIn(self.ads,ADS.P0)

def water_level_init(self):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The water level sensor does not use the ADC. Please review the recently merged water_level.py on the main branch for code.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure!

self.level = 0
self.setup()
self.read() # update level


def init_ph(self):
self.pH_sensor= AnalogIn(self.ads,ADS.P1)

def init_pH(self):
self.pH_sensor= AnalogIn(self.ads,ADS.P1)

def read_leak(self):
return self.leak_sensor.voltage

def read_pH(self):
pH_voltage = self.pH_sensor.voltage
pH = 7.7 +(pH_voltage-14.7/10)*(-3.3) #formula adjusted for use with a voltage divider to map the 5 V output to 3.3V for use with a 3.3V ADC
pH = 7.7 +(pH_voltage-1.65)*(-3.3)
return pH

def read_waterlevel(self):
try:
#self.level = GPIO.input(pins.WATER_LEVEL)
self.level = GPIO.input(11)
return self.level
except:
GPIO.cleanup()
return -1

def pump_open(self):
print ('pump opened')
GPIO.output(9,GPIO.HIGH) #9 for the relay pin on pH pump
time.sleep(1)
GPIO.output(9,GPIO.LOW)
#Here I add the function of the timer
#This code here correspond update the data at default time
#Using threading method
def test_ph(self):

def read_ph(self):
pH_voltage = self.pH_sensor.voltage
pH = 7.7 +(pH_voltage-1.65)*(-3.3)
return pH

def test_wl(self):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So test_wl(self) is the control loop for the water level?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes exactly!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! If you can just add a brief description, so that future users know what this module's function is.

while True:
read_ph()
if (int(read_ph()<= 11)):
pump_open()
time.sleep(10)

def test_waterlevel(self):
while True:
read_leak()
if (read_waterlevel()== -1):
GPIO.output(8,HIGH)
time.sleep(1)
GPIO.output(8,GPIO.LOW)
time.sleep(20)


x = adc_sensors()
thread1 = threading.Thread(target=x.test_ph())
thread2 = threading.Thread(target=x.test_waterlevel())

thread1.start()
thread2.start()
#print('valve opened')
time.sleep(6)


#Create Class
First = wl_control()
FirstThread=Thread(target=First.test_wl)
FirstThread.start()

#Create Class
Second = ph_control()
SecondThread=Thread(target=Second.test_ph)
SecondThread.start()
105 changes: 0 additions & 105 deletions src/control_phpump.py

This file was deleted.

Loading