Relay Timer Using a MySQL Database
MySQL Database Creation
Using the libraries available in python creating timers using a MySQL database to manage relays connected to a Raspberry Pi is fairly straight forward. Creating a facility to override the timers and turn the relays on or off manually is also possible. The timers will be aimed at longer term settings over months and days, when I created this code I was looking to manage a pool so I have configured it to take start and stop times for each relay spread out over an entire year. The timers can also be configured to turn on and off the relays multiple times a day either all year round or say just over the summer. As we get further into the code I will show some examples of how the timers can be setup.
The benefit of using the database over just hard coding the timers is that we can make changes to the database at anytime without have to stop the program from running. Another advantage is that if you have a web server installed then you can access the database from your own webpage or if installed, phpmyadmin.
This tutorial follows on from others showing you how to connect relays to your Raspberry Pi, how to install a web server and optionally, how to install phpmyadmin, if you haven’t already I would suggest reading these before continuing.
MySQL Database Creation via the CLI
The first thing we need to do is create a MySQL database and add some tables, there are 2 ways to do this, we can login to the command line interface (CLI) of the Pi or via phpmyadmin on a web browser. First we log into MySQL from the Pi command prompt.
Enter your password and you will be met with a new prompt – mysql>. Next we will create a new database, note that all mysql commands need to be terminated with a semi-colon.
mysql>show databases;
Replace “yourdbname” with what you want to call your database and if successful you should now see that your database has been added
Now that we have a database we can start adding our tables and columns, the first one we need is timer_override, this table will hold values of on, off and auto for each of the relays.
Database changed
mysql>CREATE TABLE timer_override (
->pk INT UNSIGNED PRIMARY KEY,
->relay_1 TEXT,
->relay_2 TEXT,
->relay_3 TEXT,
->relay_4 TEXT
->);
->show tables;
The “pk” column is defined to provide a primary key that we can use later to address the data that we want to change, all other columns are set to be of type “TEXT”. We now need to add some values to our row.
->VALUES (1,”on”,”off”,”auto”,”on”);
mysql>SELECT * FROM timer_override;
Using the same process we now need to add a table for the timers of our first relay as follows
->pk INT UNSIGNED PRIMARY KEY,
->starttime DATETIME,
->stoptime DATETIME
->);
->show tables;
Again we define a “pk” column and set the other 2 columns to be “datetime” types. Repeat this step to create tables for relay_2_timer, relay_3_timer and relay_4_timer, while we could put all of our values into one table it becomes more readable in the python code it we separate them out.
Next we will assign 4 start and stop times to each of our relays. Dates and times need to be entered in the following format: ‘YYYY-MM-DD HH:MM:SS’
->VALUES (1, ‘2016-01-01 08:00:00’, ‘2016-03-31 15:30:00’),
->(2, ‘2016-04-01 10:00:00’, ‘2016-06-30 13:00:00’),
->(3, ‘2016-07-01 13:00:00’, ‘2016-09-30 19:00:00’),
->(4, ‘2016-10-01 02:30:00’, ‘2016-12-31 06:00:00’);
mysql>SELECT * FROM relay_1_timer;
In the above example I have divided the year up into 4 equal parts so the first start/stop pair will activate the relay between the start of January and end of March between 8 am and 3:30 pm each day, pairs 2-4 will do the same for the rest of the year during their specified times. It is not necessary to fill in all 4 timer pairs, the following entry could also be used.
->VALUES (1, ‘2016-01-01 08:00:00’, ‘2016-03-31 09:30:00’),
->(2, ‘2016-01-01 15:00:00’, ‘2016-03-31 18:00:00’),
->(3, NULL, NULL),
->(4, NULL, NULL);
mysql>SELECT * FROM relay_2_timer;
In this example the first timer pair activates the relay between 8 am and 9:30 am from January to March, the 2nd pair also activates the timer from January to March but from 3 pm to 6 pm (effectively the relay is activated twice each day). The final 2 pairs are not used, there is one restriction, while you can set the timers to span multiple years this would require a modification to the python code and also the necessity to update the timers each year. The python code has been written to basically ignore the year when making it’s comparisons.
Repeat the above process to insert table data for relay_3_timer and relay_4_timer.
Finally if you wanted to for example update the 3rd row in table “relay_2_timer” from NULL, then we need to use the mysql UPDATE command as follows:
mysql>SELECT * FROM relay_2_timer;
That’s it we now have our database set up and ready to start controlling the relays.
MySQL Database Creation via phpMyAdmin (GUI)
Another way of creating the database is to use the Graphical User Interface (GUI) provided by phpMyAdmin. In the short video below I will show you how to create the same database and tables that we made above through the CLI.
The Python Code
So now that we have our database ready we can go ahead and start creating our pyhton code to read the database and control the relays.
To start we need to import some modules and setup our database connection details
#!/usr/bin/env python
import MySQLdb
from time import sleep
import datetime
import RPi.GPIO as GPIO
servername = “localhost”
username = “YourMySQLusername”
password = “YourMySQLpassword”
dbname = “YourDatabaseName”
Next we will configure the GPIO pins to be outputs, set the relays to off and setup our variables. The relays that I am using are “active low” so we need to set the output value to “True” to deactivate the relay. If your relays are active high then you will need to change the settings to “False” throughout the code.
# Set up GPIO ports GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) # Global Variables outputpins = [22, 23, 24, 25] # Set the GPIO pin numbers that are required relaynum = ["relay_1", "relay_2", "relay_3", "relay_4"] # Relay names in MySQL relaycount = range(1, 5) # Number of relays to be controlled numdtpairs = 4 # Number of Start/Stop pairs per relay #Set our GPIO pins to outputs and set them to off then wait 2 seconds for i in outputpins: GPIO.setup(i, GPIO.OUT) GPIO.output(i, False) sleep(2)
The variables describe which GPIO pins we are using, assigns the MySQL table names, sets the number of relays and sets how many start /stop pairs we have defined in the database. Here I have shown settings for 4 relays, and 4 start/stop pairs, if you have a different number of relays or are using different pins you can add and remove them in the 4 variables above.
In order to read the information that we have saved in our database we will use the following three pieces of code:
This definition will connect to the MySQL database and read in the row that specifies our manual override information. ie On/Off/Auto
def read_override_data(): conn = MySQLdb.connect(servername, username, password, yourdbname) curs = conn.cursor() curs.execute("SELECT * FROM timer_override WHERE pk=(1)") override_timer_values = curs.fetchone() conn.close() return override_timer_values
This definition reads in the start/stop pairs we have set one row at a time.
def get_relay_timer_data(tablename, row): conn = MySQLdb.connect(servername, username, password, dbname) curs = conn.cursor() curs.execute("SELECT * FROM {0} WHERE pk={1}".format(tablename, row)) relay_timer_values = curs.fetchone() conn.close() return relay_timer_values
If the read_override_data definition returns “Auto” for a particular relay then the start/stop pairs will be passed to this definition to decide if the time right now is within one of the set date/time ranges and if so, tell the main program to activate the relay.
def timercheck(timer_data, relay): if timer_data[1] is None: # Python reads a "NULL" value as None return "False" else: cdt = datetime.datetime.now() starttimer = timer_data[1] starttimer = starttimer.replace(year=cdt.year) stoptimer = timer_data[2] stoptimer = stoptimer.replace(year=cdt.year) if (cdt.date() >= starttimer.date() and cdt.date() <= stoptimer.date()): if (cdt.time() >= starttimer.time() and cdt.time() <= stoptimer.time()): return "True" else: return "False" else: return "False"
The main program consists of a series of loops that call the definitions every second checking the database for manual On/Off changes and comparing the start/stop times to the current time when the relay is set to auto. The main program is contained in a while loop that will repeat indefinitely.
while True: # Repeat the code indefinitely override = read_override_data() for i, j, z in zip(relaycount, outputpins, relaynum): if override[i] == "auto": relay = j relayon = "False" dtpair = 1 while relayon == "False" and dtpair <= numdtpairs: timer_data = get_relay_timer_data(z + "_timer", dtpair) relayon = timercheck(timer_data, relay) if relayon == "True": GPIO.output(relay, True) break elif relayon == "False": dtpair += 1 if dtpair == (numdtpairs + 1): GPIO.output(relay, False) elif override[i] == "on": GPIO.output(j, True) # turn relay on elif override[i] == "off": GPIO.output(j, False) # turn relay off sleep(1)
All going well you should now have all of your relays controlled via your MySQL database, any changes made to the database should be immediately reflected by your relays without the need to stop the program running in the background.
All the python code shown here is available for both 2.x and 3.x on my Hydropi Github Repository.
If you have any thought’s about this article, improvements or errors let me know in the comments below and if you found this helpful, why not share it with others.
Hello Dominic,
Thanks for posting this, I am building a RPi controlled timer/controller for my pool and came across your website. A lot of good info here, keep up the good work! I noticed in your instruction to create the ‘timeoverride’ table you name the fields ‘relaya’, ‘relayb’, etc… but when you populate the values you use ‘powera’, ‘powerb’, etc… FYI.
Will be following along here and looking forward to your updates!
Thanks,
Jeff
Hi Jeff,
Thanks for pointing that out, should be fixed now. If your making a pool monitor you can find the python code I’m using here, I haven’t had a chance to write a post on it yet but it’s a little more versatile. You can set the number of sensors and the type you have connected, the number of relays, and how many start/stop pairs you want on a relay by relay basis. It will then build the database for you. if you try it out add your own details to the configuration section and the email function, hopefully the notes in the code make sense.
Good Luck
Dom
Thanks Dom for posting this. I have another RPi 3 coming in the mail today. I used my first one for my sprinkler system. I have been following some of your posts with the Qemu emulator, but its time to start playing with the hardware! I was planning on using Windows IOT for my pool controller, from a example on HacksterIO, but I like your version better, especially for the scheduling events. Looking forward more of your blog posts.
Jeff
Thanks Jeff
Glad to know that your finding it useful, hopefully I can get the final code out in couple of weeks, just always hard to find the time.
Hi Dom,
Thank you so much for all your work. Can you explain where I locate the python code as in what directory and then also how i kick it off to start running on boot?
Thanks
1
Hi Jon
The full python code can be found here at GITHUB, then navigate to the following specific file for the full code, /Python 3/Pool-Monitor/Hydropi_Main_py3.py. In order to launch the code at start up use the “Crontab” function in Linux, here’s a good tutorial
Hope this helps