Things used in this project

Hardware components:
Pi 3 02
Raspberry Pi 3 Model B
×1
09590 01
LED (generic)
×7
Mfr 25fbf52 221r sml
Resistor 221 ohm
×7
pill organizer box
×1
11026 02
Jumper wires (generic)
×1
12002 04
Breadboard (generic)
×1
Raspberry Pi T - cobbler board
×1
Hexiwear docking bd
NXP Hexiwear
×1
Software apps and online services:
Dp image kit 02
Amazon Alexa Alexa Skills Kit
Screen%20shot%202015 07 20%20at%206.10.26%20pm
Amazon Web Services AWS Lambda
Ha 2up iot
Amazon Web Services AWS IoT
Hand tools and fabrication machines:
09507 01
Soldering iron (generic)

Custom parts and enclosures

Click Storage Box
An Autodesk Fusion 360 design for a storage box for up to 12 Click Modules.
It is in two pieces that snap together to make a hinge. The lid of the storage case is designed to hold the Hexiwear Docking station and keep it from sliding around on your desk.
base.057415d2-cc85-4552-a0fb-010459ad5e5b.f3d

Schematics

My Medicine Reminder Schematic
LEDs to light up 7 day pill planner box
Leds%20medminder

Code

medminder.pyPython
#!/usr/bin/python

"""python  Medicine Reminder to be controlled by Amazon Alexa"""

import paho.mqtt.client as mqtt
import json, time, sys, ssl
import logging, logging.handlers
import RPi.GPIO as GPIO  

time_window_size = 5 #duration of the reminder in minutes
schedule = [1080,1142,1200] #list of scheduled medicine reminders
#schedule is kept in minutes past midnight


sunday = 24
monday = 17
tuesday = 21
wednesday = 11
thursday = 10
friday = 15
saturday = 13

GPIO.setmode(GPIO.BCM)  

GPIO.setup(sunday, GPIO.OUT)
GPIO.setup(monday, GPIO.OUT)
GPIO.setup(tuesday, GPIO.OUT)
GPIO.setup(wednesday, GPIO.OUT)
GPIO.setup(thursday, GPIO.OUT)
GPIO.setup(friday, GPIO.OUT)
GPIO.setup(saturday, GPIO.OUT)
GPIO.output(sunday, GPIO.HIGH)
GPIO.output(monday, GPIO.HIGH)
GPIO.output(tuesday, GPIO.HIGH)
GPIO.output(wednesday, GPIO.HIGH)
GPIO.output(thursday, GPIO.HIGH)
GPIO.output(friday, GPIO.HIGH)
GPIO.output(saturday, GPIO.HIGH)

cert_path = "/home/pi/Desktop/pi_pi/certs/"
host = "avqjd231ms9qb.iot.us-east-1.amazonaws.com"
topic = "$aws/things/tom_thing/shadow/update"
root_cert = cert_path + "rootCA.key"
cert_file = cert_path + "393e2d8773-certificate.pem.crt"
key_file = cert_path + "393e2d8773-private.pem.key"

globalmessage = ""  # to send status back to MQTT
isConnected = False
logger = logging.getLogger('medminder')

def do_setreminder(data):  #   {"name":"SetReminder","slots":{"Time":{"name":"Time","value":"time_value"}}}
    time_str = str(data["slots"]["Time"]["value"])
    global globalmessage
    globalmessage = "executing SetReminder",time_str
    #add the time to the schedule list
    time_lst = time_str.split(":")
    if len(time_lst) != 2:
        logger.info("SET TIME could not work this string ")
        return
    logger.info("SET TIME = " + time_str)
    time_hrs = int(time_lst[0])
    time_mins = int(time_lst[1])
    total_mins = time_mins + 60*time_hrs
    added = False
    if total_mins in schedule:
        #do not need to add it to the schedule list if it exists in the schedule list already!!!
        logger.info("already exists in schedule! ")
    else:
        #store the set reminder time in sorted order in the schedule list
        loop_count = 0
        while loop_count < len(schedule):
            if total_mins < schedule[loop_count]:
                schedule.insert(loop_count,total_mins)
                added = True
                break
            loop_count += 1
        if added == False:
            schedule.append(total_mins)        
        logger.info(schedule)
        

def do_clearreminder(data):  #   {"name":"ClearReminder","slots":{"Time":{"name":"Time","value":"time_value"}}}
    time_str = str(data["slots"]["Time"]["value"])

    global globalmessage
    globalmessage = "executing ClearReminder",time_str
    #clear the time to the schedule list
    time_lst = time_str.split(":")
    if len(time_lst) != 2:
        logger.info("CLEAR TIME could not work this string ")
        return
    logger.info("CLEAR TIME = " + time_str)
    time_hrs = int(time_lst[0])
    time_mins = int(time_lst[1])
    total_mins = time_mins + 60*time_hrs
    if total_mins in schedule:
        #do not need to add it to the schedule list if it exists in the schedule list already!!!
        logger.info("Removed from list.")
    
def toggle(gpio,cmd):
    logger.info("GPIO: " + str(gpio) + "CMD: " + str(cmd))
    GPIO.output(gpio, cmd)
        
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    isConnected = True
    logger.info("connected with result code " + str(rc))
    # Subscribing in on_connect() means that if we lose the connection and      
    # reconnect then subscriptions will be renewed.    
    client.subscribe(topic)

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    logger.info("msg received, payload = " + str(msg.payload))
    data = json.loads(str(msg.payload))

    if "name" in data:
        if data["name"] == "SetReminder":
            do_setreminder(data)
        elif data["name"] == "ClearReminder":
            do_clearreminder(data)
        
def on_log(client, userdata, level, buf):
    logger.debug(buf)

def logger_init():
    logger.setLevel(logging.DEBUG)
    log_file_size = 1024 * 1024 * 1  # 1 MB
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(process)d - %(name)s : %(message)s')
    fh = logging.handlers.RotatingFileHandler('/home/pi/Desktop/pi_pi/logs/new_medminder.log', maxBytes=log_file_size, backupCount=5)
    fh.setFormatter(formatter)
    sh = logging.StreamHandler(sys.stdout)
    sh.setFormatter(formatter)
    logger.addHandler(fh)
    logger.addHandler(sh)
    logger.info('******************************************')
    logger.info('Starting up...')

logger_init()

client = mqtt.Client(client_id="medminder.py")
client.on_connect = on_connect
client.on_message = on_message
client.on_log = on_log
client.tls_set(root_cert,
               certfile = cert_file,
               keyfile = key_file,
               cert_reqs=ssl.CERT_REQUIRED,
               tls_version=ssl.PROTOCOL_TLSv1_2,
               ciphers=None)

logger.info('connecting to mqtt broker')
client.connect(host, 8883, 60)

run = True

was_printed = False
off_was_printed = True
one_time_only = False
checked_schedule = False

try:
    while run:
        client.loop()
          
        time.sleep(1)
        dt = list(time.localtime())
        hour = dt[3]
        minute = dt[4]
        second = dt[5]
        weekday = dt[6] # Monday is 0

        if second < 10: #check schedule once a minute only
            if one_time_only == False:
                one_time_only = True
                checked_schedule = False
        else:
            one_time_only = 0        

        cur_time_mins = minute + 60 * hour # current time in minutes past midnight
        
        if checked_schedule == False:
            if was_printed == False:
                checked_schedule = True
                schedule_loop = 0
                while schedule_loop < len(schedule):
                    schedule_time_window = schedule[schedule_loop] + time_window_size
                    if schedule_time_window > (59 + 23*60):
                        schedule_time_window = (59 + 23*60)
                    if cur_time_mins < schedule_time_window:
                        if schedule[schedule_loop] <= cur_time_mins:
                            logger.info("MEDICINE REMINDER!!!")
                            was_printed = True;
                            turn_off_mins = schedule[schedule_loop] + time_window_size
                            off_was_printed = False
                            if turn_off_mins > (59 + 23*60): # if turn off past midnight
                                turn_off_mins = (59 + 23*60) #   then turn off one minute before midnight
                            if weekday == 0:
                                GPIO.output(monday, GPIO.LOW)
                            elif weekday == 1:
                                GPIO.output(tuesday, GPIO.LOW)
                            elif weekday == 2:
                                GPIO.output(wednesday, GPIO.LOW)
                            elif weekday == 3:
                                GPIO.output(thursday, GPIO.LOW)
                            elif weekday == 4:
                                GPIO.output(friday, GPIO.LOW)
                            elif weekday == 5:
                                GPIO.output(saturday, GPIO.LOW)
                            elif weekday == 6:
                                GPIO.output(sunday, GPIO.LOW)
                    schedule_loop += 1
        if off_was_printed == False:
            if cur_time_mins >= turn_off_mins:
                logger.info("MEDICINE REMINDER OFF")
                off_was_printed = True
                was_printed = 0 # to prevent re-checking during the reminder period
                #that would move the reminder window and we do not want that
                if weekday == 0:
                    GPIO.output(monday, GPIO.HIGH)
                elif weekday == 1:
                    GPIO.output(tuesday, GPIO.HIGH)
                elif weekday == 2:
                    GPIO.output(wednesday, GPIO.HIGH)
                elif weekday == 3:
                    GPIO.output(thursday, GPIO.HIGH)
                elif weekday == 4:
                    GPIO.output(friday, GPIO.HIGH)
                elif weekday == 5:
                    GPIO.output(saturday, GPIO.HIGH)
                elif weekday == 6:
                    GPIO.output(sunday, GPIO.HIGH)

        try:
            mypayload = '''{
                "StatusMessage": "%s"
            }''' % (globalmessage)

            if globalmessage != "":
                client.publish(topic, mypayload)
                globalmessage = ""

        except (TypeError):
            pass
    
except KeyboardInterrupt:
    print "Bye Bye!"
    GPIO.cleanup()    
intent schemaXML
{
   "intents":[
      {
         "intent":"SetReminder",
         "slots":[
            {
               "name":"Time",
               "type":"AMAZON.TIME"
            }
         ]
      },
      {
         "intent":"ClearReminder",
         "slots":[
            {
               "name":"Time",
               "type":"AMAZON.TIME"
            }
         ]
      }
   ]
}
Sample UtterancesPlain text
Used interaction model for the My Medicine Reminder skill
SetReminder {Time}
SetReminder Set reminder for {Time}
SetReminder Set for {Time}
SetReminder Set {Time}
SetReminder Set time {Time}
ClearReminder {Time}
ClearReminder Clear reminder for {Time}
ClearReminder Clear for {Time}
ClearReminder Clear {Time}
ClearReminder Clear time {Time}
MyMedicineReminder
This is what gets zipped up and uploaded to create the Lambda function that is used with the MyMedicineReminder voice skill

Credits

20130301 103720 1
Tom Minnich

Embedded software guy for a long time

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

ProjectsCommunitiesContestsLiveAppsBetaFree StoreBlogAdd projectSign up / Login
Respect project
Feedback