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

  1. Feeding system – Remotely control a feeding mechanism on the Smart Fish Tank to make sure your fish will never be hungry
  2. 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
  3. 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.

/media/uploads/tapask/image001.jpg

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 .
/media/uploads/tapask/screen_shot_2017-12-14_at_12.34.13_pm.png

Example Webpage.
/media/uploads/tapask/d.jpg

What You will Need

In order to build a smart tank, you will need the following.

Overall Design

/media/uploads/tapask/image003.png

Full Features

  1. Feeding system controlled by Alexa as well as a web application
  2. Temperature Monitoring, Plotting, and Email Alerts
  3. Ambient light mode with a Photocell
  4. Light Brightness, Dimming, and Pattern changing with both Alexa and the web application
  5. Raspberry Pi and mbed communication
  6. 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.

  1. Download the ngrok client for you operating system
  2. Unzip it to a location you can remember
  3. Open up a new terminal, cd into the location, and enter:
  4. ./ngrok http 5000
  5. 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:

  1. Leave the “Skill Type” set to “Custom Interaction Model”
  2. 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:

  1. Make sure the HTTPS radio button is selected for the “Endpoint” field.
  2. Enter the HTTPS endpoint from ngrok into the textfield.
  3. 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 /media/uploads/tapask/image004.png 5. For Engine options, choose MySQL. Checkmark the only enable options eligible for RDS free tier usage. /media/uploads/tapask/image005.png 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. /media/uploads/tapask/image006.png 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.

  1. Log on to amazon web service, and navigate to the service named Simple Notification Service /media/uploads/tapask/screen_shot_2017-12-14_at_1.28.05_pm.png
  2. Under “Common Actions” select “Create topic”
  3. Name the topic something like “ece4180” and the display something like “SmartTank”
  4. Click “Create a Subscription”
  5. For “Protocol” Select “Email” and for “Endpoint” insert your email address where you want to receive the notification.
  6. 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 /media/uploads/tapask/screen_shot_2017-12-14_at_1.49.33_pm.png

Photosensor – Use P16 for Analog In /media/uploads/tapask/image008_jeiTCrP.png

NeoPixel LEDs /media/uploads/tapask/screen_shot_2017-12-14_at_1.50.44_pm.png

Pi I/O Wiring

DS18B20 Pinout:

/media/uploads/tapask/image009.png

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” /media/uploads/tapask/image010.png

2. On the left hand side, click “Users” /media/uploads/tapask/image011.png

3. Add an new User /media/uploads/tapask/image012.png

4. Name the user “my4180”, for Access Type “Programmatic Access”. Click “Next:Permissions” /media/uploads/tapask/image013.png

5. Click on “Attach existing policies directly”, add “AmazonRDSFullAccess” and “AmazonEC2FullAccess” and click “Next:Review” /media/uploads/tapask/image014.png

6. Review and create the user. /media/uploads/tapask/image015.png

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 /media/uploads/tapask/image016.png

8. Save the keys in the safe place.


Please log in to post comments.