Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
About two years ago, I started designing maker projects with Arduino Unos, bare-metal ATmega328s, ESP-01 web servers and Raspberry Pis. My background and passion had been in software development and I considered hardware to be almost black magic. But with the great software tools, code examples and support from the open source community I was able to gain a rudimentary knowledge of digital hardware design, and began to build all kinds of fun stuff.
Most of my projects have multiple environmental sensors like motion, gas, light, temperature and humidity. I've also learned how to control power to lights and servos. When I first started working with Arduinos and Raspberry Pis, I frequently used bamboo or similar wood kitchen trays and even a real breadboard to mount my projects. The photo below was my first alarm clock which I used every morning for more than a year.
Today, I use small antique boxes to showcase my maker projects. I think there is something cool about finding a new purpose for a 100 year old wooden box when integrating it with a 21st century “Internet of Things” application. Last year I transition exclusively to antique boxes that have an interesting history or character for my maker enclosures.
Sometime around Christmas or New Year's, I convinced my wife that we really “needed” an Echo in our kitchen to keep track of our grocery list. It was initially a hard sell but now we use the Echo for all kinds of things and it was a hit. In addition to keeping track of the grocery list, it is our kitchen radio, access to the Internet for questions and it has replaced old digital timers which we use for all kinds of tasks from the french press coffee maker timer to outdoor barbeque timing (turning food on the grill, etc.)
When on vacation, I stop by antique stores looking for boxes that can easily fit a 840 pin plastic breadboard. I get the strangest looks from people working in these stores when I describe their purpose. Once they get the idea, they often become enthusiastic and help me find just the right box for my projects. They know all the nooks and crannies in their store that could be hiding that perfect motion sensor project box made from bamboo imported from post-World War II Japan.
That’s how I found the perfect box for my Alexa Voice Alarm Clock in Kalispell Montana. I came across a 1910 Flemish ladies evening glove box. It's in great condition and the box has wonderful patterns burned into surface using a technique called pyrography. I’ve had this box for almost a year waiting for just the right project. And then it hit me, this box was the right size for a Rasperry Pi, a 400 pin breadboard, a few sensors, a small powered speaker and a USB microphone.
The project includes two output devices. The seven segment LED display shows time and alarm settings. The OLED display shows the current date, IP address of the PI and status messages.
Three sensors provide input. A PIR motion sensor is used to detect occupancy in the room. A VCNL-4010 proximity/ambient light sensor allows the user to stop the alarm process or initiate an Alexa request. The the ambient light sensor controls the light of the displays (next version).
I used Apple's GarageBand app to record several voice commands. The python main program sends these prerecorded messages to Alexa Voice Service (AVS). For example the wake up alarm has the following sequence:
- A voice recording says its time to get up
- A message is sent to AVS requesting the current time
- A message is sent to AVS requesting the current weather
- A song is started based on the day of the week
- An LED light strip project is an under the bed night light
If you wave your hand near the VCL-4010 it will stop the alarm. I need to add logic for a snooze function but that will be in the next version.
I used MQTT messaging to interface with an Adafruit IO dashboard. It was a great way to control the clock until I add more voice capabilities. It uses Adafruit's MQTT library for communication to the Internet.
This is a video of the working version 1.0 alarm clock. The code in this project was from version 1.0.
https://parttimemaker.com/2016/08/30/alexa-voice-alarm-clock/
I finished the prototype a couple of weeks ago. I've started working on the next version. The beta uses uses a second Raspberry Pi as a mosquitto MQTT broker. I've modified the code to update the Mosquito broker and then send fewer messages to Adafruit.IO server.
I've also started working on an iPhone user interface that communicates with the Mosquitto MQTT broker using the paho library. The prototype iPhone app is very limited today but I plan to make the MQTT broker an option.
I'll push everything to a github library as soon as the beta is ready.
VCNL4010.py
Python# The MIT License (MIT)
#
# Modern Art Electronics Project
#
# Vishay Proximity/Ambient Light Sensor VCNL4010 Class
#
# David Wilson
# Word derived from the Vishay and Adafruit library.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import time
VCNL4010_ADDRESS = 0x13 # 001 0011 shifted left 1 bit = 0x26
# registers
REGISTER_COMMAND = 0x80
REGISTER_ID = 0x81
REGISTER_PROX_RATE = 0x82
REGISTER_PROX_CURRENT = 0x83
REGISTER_AMBI_PARAMETER = 0x84
REGISTER_AMBI_VALUE = 0x85
REGISTER_PROX_VALUE = 0x87
REGISTER_INTERRUPT_CONTROL = 0x89
REGISTER_INTERRUPT_LOW_THRES = 0x8a
REGISTER_INTERRUPT_HIGH_THRES = 0x8c
REGISTER_INTERRUPT_STATUS = 0x8e
REGISTER_PROX_TIMING = 0x8f
REGISTER_AMBI_IR_LIGHT_LEVEL = 0x90 # This register is not intended to be use by customer
# Bits in Command register = 0x80
COMMAND_ALL_DISABLE = 0x00
COMMAND_SELFTIMED_MODE_ENABLE = 0x01
COMMAND_PROX_ENABLE = 0x02
COMMAND_AMBI_ENABLE = 0x04
COMMAND_PROX_ON_DEMAND = 0x08
COMMAND_AMBI_ON_DEMAND = 0x10
COMMAND_MASK_PROX_DATA_READY = 0x20
COMMAND_MASK_AMBI_DATA_READY = 0x40
COMMAND_MASK_LOCK = 0x80
# Bits in Product ID Revision Register = 0x81
PRODUCT_MASK_REVISION_ID = 0x0f
PRODUCT_MASK_PRODUCT_ID = 0xf0
# Bits in Prox Measurement Rate register = 0x82
PROX_MEASUREMENT_RATE_2 = 0x00 # DEFAULT
PROX_MEASUREMENT_RATE_4 = 0x01
PROX_MEASUREMENT_RATE_8 = 0x02
PROX_MEASUREMENT_RATE_16 = 0x03
PROX_MEASUREMENT_RATE_31 = 0x04
PROX_MEASUREMENT_RATE_62 = 0x05
PROX_MEASUREMENT_RATE_125 = 0x06
PROX_MEASUREMENT_RATE_250 = 0x07
PROX_MASK_MEASUREMENT_RATE = 0x07
# Bits in Procimity LED current setting = 0x83
PROX_MASK_LED_CURRENT = 0x3f # DEFAULT = 2
PROX_MASK_FUSE_PROG_ID = 0xc0
# Bits in Ambient Light Parameter register = 0x84
AMBI_PARA_AVERAGE_1 = 0x00
AMBI_PARA_AVERAGE_2 = 0x01
AMBI_PARA_AVERAGE_4 = 0x02
AMBI_PARA_AVERAGE_8 = 0x03
AMBI_PARA_AVERAGE_16 = 0x04
AMBI_PARA_AVERAGE_32 = 0x05 # DEFAULT
AMBI_PARA_AVERAGE_64 = 0x06
AMBI_PARA_AVERAGE_128 = 0x07
AMBI_MASK_PARA_AVERAGE = 0x07
AMBI_PARA_AUTO_OFFSET_ENABLE = 0x08 # DEFAULT enable
AMBI_MASK_PARA_AUTO_OFFSET = 0x08
AMBI_PARA_MEAS_RATE_1 = 0x00
AMBI_PARA_MEAS_RATE_2 = 0x10 # DEFAULT
AMBI_PARA_MEAS_RATE_3 = 0x20
AMBI_PARA_MEAS_RATE_4 = 0x30
AMBI_PARA_MEAS_RATE_5 = 0x40
AMBI_PARA_MEAS_RATE_6 = 0x50
AMBI_PARA_MEAS_RATE_8 = 0x60
AMBI_PARA_MEAS_RATE_10 = 0x70
AMBI_MASK_PARA_MEAS_RATE = 0x70
AMBI_PARA_CONT_CONV_ENABLE = 0x80
AMBI_MASK_PARA_CONT_CONV = 0x80 # DEFAULT disable
# Bits in Interrupt Control Register = x89
INTERRUPT_THRES_SEL_PROX = 0x00
INTERRUPT_THRES_SEL_ALS = 0x01
INTERRUPT_THRES_ENABLE = 0x02
INTERRUPT_ALS_READY_ENABLE = 0x04
INTERRUPT_PROX_READY_ENABLE = 0x08
INTERRUPT_COUNT_EXCEED_1 = 0x00 # DEFAULT
INTERRUPT_COUNT_EXCEED_2 = 0x20
INTERRUPT_COUNT_EXCEED_4 = 0x40
INTERRUPT_COUNT_EXCEED_8 = 0x60
INTERRUPT_COUNT_EXCEED_16 = 0x80
INTERRUPT_COUNT_EXCEED_32 = 0xa0
INTERRUPT_COUNT_EXCEED_64 = 0xc0
INTERRUPT_COUNT_EXCEED_128 = 0xe0
INTERRUPT_MASK_COUNT_EXCEED = 0xe0
# Bits in Interrupt Status Register = x8e
INTERRUPT_STATUS_THRES_HI = 0x01
INTERRUPT_STATUS_THRES_LO = 0x02
INTERRUPT_STATUS_ALS_READY = 0x04
INTERRUPT_STATUS_PROX_READY = 0x08
INTERRUPT_MASK_STATUS_THRES_HI = 0x01
INTERRUPT_MASK_THRES_LO = 0x02
INTERRUPT_MASK_ALS_READY = 0x04
INTERRUPT_MASK_PROX_READY = 0x08
class VCNL4010(object):
"""VCNL40xx proximity sensors."""
def __init__(self, address=VCNL4010_ADDRESS, i2c=None, **kwargs):
"""Initialize the VCNL40xx sensor."""
# Setup I2C interface for the device.
if i2c is None:
import Adafruit_GPIO.I2C as I2C
i2c = I2C
self._device = i2c.get_i2c_device(address, **kwargs)
self.reset()
def reset(self,):
byte = self.getProductIDRegister()
# print "Product ID=",byte
self.setCommandRegister(COMMAND_ALL_DISABLE);
self.setProximityRate (PROX_MEASUREMENT_RATE_31);
# enable proximity and ambiant in selftimed mode
self.setCommandRegister(COMMAND_PROX_ENABLE|COMMAND_AMBI_ENABLE|COMMAND_SELFTIMED_MODE_ENABLE)
# set interrupt control for threshold
self.setInterruptControl(INTERRUPT_THRES_SEL_PROX|INTERRUPT_THRES_ENABLE|INTERRUPT_COUNT_EXCEED_1)
#set ambient light measurement parameter
self.setAmbientConfiguration(AMBI_PARA_AVERAGE_32|AMBI_PARA_AUTO_OFFSET_ENABLE|AMBI_PARA_MEAS_RATE_2)
def calibrate(self,):
sum = 0
for x in xrange(1, 30):
sum = sum + self.getProximityOnDemand()
sum = sum / 30
offset = sum + 100
self.reset()
self.setHighThreshold(offset)
# print('Proximity={0}, Threshold={1}'.format(sum, offset))
# enable proximity and ambiant in selftimed mode
self.setCommandRegister(COMMAND_PROX_ENABLE|COMMAND_AMBI_ENABLE|COMMAND_SELFTIMED_MODE_ENABLE)
def getProductIDRegister(self,):
result = self._device.readU8(REGISTER_ID)
return result
def setCommandRegister(self, command):
self._device.write8(REGISTER_COMMAND,command)
def getCommandRegister(self, ):
return self._device.readU8(REGISTER_COMMAND)
def setProximityRate(self, command):
self._device.write8(REGISTER_PROX_RATE,command)
def setProximityCurrent(self, command):
self._device.write8(REGISTER_PROX_CURRENT,command)
def setInterruptControl(self, command):
self._device.write8(REGISTER_INTERRUPT_CONTROL,command)
def getInterruptControl(self,):
result = self._device.readU8(REGISTER_INTERRUPT_CONTROL)
return result
def setInterruptStatus (self, command):
self._device.write8(REGISTER_INTERRUPT_STATUS,command)
def getInterruptStatus (self,):
result = self._device.readU8(REGISTER_INTERRUPT_STATUS)
return result
def setAmbientConfiguration (self, command):
self._device.write8(REGISTER_AMBI_PARAMETER,command)
def setLowThreshold (self, command):
loByte = (command & 0xff)
hiByte = ((command >> 8) & 0xff)
self._device.write8(REGISTER_INTERRUPT_LOW_THRES,hiByte)
self._device.write8(REGISTER_INTERRUPT_LOW_THRES+1,loByte)
def setHighThreshold (self, command):
loByte = (command & 0xff)
hiByte = ((command >> 8) & 0xff)
self._device.write8(REGISTER_INTERRUPT_HIGH_THRES,hiByte)
self._device.write8(REGISTER_INTERRUPT_HIGH_THRES+1,loByte)
def setModulatorTimingAdjustment (self, command):
self._device.write8(REGISTER_PROX_TIMING,command)
def getProximityValue (self,):
return self._device.readU16BE(REGISTER_PROX_VALUE);
def getAmbientValue (self,):
return self._device.readU16BE(REGISTER_AMBI_VALUE);
def getProximityOnDemand (self,):
self.setCommandRegister (COMMAND_PROX_ENABLE | COMMAND_PROX_ON_DEMAND)
command = self.getCommandRegister ()
while ( (command & COMMAND_MASK_PROX_DATA_READY) == 0 ):
command = self.getCommandRegister ()
result = self._device.readU16BE(REGISTER_PROX_VALUE)
# self.reset()
return result
def getAmbientOnDemand (self,):
self.setCommandRegister (COMMAND_AMBI_ENABLE | COMMAND_AMBI_ON_DEMAND)
command = self.getCommandRegister ()
while ( (command & COMMAND_MASK_AMBI_DATA_READY) == 0 ):
command = self.getCommandRegister ()
result = self._device.readU16BE(REGISTER_AMBI_VALUE)
# self.reset()
return result
if __name__ == '__main__':
print "VCNL4010 Driver Running"
vcnl = VCNL4010()
vcnl.calibrate()
print "modes a,b,i,p"
mode=raw_input()
if mode.lower()=='a':
while True:
val = vcnl.getAmbientValue()
print "Ambient=",val
time.sleep(1.0)
elif mode.lower()=='p':
while True:
val = vcnl.getProximityValue()
print "proximity=",val
time.sleep(1.0)
else:
while True:
proximity = vcnl.getProximityOnDemand()
ambient = vcnl.getAmbientOnDemand()
print('Proximity={0}, Ambient light={1}'.format(proximity, ambient))
time.sleep(1.0)
Seven Segment LED Clock Class
Python#!/usr/bin/python
# ===========================================================================
# ClockLED
# ===========================================================================
import time
from Adafruit_LED_Backpack import SevenSegment
from threading import Thread
class LED_Clock(object):
def __init__(self,):
# Create display instance on default I2C address (0x70) and bus number.
self.display = SevenSegment.SevenSegment()
# Initialize the display. Must be called once before using the display.
self.display.begin()
self.brightness = 7
self.display.set_brightness(self.brightness)
self.colon = False
self.alarm = False
self.timeUpdateRunning = False
self.timeFormat = "%l%M"
def timeUpdateThread(self,):
# print "started timeUpdateThread"
while self.timeUpdateRunning:
time.sleep(1.0)
digitString = time.strftime(self.timeFormat)
self.display.clear()
self.display.print_number_str(digitString)
self.display.set_colon(self.colon)
if (self.colon):
self.colon = False
else:
self.colon = True
self.display.set_decimal(3, self.alarm)
self.display.write_display()
def setTime24(self,Time24=True):
if Time24:
self.timeFormat = "%I%M"
else:
self.timeFormat = "%l%M"
def setAlarm(self,val):
self.alarm = val
def setBrightness(self,val):
# print("set brightness="+str(val))
self.brightness = val
self.display.set_brightness(self.brightness)
def increaseBrightness(self,):
self.brightness = self.brightness + 1
if self.brightness > 15:
self.brightness = 15
self.display.set_brightness(self.brightness)
def decreaseBrightness(self,):
self.brightness = self.brightness - 1
if self.brightness < 0:
self.brightness = 0
self.display.set_brightness(self.brightness)
def run(self):
self.timeUpdateRunning = True
self.tuThread = Thread(target=self.timeUpdateThread )
self.tuThread.daemon = True
self.tuThread.start()
if __name__ == '__main__':
# print "ClockLED"
clock = LED_Clock()
clock.run()
while True:
# simple input driver
choice = raw_input("> ")
if choice == 'x' :
print "exiting"
clock.timeUpdateRunning = False
time.sleep(2.0)
break
elif choice == 'a':
if clock.alarm:
clock.alarm = False
else:
clock.alarm = True
elif choice == '+':
clock.increaseBrightness()
print "brightness=",clock.brightness
elif choice == '-':
clock.decreaseBrightness()
print "brightness=",clock.brightness
else:
print ("e)xit or a)larm or + or -")
OLED I2C Display Class
Python#!/usr/bin/python
# ===========================================================================
# DisplayOLED
# ===========================================================================
import time
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import socket
hostname = socket.gethostname()
IP = socket.gethostbyname(hostname)
from threading import Thread
class OLED_Display(object):
def __init__(self,):
# Raspberry Pi pin configuration:
RST = 24
# 128x64 display with hardware I2C:
self.disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)
self.disp.begin()
self.disp.clear()
self.disp.display()
# Create image buffer. Make sure to create image with mode '1' for 1-bit color.
self.image = Image.new('1', (self.disp.width, self.disp.height))
self.font = ImageFont.truetype("/home/pi/Fonts/Tahoma.ttf",12)
# self.font = ImageFont.load_default()
# Alternatively load a TTF font. Make sure the .ttf font file is in the same directory as this python script!
# Some nice fonts to try: http://www.dafont.com/bitmap.php
self.draw = ImageDraw.Draw( self.image )
self.hostname = socket.gethostname()
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#connect to any target website
s.connect(('google.com', 0))
self.ipAddress = s.getsockname()[0]
s.close()
self.oledUpdateRunning = False
self.sleepingOled = False
self.line3 = ""
self.line4 = ""
self.wakeUpImage = Image.open('/home/pi/Projects/wakeUpImage.jpg').convert('1')
self.speakImage = Image.open('/home/pi/Projects/speakImage.jpg').convert('1')
self.mode = 'text'
def updateDisplay(self,):
self.disp.clear()
# Clear image buffer by drawing a black filled box.
self.draw.rectangle((0,0,self.disp.width,self.disp.height), outline=0, fill=0)
if not self.sleepingOled:
if self.mode == 'speakImage':
self.disp.image(self.speakImage)
elif self.mode == 'wakeUpImage':
self.disp.image(self.wakeUpImage)
else:
dayOfWeekString = time.strftime("%A %b %-d")
self.draw.text((4,1), dayOfWeekString, font=self.font, fill=255)
self.draw.text((2,16), self.ipAddress, font=self.font, fill=255)
self.draw.text((2,32), self.line3, font=self.font, fill=255)
self.draw.text((2,48), self.line4, font=self.font, fill=255)
self.disp.image(self.image)
self.disp.display()
def oledUpdateThread(self,):
# print "started oledeUpdateThread"
while self.oledUpdateRunning:
self.updateDisplay()
time.sleep(0.5)
def setImageMode(self,newMode='text'):
self.mode = newMode
self.updateDisplay()
def setLine3(self,val=""):
self.line3 = val
self.updateDisplay()
def setLine4(self,val=""):
self.line4 = val
self.updateDisplay()
def setSleepMode(self,sleep):
# print("set sleep mode="+str(sleep))
self.sleepingOled = sleep
self.updateDisplay()
def run(self):
self.oledUpdateRunning = True
self.oThread = Thread(target=self.oledUpdateThread )
self.oThread.daemon = True
self.oThread.start()
if __name__ == '__main__':
# print "DisplayOLED"
oled = OLED_Display()
oled.run()
while True:
time.sleep(5.0)
oled.setImageMode('speakImage')
time.sleep(5.0)
oled.setImageMode('text')
time.sleep(5.0)
oled.setImageMode('wakeUpImage')
time.sleep(5.0)
oled.setImageMode('text')
#!/usr/bin/python
# ===========================================================================
# Alexa Voice Handler
# ===========================================================================
import time
from threading import Thread
from Queue import Queue
import subprocess
import os
#import random
import alsaaudio
import wave
from creds import *
import requests
import json
import re
from memcache import Client
servers = ["127.0.0.1:11211"]
mc = Client(servers, debug=1)
path = os.path.realpath(__file__).rstrip(os.path.basename(__file__))
device = "plughw:1" # Name of your microphone/soundcard in arecord -L
class AlexaVoice(object):
def __init__(self,):
# Create display instance on default I2C address (0x70) and bus number.
self.commandQueue = Queue()
self.running = False
self.defaultCommand = "/home/pi/Voices/time.wav"
def internetAvailable(self,):
# print "Checking Internet Connection"
try:
r =requests.get('https://api.amazon.com/auth/o2/token')
# print "Connection OK"
return True
except:
# print "Connection Failed"
return False
def getAmazonToken(self,):
# print "getAmazonToke"
token = mc.get("access_token")
refresh = refresh_token
if token:
return token
elif refresh:
payload = {"client_id" : Client_ID, "client_secret" : Client_Secret, "refresh_token" : refresh, "grant_type" : "refresh_token", }
url = "https://api.amazon.com/auth/o2/token"
r = requests.post(url, data = payload)
resp = json.loads(r.text)
mc.set("access_token", resp['access_token'], 3570)
return resp['access_token']
else:
return False
def getVerbalCommand(self,):
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, device)
inp.setchannels(1)
inp.setrate(16000)
inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
inp.setperiodsize(500)
audio = ""
t_end = time.time() + 5
while time.time() < t_end:
l, data = inp.read()
if l:
audio += data
rf = open('/home/pi/Recordings/recording.wav', 'w')
rf.write(audio)
rf.close()
inp = None
def startVerbalCommand(self,command='/home/pi/Recordings/recording.wav'):
self.commandQueue.put(command)
def startDialog(self,command='/home/pi/Voices/time.wav'):
self.commandQueue.put(command)
def alexaVoiceHandler(self,):
while self.running:
command = self.commandQueue.get(block=True)
url = 'https://access-alexa-na.amazon.com/v1/avs/speechrecognizer/recognize'
headers = {'Authorization' : 'Bearer %s' % self.getAmazonToken()}
d = {
"messageHeader": {
"deviceContext": [
{
"name": "playbackState",
"namespace": "AudioPlayer",
"payload": {
"streamId": "",
"offsetInMilliseconds": "0",
"playerActivity": "IDLE"
}
}
]
},
"messageBody": {
"profile": "alexa-close-talk",
"locale": "en-us",
"format": "audio/L16; rate=16000; channels=1"
}
}
with open(command) as inf:
files = [
('file', ('request', json.dumps(d), 'application/json; charset=UTF-8')),
('file', ('audio', inf, 'audio/L16; rate=16000; channels=1'))
]
r = requests.post(url, headers=headers, files=files)
if r.status_code == 200:
for v in r.headers['content-type'].split(";"):
if re.match('.*boundary.*', v):
boundary = v.split("=")[1]
data = r.content.split(boundary)
for d in data:
if (len(d) >= 1024):
audio = d.split('\r\n\r\n')[1].rstrip('--')
with open(path+"response.mp3", 'wb') as f:
f.write(audio)
os.system('mpg123 -q {}1sec.mp3 {}response.mp3 {}1sec.mp3'.format(path, path, path))
else:
print "http status=",r.status_code
def run(self,):
while self.internetAvailable() == False:
print "."
self.getAmazonToken()
self.running = True
self.tuThread = Thread(target=self.alexaVoiceHandler )
self.tuThread.daemon = True
self.tuThread.start()
if __name__ == '__main__':
# print "ClockLED"
alexa = AlexaVoice()
alexa.run()
while True:
# simple input driver
choice = raw_input("> ")
if choice == 'x' :
print "exiting"
alexa.running = False
time.sleep(2.0)
break
elif choice == 't':
alexa.startDialog("/home/pi/Voices/time.wav")
elif choice == 'w':
alexa.startDialog("/home/pi/Voices/weather.wav")
else:
print ("e)xit or a)larm or + or -")
#!/usr/bin/python
# ===========================================================================
# Rotating Logger Class
# ===========================================================================
import logging
from logging.handlers import RotatingFileHandler
class MyLogger(object):
def __init__(self, fileName='logging.log', fileSize=1024*1024, fileCopies=5):
self.logger = logging.getLogger(fileName)
self.logger.setLevel(logging.INFO)
self.handler = RotatingFileHandler(filename=fileName,maxBytes=fileSize,backupCount=fileCopies)
self.formatter = logging.Formatter('%(asctime)s : %(message)s')
self.handler.setFormatter(self.formatter)
self.logger.addHandler(self.handler)
def write(self,msg):
self.logger.info(msg)
if __name__ == '__main__':
print "Logging from main"
#!/usr/bin/python
import sys
import smbus
from Queue import Queue
import threading
import datetime
import time
import RPi.GPIO as GPIO
from Adafruit_I2C import Adafruit_I2C
import VCNL4010
# ===========================================================================
# AVAC HW Class
# ===========================================================================
class AVAC_HW(object):
def __init__(self):
#define 3 queues - log entries, send and receive messages
self.pirQueue = Queue()
self.vcnlQueue = Queue()
self.interruptQueue = Queue()
self.vcnl4010 = VCNL4010.VCNL4010()
self.vcnl4010.calibrate()
self.ambient = 0
self.newEvent = time.time()
self.lastEvent = time.time()
# setup the GPIO bus and 2 interrupts
GPIO.setmode(GPIO.BCM)
GPIO.setup(24, GPIO.IN,pull_up_down=GPIO.PUD_UP) # GPIO pin 24 is the PIR interrupt
GPIO.setup(23, GPIO.IN) # GPIO pin 23 is the VCNL4010 interrupt
GPIO.add_event_detect(24, GPIO.FALLING, callback=self.pirInterruptHandler)
GPIO.add_event_detect(23, GPIO.FALLING, callback=self.vcnlInterruptHandler)
def pirWorkAround(self,):
self.newEvent = time.time()
self.elapsed = self.newEvent - self.lastEvent
# print "seconds=",self.elapsed
self.lastEvent = self.newEvent
def interruptHelper(self,iQ,pQ,vQ):
# print "interruptHandler running"
while True:
event = self.interruptQueue.get()
if event == "PIR":
m = time.strftime("PIR %y-%m-%d %H:%M:%S")
self.pirQueue.put(m)
# print m
else:
m = time.strftime("VCNL %y-%m-%d %H:%M:%S")
self.vcnlQueue.put(m)
# print m
# define threaded callback function for the atmega328pu interrupt
def pirInterruptHandler(self,channel):
self.interruptQueue.put("PIR")
print "PIR INT"
# define threaded callback function for the atmega328pu interrupt
def vcnlInterruptHandler(self,channel):
val = self.vcnl4010.getInterruptStatus()
self.vcnl4010.setInterruptStatus(val)
self.interruptQueue.put("VCNL")
# print "VCNL INT"
def pirWait(self,blocking):
if blocking:
print "1 pirWait: blocking"
data = self.pirQueue.get(blocking)
# print "2 pirWait: data=",data
self.pirWorkAround()
return data
else:
if self.pirQueue.empty():
print "3 pirWait non block: EMPTY"
return ""
else:
data = self.pirQueue.get(False)
print "4 pirWait non block: data=",data
self.pirWorkAround()
return data
def vcnlWait(self,blocking):
if blocking:
data = self.vcnlQueue.get(True)
return data
else:
if self.vcnlQueue.empty():
return ""
else:
data = self.vcnlQueue.get(False)
return data
def run(self,):
hwThread = threading.Thread(target=self.interruptHelper,args=(self.interruptQueue,self.pirQueue,self.vcnlQueue))
hwThread.start()
def exitCleanUp(self):
self.running = False
GPIO.cleanup() # clean up GPIO on normal exit
if __name__ == '__main__':
print "AVAC HW Main Running"
hw = AVAC_HW()
hw.run()
while True:
# time.sleep(0.5)
m = hw.pirWait(True)
print m
if len(m) > 0:
m = hw.pirWait(False)
Alexa Voice Alarm Clock
Python# Alexa Voice Alarm Clock
# Dave Wilson
# MIT license
# Based on Adafruit exmaples and other great developers
# Derived from - Example of using the MQTT client class to subscribe to and publish feed values.
# Author: Tony DiCola
# Import standard python modules.
import os
import random
import sys
import time
import subprocess
import threading
import alsaaudio
# Import Adafruit IO MQTT client.
from Adafruit_IO import MQTTClient
# Set to your Adafruit IO key & username below.
ADAFRUIT_IO_KEY = '---'
ADAFRUIT_IO_USERNAME = '---' # See https://accounts.adafruit.com
import AlexaVoice
import LED_Clock
import OLED_Display
import VCNL4010
import PIR_HW
import VCNL_HW
import MyLogger
global clock
clock = LED_Clock.LED_Clock()
clock.run()
global oled
oled = OLED_Display.OLED_Display()
oled.run()
global vcnl
vcnl = VCNL4010.VCNL4010()
vcnl.calibrate()
global vcnl_interrupt
vcnl_interrupt = VCNL_HW.VCNL_HW()
global pir_interrupt
pir_interrupt = PIR_HW.PIR_HW()
global myprocess
myprocess = None
global alarmTime
alarmTime = ""
global alarmOn
alarmOn = False
global lightOn
lightOn = False
global ID_WAKEUP
ID_WAKEUP = '600509'
global ID_MUSIC
ID_MUSIC = '600620'
global ID_ALARM_TIME
ID_ALARM_TIME = '601507'
global ID_LIGHT_STRIP
ID_LIGHT_STRIP = '601387'
global ID_SLEEP_MODE
ID_SLEEP_MODE = '601554'
global ID_MOTION
ID_MOTION = '600511'
#set up the status logger
global logger
logger = MyLogger.MyLogger(fileName="/home/pi/LogFiles/RotatingLog.log",fileSize=1024*1024)
logger.write("MQTT_AVAC STARTED")
# Define callback functions which will be called when certain events happen.
def connected(client):
client.subscribe(ID_WAKEUP) # wake up alarm swith
client.subscribe(ID_MUSIC) # music switch
client.subscribe(ID_ALARM_TIME) # alarm time
client.subscribe(ID_LIGHT_STRIP) # light strip
client.subscribe(ID_SLEEP_MODE) # System sleep mode
def disconnected(client):
sys.exit(1)
def message(client, feed_id, payload):
global myprocess
global alarmTime
# wake up alarm switch
if feed_id == ID_WAKEUP:
alarmOn = False
if payload == "ON":
clock.alarm = True
logger.write("WAKEUP ON")
else:
clock.alarm = False
logger.write("WAKEUP OFF")
# music switch
elif feed_id == ID_MUSIC:
if payload == "ON":
dirStr = '/home/pi/Music/'
fileStr = time.strftime("%A")
pathStr = dirStr + fileStr + '.m4a'
myprocess = subprocess.Popen(['omxplayer','-b',pathStr],
stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
oled.setLine3("Music Player")
logger.write("MUSIC ON")
else:
logger.write("MUSIC OFF")
if myprocess != None:
try:
myprocess.stdin.write('q')
except IOError as e:
logger.write("BROKEN PIPE: OMXPLAYER")
oled.setLine3("")
# light switch
elif feed_id == ID_LIGHT_STRIP:
if payload == "ON":
lightOn = True
logger.write("LIGHT STRIP ON")
oled.setLine3("Night Light: ON")
else:
lightOn = False
logger.write("LIGHT STRIP OFF")
oled.setLine3("Night Light: OFF")
# brighthness controls during sleep
elif feed_id == ID_SLEEP_MODE:
if payload == "ON":
logger.write("SLEEP ON")
clock.setBrightness(0)
oled.setSleepMode(True)
else:
logger.write("SLEEP OFF")
clock.setBrightness(7)
oled.setSleepMode(False)
# wake up time
elif feed_id == ID_ALARM_TIME: # alarm time
logger.write("ALARM TIME: "+payload)
alarmTime = payload
oled.setLine4(alarmTime)
else:
logger.write("UNDEFINED MESSAGE")
oled.setLine4("TILT")
### MAIN THREAD ###
global client
# Create an MQTT client instance.
client = MQTTClient(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)
# Setup the callback functions defined above.
client.on_connect = connected
client.on_disconnect = disconnected
client.on_message = message
# Connect to the Adafruit IO server.
client.connect()
client.loop_background()
# check for proximity user command
def userMonitor():
global alarmOn
global alarmWait
global vcnl_interrupt
global logger
global alexa
global oled
logger.write("USER MONITOR THREAD STARTED")
while True:
switch = vcnl_interrupt.wait(True)
while len(switch) > 0:
switch = vcnl_interrupt.wait(False)
# time.sleep(0.1)
if alarmOn:
alarmOn = False
logger.write("STOP ALARM PROCESS")
else:
oled.setImageMode('speakImage')
alexa.getVerbalCommand()
oled.setImageMode('text')
alexa.startVerbalCommand()
# check for pir movement
def motionMonitor():
global pir_interrupt
global logger
global alexa
global client
logger.write("MOTION MONITOR THREAD STARTED")
# print "motionMonitor"
lastMotion = 0
currentMotion = 0
waitForMotion = True
#client.publish(ID_MOTION,currentMotion)
while True:
time.sleep(0.1)
motion = pir_interrupt.wait(waitForMotion)
# logger.write(motion)
if len(motion) > 0:
waitForMotion = False
while len(motion) > 0:
# logger.write(motion)
motion = pir_interrupt.wait(waitForMotion)
currentMotion = 1
logger.write("MOTION DETECTED")
else:
currentMotion = 0
waitForMotion = True
logger.write("MOTION NOT DETECTED")
if not (lastMotion == currentMotion):
lastMotion = currentMotion
#client.publish(ID_MOTION,currentMotion)
alexa = AlexaVoice.AlexaVoice()
alexa.run()
# initialize the clock
time.sleep(5.0)
client.publish(ID_SLEEP_MODE, "OFF")
client.publish(ID_LIGHT_STRIP, "OFF")
client.publish(ID_WAKEUP, "OFF")
client.publish(ID_MUSIC, "OFF")
client.publish(ID_ALARM_TIME, "05:00")
time.sleep(5.0)
userThread = threading.Thread(target=userMonitor)
userThread.start()
#motionThread = threading.Thread(target=motionMonitor)
#motionThread.start()
frame = 0
### Loop forever checking for the alarm
alarmOn = False
while True:
time.sleep(0.1)
frame = frame + 1
if clock.alarm:
digitString = time.strftime("%H:%M")
if str(alarmTime) == str(digitString):
alarmOn = True
logger.write("START ALARM PROCESS")
oled.setImageMode('wakeUpMode')
os.system('mpg123 -q /home/pi/Voices/AVAC-Hello-Time-To-Get-Up.mp3')
time.sleep(5.0)
if alarmOn:
alexa.startDialog("/home/pi/Voices/time.wav")
time.sleep(5.0)
if alarmOn:
alexa.startDialog("/home/pi/Voices/weather.wav")
time.sleep(5.0)
if alarmOn:
client.publish(ID_MUSIC, "ON")
time.sleep(5.0)
if not alarmOn:
client.publish(ID_MUSIC, "OFF")
client.publish(ID_LIGHT_STRIP, "ON")
alarmOn = False
while str(alarmTime) == str(digitString):
time.sleep(10.0)
digitString = time.strftime("%H:%M")
oled.setImageMode('text')
frame = 6
if frame >= 40:
value = vcnl.getAmbientOnDemand()
vcnl.calibrate()
client.publish(600510, value)
frame = 1
Comments