Smart Aquarium
4180 Smart Aquarium
By Tapas Kapadia & Michael Troughton
Introduction
Keep your fish happy through the web and Alexa! The Smart Fish Tank is an IoT device that allows you to remotely feed your fish, light up the tank, and alert you via email when the temperature is in a critical state.
Key Features
- Feeding system – Remotely control a feeding mechanism on the Smart Fish Tank to make sure your fish will never be hungry
- Lighting – The Smart Fish Tank Web portal or Amazon Alexa Fish Tank Skill enables you to control the lighting in the tank for setting the perfect mood
- Temperature Sensor – Keep track of your Smart Fish Tank’s temperature from the internet. Receive email alerts if the temperature rises or falls to a dangerous level.
Demonstration
Not demonstrated in the video is the emailing service for temperature values that are out of the safe range for a fish. An example of this working is shown below with a temperature of below 70 degrees Fahrenheit .
Example Webpage.
What You will Need
In order to build a smart tank, you will need the following.
- Mbed LPC1768 - https://os.mbed.com/platforms/mbed-LPC1768/
- A Raspberry Pi 3 (or Pi Zero) - https://www.adafruit.com/product/3055
- Raspberry Pi Camera - https://www.amazon.com/Raspberry-Pi-Camera-Module-Megapixel/dp/B01ER2SKFS
- NeoPixel 8x8 LEDs - https://www.adafruit.com/product/1487
- H-Bridge (TB6612FNG) and Motor - https://os.mbed.com/users/4180_1/notebook/relays1/
- Photocell - https://os.mbed.com/users/4180_1/notebook/using-a-photocell-to-determine-light-levels/
- Water sensor (DS18B20) - https://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/overview
- An Echo or an Echo Dot - https://www.amazon.com/Amazon-Echo-Dot-Portable-Bluetooth-Speaker-with-Alexa-*Black/dp/B01DFKC2SO
- Amazon Web Service account for email notifications (Simple Notification Service)
- A MySQL database, preferably hosted on Amazon Web Services as a RDS
- A fish tank
- A fish
Overall Design
Full Features
- Feeding system controlled by Alexa as well as a web application
- Temperature Monitoring, Plotting, and Email Alerts
- Ambient light mode with a Photocell
- Light Brightness, Dimming, and Pattern changing with both Alexa and the web application
- Raspberry Pi and mbed communication
- Live Video Feed
Links to Source Code
All of the code used for this project can be found on the following links.
Python source code: https://github.gatech.edu/tkapadia3/FishTank.git
Mbed source code :
Import program4180SmartFishTank
4180 Smart Fish Tank Project
Getting the Smart Fish Tank Working
I assume that you are familiar with Raspberry Pi and Linux environment. Install Raspbian OS on your Raspberry Pi, update, upgrade, and set it up as you like.
When you speak to the Smart Fish Tank, the Echo Dot will receive your commands and send it to the Flask-Ask server that is running. The Flask-Ask server will check for the corresponding command and update the AWS RDS accordingly. The Flask server that is running will recognize the change in the database and send a message to the Mbed LPC 1768 through the serial port. The code running on the Mbed will recognize the associated message and update the LED/motor accordingly.
Setting Up Your Flask-Ask Server
To get started with Alexa, you’ll need Python and pip installed. If you are on a recent version of OS X or Linux, Python comes preinstalled. Once Python and pip are installed, open a terminal and type the following command to install Flask-ask. Note: You might need to precede it with sudo on Unix if you get permission errors.
pip install flask-ask
Next, copy the following onto a file called “fishTank.py” and place that in any directory of your choice.
import logging from random import randint from flask import Flask, render_template from flask_ask import Ask, statement, question, session import datetime import time import pymysql import sys HOSTNAME = "sensordata.cxvfjw9upbqk.us-east-1.rds.amazonaws.com" USERNAME = 'root' PASSWORD = 'password' DB_NAME = 'sensorstuff' connection = pymysql.connect(host=HOSTNAME, user=USERNAME, passwd=PASSWORD, db=DB_NAME, port=3306, autocommit=True, cursorclass=pymysql.cursors.DictCursor) connection.autocommit(True) app = Flask(__name__) ask = Ask(app, "/") logging.getLogger("flask_ask").setLevel(logging.DEBUG) @ask.launch def start_skill(): msg = "Welcome to the fish tank app. Please say your command" return question(msg).reprompt("Do you have another command?") # welcome_msg = "Would you like to know the external or internal temperature?" # return question(welcome_msg) @ask.intent("InternalIntent") def internal_temperature(): with connection.cursor() as cursor: sql = "SELECT * FROM Temp ORDER BY ID desc LIMIT 1" cursor.execute(sql) result = cursor.fetchone() curTime = result['TS'] month = curTime.strftime("%I %M") msg = "The current internal temperature is %.2f degrees fahrenheit recorded at %s . Is there something else you would like me to do?" % (result['V'],month) return question(msg).reprompt("Do you have another command?") @ask.intent("LightsOnIntent") def lights_on(): ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') with connection.cursor() as cursor: sql = "INSERT INTO Alexa (TS,Code) VALUE ('%s','1')" % (timestamp) cursor.execute(sql) msg = "Okay. Turning on the lights. Is there something else you would like me to do?" return question(msg).reprompt("Do you have another command?") @ask.intent("LightsOffIntent") def lights_off(): ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') with connection.cursor() as cursor: sql = "INSERT INTO Alexa (TS,Code) VALUE ('%s','0')" % (timestamp) cursor.execute(sql) msg = "Okay. Turning off the lights. Is there something else you would like me to do?" return question(msg).reprompt("Do you have another command?") @ask.intent("RaiseBrightnessIntent") def raise_brightness(): ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') with connection.cursor() as cursor: sql = "INSERT INTO Alexa (TS,Code) VALUE ('%s','+')" % (timestamp) cursor.execute(sql) msg = "Okay. Raising the brightness. Is there something else you would like me to do?" return question(msg).reprompt("Do you have another command?") @ask.intent("LowerBrightnessIntent") def lower_brightness(): ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') with connection.cursor() as cursor: sql = "INSERT INTO Alexa (TS,Code) VALUE ('%s','-')" % (timestamp) cursor.execute(sql) msg = "Okay. Lowering the brightness. Is there something else you would like me to do?" return question(msg).reprompt("Do you have another command?") @ask.intent("PatternIntent") def pattern(): ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') with connection.cursor() as cursor: sql = "INSERT INTO Alexa (TS,Code) VALUE ('%s','p')" % (timestamp) cursor.execute(sql) msg = "Okay. Changing the pattern. Is there something else you would like me to do?" return question(msg).reprompt("Do you have another command?") @ask.intent("AmbientModeIntent") def ambient_mode(): ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') with connection.cursor() as cursor: sql = "INSERT INTO Alexa (TS,Code) VALUE ('%s','a')" % (timestamp) cursor.execute(sql) msg = "Okay. Switching to ambient mode. Is there something else you would like me to do?" return question(msg).reprompt("Do you have another command?") @ask.intent("ManualModeIntent") def manual_mode(): ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') with connection.cursor() as cursor: sql = "INSERT INTO Alexa (TS,Code) VALUE ('%s','m')" % (timestamp) cursor.execute(sql) msg = "Okay. Switching to manual mode. Is there something else you would like me to do?" return question(msg).reprompt("Do you have another command?") @ask.intent("FeedIntent") def feed(): ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') with connection.cursor() as cursor: sql = "INSERT INTO Alexa (TS,Code) VALUE ('%s','=')" % (timestamp) cursor.execute(sql) msg = "Okay. Feeding the fish. Is there something else you would like me to do?" return question(msg).reprompt("Do you have another command?") @ask.intent("NoIntent") def no(): return statement("Okay. Bye then.") if __name__ == '__main__': app.run(debug=True)
Now the Alexa skill is ready to run. Run the following in a terminal in the same directory as your “fishTank.py” file:
python fishTank.py
A development server launches on http://127.0.0.1:5000/, and the skill is almost ready to configure in Amazon’s Develop Portal. Before configuration, the skill must run behind a public HTTPS server or AWS Lambda function. Setting up either would work fine, but I decided to use ngrok. Ngrok is a command-line program that opens a secure tunnel to localhost and exposes that tunnel behind an HTTPS endpoint. Ngrok makes it so Alexa can talk to your code right away. Follow the next three steps to general a public HTTPS endpoint to 127.0.0.1:5000.
- Download the ngrok client for you operating system
- Unzip it to a location you can remember
- Open up a new terminal, cd into the location, and enter:
- ./ngrok http 5000
- Make note of the Fowarding https: address.
Setting Up Your Alexa Skill
Make sure you’re logged into your Amazon developer account, and go to your list of Alexa skills. Click the “Add a New Skill” button. Configure each section as outlined below: Skill Information Settings:
- Leave the “Skill Type” set to “Custom Interaction Model”
- Enter “fish tank” (without quotes for both the “Name” and “Invocation Name” fields.
Interaction Model Settings: Copy the JSON below into the “Intent Schema” field. Don’t worry about “Custom Slot Types”.
{ "intents": [ { "intent": "ExternalIntent" }, { "intent": "InternalIntent" }, { "intent": "LightsOnIntent" }, { "intent": "LightsOffIntent" }, { "intent": "RaiseBrightnessIntent" }, { "intent": "LowerBrightnessIntent" }, { "intent": "PatternIntent" }, { "intent": "AmbientModeIntent" }, { "intent": "ManualModeIntent" }, { "intent": "NoIntent" }, { "intent": "FeedIntent" } ] }
Copy the utterances below into the “Sample Utterances” field:
InternalIntent internal temperature LightsOnIntent lights on LightsOffIntent lights off RaiseBrightnessIntent raise the brightness LowerBrightnessIntent lower the brightness PatternIntent change patterns PatternIntent pattern AmbientModeIntent ambient mode AmbientModeIntent switch to ambient mode on ManualModeIntent manual mode ManualModeIntent switch to manual mode NoIntent no FeedIntent feed the fish FeedIntent motor
Configuration Settings:
- Make sure the HTTPS radio button is selected for the “Endpoint” field.
- Enter the HTTPS endpoint from ngrok into the textfield.
- Don’t bother with “Account Linking”
SSL Certificate Settings:
Choose “My development endpoint is a subdomain of a domain that has a wildcard certificate from a certificate authority”.
Your Alexa skill should now be set up.
Configuring AWS RDS / MySQL Database
If you are familiar with creating and starting services without a GUI, you can use this template code to setup your AWS RDS.
import boto3 from time import sleep # AWS KEYS AWS_KEY="Your KEY" AWS_SECRET="Your SECRET" REGION="us-east-1" # GLOBAL VARIABLES EC2_INSTANCE_ID = "<enter-here>" # INSERT EC2 INSTANCE ID INSTANCE_TYPE = "db.t2.micro" # TYPE OF INSTANCE (FREE TIER) ID = "" # DATABASE UNIQUE IDENTIFIER USERNAME = '' # DATABASE USERNAME PASSWORD = '' # DATABASE PASSWORD DB_PORT = 3306 # DATABASE PORT DB_SIZE = 5 # SIZE OF THE DATABSE (5GB) DB_ENGINE = 'mysql' # TYPE OF DATABASE DB_NAME = '' # NAME OF DATABASE TO USE (DEFAULT) SECGROUP_ID = "" # SECURITY GROUP ID (USED BY THE EC2 INSTANCE) print "Connecting to RDS" ec2 = boto3.client('ec2', aws_access_key_id = AWS_KEY, aws_secret_access_key = AWS_SECRET, region_name = REGION) rds = boto3.client('rds', aws_access_key_id = AWS_KEY, aws_secret_access_key = AWS_SECRET, region_name = REGION) # GET THE SECURITY GROUP OF THE INSTANCE ALREADY CREATED SECGROUP_ID = ec2.describe_instances(InstanceIds = [EC2_INSTANCE_ID])['Reservations'][0]['Instances'][0]['SecurityGroups'][0]['GroupId'] print "Creating an RDS instance" response = rds.create_db_instance( DBName = DB_NAME, DBInstanceIdentifier = ID, AllocatedStorage = DB_SIZE, DBInstanceClass = INSTANCE_TYPE, Engine = DB_ENGINE, MasterUsername = USERNAME, MasterUserPassword = PASSWORD, VpcSecurityGroupIds = [ SECGROUP_ID, ], Port = DB_PORT) print "Waiting for instance to be up and running\n" sleep(30) response = rds.describe_db_instances(DBInstanceIdentifier = ID) status = response['DBInstances'][0]['DBInstanceStatus'] while not status == 'available': sleep(10) response = rds.describe_db_instances(DBInstanceIdentifier = ID) status = response['DBInstances'][0]['DBInstanceStatus'] print "Status: "+str(status) if status == 'available': response = rds.describe_db_instances(DBInstanceIdentifier = ID) print "\nRDS Instance is now running. Instance details are:" print "Intance ID: " + str(response['DBInstances'][0]['DBInstanceIdentifier']) print "Intance State: " + str(response['DBInstances'][0]['DBInstanceStatus']) print "Instance Type: " + str(response['DBInstances'][0]['DBInstanceClass']) print "Engine: " + str(response['DBInstances'][0]['Engine']) print "Allocated Storage: " + str(response['DBInstances'][0]['AllocatedStorage']) print "Endpoint: " + str(response['DBInstances'][0]['Endpoint'])
However, the steps to create the RDS are shown below. 1. Create and Amazon Web Service Account or Login to Amazon Web Services at https://aws.amazon.com/ 2. Refer to Appendix A if you do have a key pair setup for AWS. 3. Under the Service Tab, click RDS. 4. Click the Instances menu option, and then press Launch DB Instance 5. For Engine options, choose MySQL. Checkmark the only enable options eligible for RDS free tier usage. 6. On the next page under the settings header, name the database, create a username, and create a password. 7. Next launch the DB with the default settings. 8. From you launched instance, find your Endpoint. 9. Download a visual database design tool such as MySQL Workbench or Sequel Pro in order to facilitate creating a database and tables. 10. Once you are logged, in we need to create a new database and two tables.
CREATE TABLE `Alexa` ( `TS` timestamp NOT NULL, `Code` char(1) DEFAULT NULL, PRIMARY KEY (`TS`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `Temp` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `TS` timestamp NOT NULL, `V` decimal(5,2) DEFAULT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB AUTO_INCREMENT=1993 DEFAULT CHARSET=latin1;
11. The database should be setup now!
Note. An alternative to using an RDS host on AWS would be to use a local MySQL database. This however would limit the versatility of the app and make it so that only your machine will be able to use the app.
Creating Emailing Service on AWS
The Simple Notification Service on Amazon Web Service was used to send out a notification to an email that is subscribed to a topic if a certain condition is met. In our circumstance, we sent out emails if the water temperature fell below 70 or above 84 degrees Fahrenheit.
- Log on to amazon web service, and navigate to the service named Simple Notification Service
- Under “Common Actions” select “Create topic”
- Name the topic something like “ece4180” and the display something like “SmartTank”
- Click “Create a Subscription”
- For “Protocol” Select “Email” and for “Endpoint” insert your email address where you want to receive the notification.
- In your app.python file under the hello_flask directory in the pi source code. You should change the TargetArn to the topic you just created.
response = client.publish( TargetArn="arn:aws:sns:us-east-1:426036099940:FakeEnding", Message="Watch Out: " + str(x), MessageStructure='string', Subject='Fish Alert' )
Creating the Flask Web Server
1. Download the source code from: https://github.gatech.edu/tkapadia3/FishTank.git onto the raspberry pi 2. If the raspberry pi does not already have boto3 or pymysql install them by opening a terminal and one by one entering the following commands.
pip install boto3
pip install PyMySql
3. Open the database.py in the main directory of the helloflask folder. 4. Fill in the appropriate information for HOST_NAME, USERNAME, PASSWORD, and DB_NAME.
import pymysql import sys HOSTNAME = 'Your End Point ' USERNAME = 'Your Username ' PASSWORD = 'Your Password' DB_NAME = 'Your created Database Name' connection = None def get_connection(): global connection if connection is not None: return connection connection = pymysql.connect(host=HOSTNAME, user=USERNAME, passwd=PASSWORD, db=DB_NAME, port=3306, autocommit=True, cursorclass=pymysql.cursors.DictCursor) connection.autocommit(True) return connection
5. Update the ACCESS_KEY and SECRETY_KEY to your values. The ACCESS_KEY and SECRET_KEY is the same as in setting up the RDS. The information on setting up the keys is in Appendix A.
ACCESS_KEY="YourAccessKey" SECRET_KEY="YourSecretKey" REGION="us-east-1" #get sns client = boto3.client('sns', aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY, region_name=REGION)
6. Run python app.py to start the web application on port 5000. The address should be the ip address of the raspberry pi.
Mbed I/O Wiring
H-Bridge TB6612FNG
Photosensor – Use P16 for Analog In
NeoPixel LEDs
Pi I/O Wiring
DS18B20 Pinout:
Testing the Alexa device
Download Alexa app on your phone and launch it. Sign in with the same developer account you used to create the Alexa skill. Then, open the skill by saying , “Alexa open fish tank”. Then, you can say utterances that you listed when you created your skill. Try saying “Lights On” and see what happens. (Make sure your Flask-Ask and Flask servers are running)
Conclusion
Problems Encountered
Alexa skill turns off if a user does not input a command quickly. Thus, you may need to open up skills quite open before you give your command. The water temperature sensor failed.
Further Work
For the further work, I could implement additional I/O devices such as a heating system or filtering system. The web page could display other information such as air temperature. The Alexa experience could be a bit smoother. Furthermore, instead of hosting the Alexa Skills on our own server, we could move the server to let AWS Lambda handle all the Alexa Skills.
Appendix A – IAM Key
The AWS Identity and Access Management (IAM) enables you to control who can do what in your AWS account. It use access control concepts that you are familiar with, like: • User • Group • Role • Permissions
To access our services, we need to create a “user” and give them the necessary “permissions” to access the resources that we are going to use.
Follow the instruction to create “User” with some “Permissions”:
1. On your AWS Dashboard, under “Security, Identity, & Compliance” click “IAM”
2. On the left hand side, click “Users”
3. Add an new User
4. Name the user “my4180”, for Access Type “Programmatic Access”. Click “Next:Permissions”
5. Click on “Attach existing policies directly”, add “AmazonRDSFullAccess” and “AmazonEC2FullAccess” and click “Next:Review”
6. Review and create the user.
7. Copy the Access Key ID and the Secret Access Key or download the csv file by clicking the button on the left-hand corner
8. Save the keys in the safe place.
Please log in to post comments.