Upload
elliot-barer
View
149
Download
2
Tags:
Embed Size (px)
Citation preview
Formal Report for SmartLock Prepared for: Robert Trost and Susan Woo Prepared by: Elliot Barer, James Esau, Albert Phan December 19, 2014
Formal Report for SmartLock
Executive Summary 5 INTRODUCTION 5
ELECTROMECHANICAL ACTUATION 5
POWER 5
3D DESIGN 6
FIRMWARE 7
SOFTWARE 7
CONCLUSIONS 8
RECOMMENDATIONS 8
1. SmartLock 9 1.1. INTRODUCTION 9
1.1.1 DEADBOLT BACKGROUND 9
1.1.2 ORGANIZATION OF REPORT 10
1.2 GENERAL DESCRIPTION AND BLOCK DIAGRAM 10
FIGURE 1.1: SMARTLOCK BLOCK DIAGRAM 10
2. Electromechanical Actuation 12 2.1 SERVO MECHANICAL DESIGN REQUIREMENTS 12
2.1.1 DESIGN CONSIDERATIONS 12
2.1.2 SERVO ROTATION 13
2.1.3 ABSOLUTE POSITIONING 13
2.2 SERVO CONNECTION REQUIREMENTS 14
2.2.1 KEY AND TUMBLER DESIGN 14
2.2.2 EMULATING SIMILAR MECHANICS WITH A SERVO 15
FIGURE 2.1: AUTOMATION OF SMARTLOCK LOCKING 15
2.2.3 CONNECTING AND POSITIONING THE SERVO 16
FIGURE 2.2: SERVO HORN ATTACHMENT AND SERVO POSITION 16
2.3 DESIGNING THE SMARTLOCK MANUAL OVERRIDE 17
2.3.1 ADDING MANUAL POSITION DETECTION 17
FIGURE 2.3: MICROSWITCH MOUNTS IN SMARTLOCK HOUSING 17
2.3.2 UTILIZING MANUAL POSITION DETECTION 18
3. Power 19 3.1 DESIGN CONSIDERATIONS 19
3.2 OVERVIEW/SUMMARY 19
3.3 BATTERY SELECTION 20
�2
Formal Report for SmartLock
FIGURE 3.1: BATTERY DISCHARGE CURVE 20
3.4 ATMEGA328P MICROCONTROLLER REQUIREMENTS 21
FIGURE 3.2: ATMEGA328P: ACTIVE SUPPLY CURRENT VS. FREQUENCY 21
3.5 NRF8001 BLUETOOTH MODULE REQUIREMENTS 22
TABLE 3.1: NRF8001 CURRENT CONSUMPTION PARAMETERS 22
3.6 CC3000 WIFI MODULE REQUIREMENTS 23
TABLE 3.2: CC3000 POWER CONSUMPTION 23
3.7 HS-225BB SERVO REQUIREMENTS 23
3.8 AAT1217 SOT23-6 PACKAGE BOOST CONTROLLER 24
FIGURE 3.3: EFFICIENCY VS. OUTPUT CURRENT FOR 3.3V AND 5V OUTPUTS 24
3.8.1 OUTPUT CURRENT 25
FIGURE 3.4: MAXIMUM OUTPUT CURRENT VS. INPUT VOLTAGE 25
FIGURE 3.5: SCHEMATICS FOR 3.3V AND 5V BOOST CONVERTERS 26
4. 3D Design 27 4.1 MODELLING 27
FIGURE 4.1: BACKPLANE 27
FIGURE 4.2: TUMBLER 27
FIGURE 4.3: BODY HOUSING 28
FIGURE 4.4: TOP COVER 29
4.2 3D PRINTING 30
4.2.1 FIRST PROTOTYPE 30
FIGURE 4.5: FIRST PROTOTYPE, PRINTED IN RESIN 30
4.2.2 SECOND REVISION 31
FIGURE 4.6: SECOND PROTOTYPE, PRINTED IN ABS PLASTIC 31
5. Bluetooth Low Energy 32 5.1 GENERIC ACCESS PROFILE 32
5.2 GENERIC ATTRIBUTE PROFILE 33
5.3 PROFILE, SERVICES AND CHARACTERISTICS 33
6. Firmware 35 FIGURE 6.1: FLOWCHART FOR FIRMWARE LOCK AND UNLOCK FUNCTIONS 35
FIGURE 6.2: FLOWCHART FOR MICROCONTROLLER FIRMWARE 36
7. Software 37 7.1 SWIFT 37
7.2 SMARTLOCK CLASS 38
�3
Formal Report for SmartLock
7.3 SMARTLOCK MOBILE APP 39
FIGURE 7.1: PRIMARY VIEW AND DEBUG VIEW, RESPECTIVELY 39
FIGURE 7.2: FLOWCHART FOR CONNECTING TO SMARTLOCK 40
FIGURE 7.3: FLOWCHART FOR APP BUTTON CONTROLS 40
FIGURE 7.4: FLOWCHART FOR PROXIMITY DETECTION 41
8. Test Plans and Results 42 8.1 SERVO DRAIN AND BATTERY TEST 42
8.1.1 RESULTS 42
8.1.2 SOLUTIONS ATTEMPTED 42
8.1.3 RECOMMENDATIONS 42
8.2 FIRST ASSEMBLY OF 3D PRINTED PARTS 43
8.2.1 RESULTS 43
8.2.2 REVISIONS 43
8.3 SECOND ASSEMBLY OF 3D PRINTED PARTS 44
8.3.1 RESULTS 44
8.4 BLUETOOTH CONTROL TESTING 45
8.4.1 VERIFICATION OF HARDWARE 45
8.4.2 VERIFICATION OF FIRMWARE 45
8.4.3 VERIFICATION OF SOFTWARE 46
8.4.4 REVISIONS 46
9. Scope Changes 47 10. Analysis of Success and Failure 48
10.1 SUCCESSES 48
10.1.1 IOS APP 48
10.2 FAILURES 48
10.2.1 BOOST CONVERTERS 48
11. Conclusion 49 11.1 ELECTROMECHANICAL AND MANUAL OPERATION 49
11.2 BLUETOOTH CONTROL AND PROXIMITY DETECTION 50
11.3 LESSONS LEARNED 50
12. Recommendations 51 13. Documentation References 52
�4
Formal Report for SmartLock
EXECUTIVE SUMMARY
Introduction
For completion of the Computer Control option of the Electrical and Computer Engineering Technology program at the British Columbia Institute of Technology, we were tasked with designing, developing, implementing and testing a project as part of the ELEX 4330 Technical Project course. For our project, we created a Bluetooth controlled door lock, named SmartLock. This report serves to record the process of design, development and manufacturing of the SmartLock. It was requested by Robert Trost, ELEX 4330 Technical Project Instructor, and Susan Woo, COMM 2443 Communications Instructor, in order to evaluate the technical aspects and to adequately document the project.
Electromechanical Actuation
The SmartLock utilizes a servo to rotate the lock electronically. It was chosen for its high torque to size ratio. The servo actuates the door lock via a servo horn attachment that it uses to rotate the tumbler, which is in turn connected to the lock shaft. This system has 90 degrees of rotational freedom in it so as to allow the ability to manually override the electronic system without causing damage to any of the servo components.
Power
The various components of the SmartLock are powered using two AA batteries in series directly or via boost converters. Utilizing low power (sleep) modes of the microcontroller, we calculate approximately six months of battery life depending on usage. The ATMega328P microcontroller and the nRF8001 Bluetooth module are powered directly off the batteries, with the microcontroller’s main clock running at
�5
Formal Report for SmartLock
a low frequency to keep the supply current low. The CC3000 WiFi module has two voltage rails: VBAT_IN and VIO_HOST. VBAT_IN requires 3.3V which is sparingly supplied using a boost converter. VIO_HOST matches the interface voltage levels to that of the microcontroller, and as such will also be powered directly off the batteries. Finally, the servo requires 5V for normal operation which is supplied using a secondary boost converter. As with the 3.3V boost converter, their respective usages were minimized in order to maximize the efficiency of the power circuit and reduce overall power consumption.
3D Design
With 3D printing becoming more accessible and providing tremendous flexibility, the choice was made to have our prototype device 3D printed for quick production and reproduction when revision of the SmartLock was needed. Throughout the testing process the modelling was revised twice, achieving a design as close as possible to the desired final product. The first print was done by Integral Dental Labs, and was printed with a resin material. Unfortunately, this material proved to be too brittle for our applications and was unacceptable as a working prototype. The second revision was printed out of acrylonitrile butadiene styrene (ABS) plastic, a much stronger material, at the BCIT Tech Centre. The second revision was much more flexible for our operation; however, adjustments were required to correct some issues with tolerances. Unfortunately, there was not enough time for a third revision prior to our presentation; however, we have redesigned our 3D models to allow for a reprint if we so choose. Without the 3D printing technology we have today, we would not have been able to procure a working prototype.
�6
Formal Report for SmartLock
Firmware
The SmartLock is controlled using an Arduino Uno, specifically the ATMega328P microcontroller. Using the Arduino libraries and integrated development environment (IDE), the firmware was written in the C programming language. The firmware performs the setup of the Bluetooth module and the various I/O ports for the device, then keeps the device in an alternating loop of advertising itself as a peripheral Bluetooth device and going to sleep. When it receives a connection request from a central Bluetooth device (e.g. an iPhone), the device awaits an unlock or lock command and performs the appropriate actions, including toggling the correct LEDs and chirping the speaker to alert the user to the device’s activity. Upon completion of the correct action, the device sends a response to the central device alerting it of the successful operation of the command.
Software
The SmartLock app is written in Apple’s new programming language, Swift, and is developed to make use of the latest hardware and software. The app has a primary view for interacting with the SmartLock, allowing the user to toggle the state of the device with a large circular control, and a debug view allowing us to troubleshoot the device and test our proximity detection. Proximity detection allows the user to unlock the SmartLock by simply approaching the door, and have it lock automatically behind them as they walk away. This is performed by averaging the received signal strength indication (RSSI) of the peripheral device and comparing it against threshold values for lock and unlock. To prevent flipping rapidly between the locking and unlocking actions, hysteresis is introduced into the threshold values.
�7
Formal Report for SmartLock
Conclusions
Much to our delight, we were successful in creating a functional prototype of the SmartLock, achieving the majority of our goals including Bluetooth control, proximity detection, and manual locking/unlocking.
Bluetooth communication through the app was successful and there were no major issues with it. The mechanical aspect of locking and unlocking worked correctly. We experienced issues with the proximity detection due to variance in the returned RSSI values; however, these issues were largely out of our control. Our chief concern was the servo power consumption. Specifically, we saw much larger current spikes than we had anticipated and the torque on the servo was insufficient. These issues could be addressed by utilizing a boost converter capable of outputting greater current and a possible redesign of the mechanics of the automated locking and unlocking may also be required. However, by all accounts the prototype demonstration was successful proving that the SmartLock could be a legitimate product.
Recommendations
Prior to bringing the SmartLock to market, it will require further iteration including a re-evaluation of the mechanical aspects and the power mechanics. Specifically, the servo may need to be reconsidered, or replaced with a custom implementation. The power electronics will also be updated to supply higher current for the motor.
To improve the overall product design, consultation with mechanical engineers would be highly advisable in order to account for aspects we may have yet to consider. As for the ELEX 4330 Project Course, we would like to see a vastly improved lab as we were severely constrained in our ability to adequately test the device with the equipment supplied; specifically oscilloscopes, bench DMM’s and mechanical tools such as Dremel hand grinders, files and hacksaws.
�8
Formal Report for SmartLock
1. SMARTLOCK
1.1. Introduction
For completion of the Computer Control option of the Electrical and Computer Engineering Technology program at the British Columbia Institute of Technology, we were tasked with designing, developing, implementing and testing a project as part of the ELEX 4330 Technical Project course. For our project, we created a Bluetooth controlled door lock, named SmartLock. This report serves to record the process of design, development and manufacturing of the SmartLock. It was requested by Robert Trost, ELEX 4330 Technical Project Instructor, and Susan Woo, COMM 2443 Communications Instructor, in order to evaluate the technical aspects and to adequately document the project. During the development of the SmartLock, we referenced various datasheets and protocol specifications. For detailed information on these resources, refer to Appendix A.
1.1.1 Deadbolt Background
There are four important components to a standard household deadbolt. On the outside of the door, there is a keyhole allowing operation of the deadbolt with a key. Internal to the door is the deadbolt itself which moves between the locked and unlocked positions. The shaft runs perpendicularly through the door, actuating the deadbolt from within. On the rear of the door, connected to the shaft, is the thumbturn. Our project effectively replaces this component with an automated substitute allowing for remote control of the deadbolt.
�9
Formal Report for SmartLock
1.1.2 Organization of Report
The body of this report is divided into several sections, each referring to a specific aspect of the design process. We begin by describing the general functionality of the SmartLock including a block diagram of the device and its components. This is followed by a detailed description of each of the major blocks of the device. To demonstrate the various tests conducted throughout the development process, we have included our test plans and results followed by scope changes to the project. Finally, we analyze the successes and failures of the project with lessons learned, recommendations for future endeavours and a conclusion discussing our project’s accomplishments.
1.2 General Description and Block Diagram
As illustrated in Figure 1.1, the SmartLock is comprised of an Arduino Uno, utilizing an ATMega328P microcontroller, the nRF8001 Bluetooth Low Energy (BLE) module manufactured by Nordic, the CC3000 WiFI module manufactured by Texas Instruments, and a variety of electromechanical components, all of which can be found in Appendix B. Schematics detailing all connections for the SmartLock can be found in Appendix C.
FIGURE 1.1: SMARTLOCK BLOCK DIAGRAM
�10
Formal Report for SmartLock
The SmartLock uses the nRF8001 BLE module to communicate with its mobile app on any compatible smartphone, allowing it to be remotely controlled. When the user opens the SmartLock app on their smartphone, the app automatically connects to the SmartLock device, at which point it receives the status of the lock. The user can then tap on the lock or unlock button. This sends a command to the SmartLock using a BLE service designed to mimic universal asynchronous receiver/transmitter (UART). The SmartLock then activates the correct light-emitting diodes (LEDs), chirps the speaker, and rotates the servo according to the command sent and the status of the lock. Once it has successfully changed states, the SmartLock sends a reply over the same UART service to the phone, informing it that the command was completed successfully.
The SmartLock houses two LEDs to indicate the status of the lock: a red locked symbol, and a green unlocked symbol. These are illuminated according to the status of the lock. There is also a small speaker in the device that chirps once when the device is locked and twice when it is unlocked. The servo rotates 90 degrees in either direction in order to actuate the deadbolt to either the locked or unlocked position. When it has reached this endpoint, it returns to its neutral position so that the user can lock or unlock the door manually without damaging the internal components or fighting against the servo. As a result of this design, the user also has the ability to both lock and unlock the door manually: externally using their house key, or internally by rotating the SmartLock tumbler.
Were this product to be marketed commercially, we would have WiFi implemented in the device. The WiFi module would allow the SmartLock to communicate through a home router and the internet to a phone over long distances, allowing the user to perform various tasks remotely. Such tasks include remotely locking and unlocking the door, providing temporary guest access to visitors, logging door transactions, allowing the user to see when people have entered and exited, and viewing the battery life of the product.
�11
Formal Report for SmartLock
2. ELECTROMECHANICAL ACTUATION
2.1 Servo Mechanical Design Requirements
The primary goal for the SmartLock was the ability to lock and unlock the door electronically, while still permitting manual system override in case of battery failure, electromechanical failure, or lack of access to a phone. To achieve this goal, we required a mechanism that would have enough torque to rotate the deadbolt while also being able to disengage when in the neutral position. This feature serves the dual purpose of preventing damage to the device while allowing easier manual operation of the door lock. We also sought a small driver and mechanism to minimize the SmartLock footprint.
2.1.1 Design Considerations
In order to fulfill the aforementioned requirements, we chose to use a “mini-sized” hobby servo. This would give us the desired torque while reducing its footprint. Prior to making this decision, we considered several other options including stepper motors and standard DC motors. While stepper motors offer significant torque, they are generally quite large and would not fit inside our target design. In contrast, DC motors can be quite small; however, they provide low torque. In order to achieve an adequate torque, we would have required a significant reduction gear making the locking/unlocking process unacceptably slow.
DC motors and stepper motors also add additional complexity as they require separate controllers in order to deliver the power necessary to drive them but microcontrollers can only output minimal amounts of current from their I/O pins. In contrast, instead of relying on discrete drivers, as with DC or stepper motors, servos internally house all of the necessary driver circuitry and simply require connections to power, ground, and control signal. Additionally, the microcontroller outputs a pulse width modulated (PWM) signal to the servo’s control pin to actuate the servo horn.
�12
Formal Report for SmartLock
2.1.2 Servo Rotation
PWM is a method of encoding information in the duty cycle of a square wave. It is typically used to emulate an analog output from a device only capable of digital outputs. The device sets the duty cycle of a high frequency square wave according to the percentage of the output voltage that equates to the analog voltage required. This is typically then passed through a low-pass filter to convert it from a digital waveform to an analog voltage.
Servos use a modified version of PWM for their control system as their internal controllers are also digital and do not require an analog signal to operate. While PWM signals designed to output analog voltages can operate at any reasonably high frequency, servos require a very specific frequency of 50 Hz, which translates to a period of 20 ms. While standard PWM allows for manipulating the duty cycle between 0 and 100%, servo PWM requires a positive pulse width between 1 and 2 ms, which translates to a range of 5 to 10% of the signal waveform.
2.1.3 Absolute Positioning
Another design consideration was the need to know the current orientation of the lock mechanism. Neither a stepper motor, nor a DC motor, would provide us with absolute position control; they can only be moved relative to their previous position, requiring zeroing in order to ascertain their position. A servo, however, is capable of absolute position control once it has been initially calibrated. After the servo has been calibrated in the lab, achieved by measuring the degree of rotation acquired from a specific pulse width, it can easily be tuned to rotate a specific number of degrees with a high level of precision.
The servo accomplishes this by using a small geared motor which is connected to a potentiometer. The position of the servo’s shaft is recorded and this information is sent back to the built in controller. The controller uses this information, combined with the input PWM signal, to decide whether the servo needs to continue rotation or if it has already reached its desired location.
�13
Formal Report for SmartLock
2.2 Servo Connection Requirements
After making the decision to proceed with the design using a servo to drive the SmartLock, the best way to connect it to the rotating metal shaft that activates the deadbolt had to be determined. This shaft rotates approximately 90 degrees resulting in the deadbolt extending or retracting. Unfortunately, there is no simple way to directly connect the servo to the shaft, as that would prevent the user from manually operating the lock. Had the servo been connected directly to the shaft, manual operation would result in a struggle against the servo, stressing it and potentially resulting in a catastrophic failure.
2.2.1 Key and Tumbler Design
The solution to overcome this challenge was very similar to that of the existing key and tumbler. When a key is inserted into a lock, it is rotated in a direction consistent with locking or unlocking the door. It is then returned to a neutral position in order to remove it from the lock. This is made possible by connecting the tumbler and the shaft via a mechanism that allows the key to rotate freely in the range of 90 and 180 degrees.
When the key is turned initially, the lock is activated. When the key is returned to its neutral position, the tumbler is also rotated back to neutral. As a result of this limited slip and neutral position, a user on the other side of the door can both lock and unlock the door with the thumbturn without impediment from the key and tumbler mechanism. In summary, as long as the tumbler is in its neutral position, it does not affect the activation or deactivation of the deadbolt.
�14
Formal Report for SmartLock
2.2.2 Emulating Similar Mechanics with a Servo
To apply this technique to the electromechanical system of the SmartLock, the servo was required to rotate more than the 90 degrees required to activate the deadbolt into a locked position. In addition, the servo had to always return to a neutral position, allowing the user to operate the lock manually using either a key or the SmartLock’s tumbler. To meet these requirements, we required a servo that could rotate at least 180 degrees: 90 to actuate the deadbolt and an additional 90 degrees to allow for the necessary mechanical slippage.
When the SmartLock is idle, the servo sits in its neutral state. When a lock command is applied, the servo is rotated 90 degrees to its end point, rotating the tumbler and activating the locking mechanism. When the door has successfully been locked, the servo rotates 90 degrees back to its neutral position. See Figure 2.1 for a diagram illustrating the locking process. To unlock the door, the servo initially rotates in the opposite direction, before returning to neutral.
FIGURE 2.1: AUTOMATION OF SMARTLOCK LOCKING
1. A lock command is sent to the SmartLock 2. The servo, sitting in its neutral position, rotates 90 degrees thus actuating the deadbolt 3. Once the deadbolt is actuated, the servo rotates back 90 degrees to its neutral position
�15
Formal Report for SmartLock
2.2.3 Connecting and Positioning the Servo
Initial approaches for accomplishing the aforementioned design included lengthening the servo arm and adding two pegs, separated by 90 degrees, to the internal rotating portion of the lock. However, to reduce the size of the actuation mechanism, this design was scrapped. The enhanced design consisted of a modified servo horn attachment with a raised section equivalent to 90 degrees and a matching raised section inside the lock equivalent to 180 degrees, as see Figure 2.2.
This design allows the servo to rotate freely up to the remaining 90 degrees while still activating the lock 90 degrees in either direction. It also allows for placement of the servo directly over the shaft, as opposed to placing it beside the shaft, as seen in Figure 2.2. This allows for maximum torque output from the servo to the lock shaft.
FIGURE 2.2: SERVO HORN ATTACHMENT AND SERVO POSITION
�16
Formal Report for SmartLock
2.3 Designing the SmartLock Manual Override
As outlined previously, allowing the user to manually operate the lock from inside or out without relying on the electromechanical system was a fundamental requirement of the SmartLock. To facilitate the manual operation from inside the house, the SmartLock was designed so that its main housing is a tumbler attaching internally to the lock shaft. As a result, the user can simply rotate the tumbler, which directly translates the rotational movement to the lock shaft, locking or unlocking the door.
2.3.1 Adding Manual Position Detection
For all of the electromechanical components to work correctly, the system requires the ability to detect the orientation of the lock, particularly if it is manually operated. Otherwise, the device would light the inappropriate LED and the app would suggest the user perform the incorrect operation. Beyond the simple irritation factor such a flaw could present to the user, it would also represent a fundamental security flaw as the user could assume the door is locked when in reality it remains unlocked.
To solve this challenge, SmartLock employs the use of two microswitches to detect the present state of the SmartLock. As seen in Figure 2.3, these switches are located at either end of the mechanical range and are activated when the tumbler arm comes into contact. This allows the SmartLock to always determine the true orientation of the deadbolt, and update all electromechanical elements appropriately.
FIGURE 2.3: MICROSWITCH MOUNTS IN SMARTLOCK HOUSING
�17
Formal Report for SmartLock
2.3.2 Utilizing Manual Position Detection
As mentioned above, using manual position detection allows the SmartLock to always know the true state of the deadbolt regardless of whether it was manually or electronically actuated. This allows the system to update the SmartLock mobile app when it is operated manually. It also allows the device to keep a log of all door activity, including lock and unlock activity and how the activity was performed, through a simple web interface.
This information is also utilized when electronically actuating the deadbolt. It allows the SmartLock to confirm that a lock or unlock command had been completed successfully. If there were an impedance, or the operation did not complete successfully, the switch would not activate and the command would return an error. It would also allow the device to notify the user audibly using the speaker and through the SmartLock mobile app.
�18
Formal Report for SmartLock
3. POWER
3.1 Design Considerations
The SmartLock is powered using two AA batteries, therefore power consumption needed to be minimized to ensure maximum efficiency, and reasonable battery longevity. To achieve this, the majority of the SmartLock’s modules are connected directly to the batteries. In situations where the voltage supplied by the batteries is not great enough, boost converters are used sparingly to achieve the desired voltage levels. This is done by way of the shutdown pins on the boost controller, allowing the microcontroller to effectively turn it off whenever it is not in use. The ATMega328P microcontroller will spend the majority of its time in low power mode, only waking to communicate over Bluetooth or to control the electromechanical elements.
3.2 Overview/Summary
The two AA batteries will directly power the ATMega328P microcontroller, the nRF8001 Bluetooth module, and the VIO_HOST rail for the CC3000 WiFi module. A 5V boost converter will power the Servo and a 3.3V boost converter will power the VBAT_IN of the WiFi module. In standby mode, the SmartLock system has an expected current drain of less than 1mA.
�19
Formal Report for SmartLock
3.3 Battery Selection
The decision to power the SmartLock using two AA batteries was made primarily due to the common utilization of AA batteries in the average household, in addition to their ability to provide months of power before needing to be replaced. A single AA battery is advertised as providing between 1700 and 3000 mAh. The nominal voltage is 1.55V to 1.65V when fully charged and drops to between 0.7 and 1.0V when depleted. When the battery voltage drops below 1.3V a low battery warning is issued. See Figure 3.1 for a graph describing the nominal voltage of an AA battery over its lifespan.
FIGURE 3.1: BATTERY DISCHARGE CURVE
" (http://www.powerstream.com/AA-tests.htm)
As can be seen above, the battery voltage discharges linearly during its regular operating capacity but drops off rapidly at the end of its life around 2000mAh. To prevent abnormal behaviour, SmartLock ensures its batteries are operating in the linear region.
�20
Formal Report for SmartLock
3.4 ATMega328P Microcontroller Requirements
The ATMega328P microcontroller is the primary component of the SmartLock. For maximum efficiency, it is being powered directly from the batteries. As mentioned previously, two AA batteries in series provide a nominal voltage of approximately 3.0V and when fully discharged provide a voltage of approximately 1.4V. The microcontroller is capable of operation with voltages as low as 1.8V, allowing it to continue operating for an extended duration after the low voltage warning (2.6V). At low voltages, current drain is anticipated to be less than 1mA. See Figure 3.2 for a graph of supply current with respect to clock frequency.
FIGURE 3.2: ATMEGA328P: ACTIVE SUPPLY CURRENT VS. FREQUENCY
(ATMega328 Data sheet)
Powering the SmartLock via two AA batteries limits us to operating along the 2.7V curve. In order to be as efficient as possible, the ATMega328P will operate at a frequency less than 10MHz.
�21
Formal Report for SmartLock
3.5 nRF8001 Bluetooth Module Requirements
A primary factor in the decision to use the nRF8001 Bluetooth module is its ability to operate using 3V. As discussed above, the two AA batteries provide a nominal voltage of 3V allowing for direct connection to the nRF8001. As can be seen in Table 3.1, the Bluetooth module has a very low idle current of 2 uA and peaks at 14.6mA while receiving data.
TABLE 3.1: NRF8001 CURRENT CONSUMPTION PARAMETERS
(nRF8001 Datasheet)
�22
Formal Report for SmartLock
3.6 CC3000 WiFi Module Requirements
The WiFi Module has two voltage rails, VBAT_IN and VIO_HOST. VBAT_IN powers the chip and has a recommended voltage of 3.3V which is supplied using a boost converter. VIO_HOST sets the voltage levels for interfacing with the microcontroller and is powered directly from the batteries, as is the microcontroller. As shown in Table 3.2, of the various components, excluding the servo, the CC3000 WiFi module has the largest current drain when active at 275mA. However, the shut-down mode current drain is a minimal 5uA.
TABLE 3.2: CC3000 POWER CONSUMPTION
(CC3000 TI datasheet)
3.7 HS-225BB Servo Requirements
For regular operation the servo requires a nominal 5V and is supplied using a boost converter. To limit overall current draw, the boost converter is shutdown when the servo is not in use. While rotating with no load, the servo draws 300mAl however, under load it peaked around 800mA. See the datasheet in Appendix A for further specifications.
�23
Formal Report for SmartLock
3.8 AAT1217 SOT23-6 Package Boost Controller
The SmartLock uses the AAT1217 SOT23-6 Package Boost Controller for both the 3.3V and 5V boost converters. See Figure 3.3 for the efficiency of the package when generating 3.3V and 5V outputs, and Figure 3.5 for complete schematics of both boost converters. This package was chosen for the following features:
• Low current shutdown ability
• 400mA Output from a Dual AA Cell
• Provides 3.3V and 5V outputs
• High efficiency (up to 93%)
• Low cost: $0.50 on Digi-Key
FIGURE 3.3: EFFICIENCY VS. OUTPUT CURRENT FOR 3.3V AND 5V OUTPUTS
(AAT1217 Datasheet)
To predict the efficiency, the 2.4V line is used when considering a dual AA battery source. Recall that when active, the WiFi module uses approximately 275mA at 3.3V and the servo uses between 500mA and 1A when operating at 5V.
�24
Formal Report for SmartLock
3.8.1 Output Current
As previously discussed, the servo draws large spikes in current during operation. Initial estimates for peak servo current draw were approximately 500mA; however, measurements demonstrated peak currents of up to 800mA. As illustrated in Figure 3.4, when providing an input of 3V from dual AA batteries and an output of 5V, the design is limited to an output of approximately 450mA. This is insufficient, and as a result corrections to the power design are required to accommodate the higher current draw. Refer to Section 9, Scope Changes, for further details.
FIGURE 3.4: MAXIMUM OUTPUT CURRENT VS. INPUT VOLTAGE
(ATT1217 Datasheet)
�25
Formal Report for SmartLock
FIGURE 3.5: SCHEMATICS FOR 3.3V AND 5V BOOST CONVERTERS
As previously mentioned, the boost converters can be placed into shutdown mode via the !SHDN pin. This pin is connected to the microcontroller and pulled low when the boost converter is not in use.
�26
Formal Report for SmartLock
4. 3D DESIGN
In order to produce a prototype SmartLock, 3D printing was selected for manufacturing as it offers the flexibility to quickly revise designs with relatively low costs. Autodesk Inventor 2013 was used to model the 3D prototype.
4.1 Modelling
This section describes each component of the 3D printed enclosure, with illustrations of each and a brief description as to the purpose of the piece.
FIGURE 4.1: BACKPLANE
The backplane is the foundation of the SmartLock. It attaches to the deadbolt metal plate via two pre-existing bolts. It supports the body housing while providing a ring guide for the tumbler, holes for the door bolts, and mounts for the microswitches.
FIGURE 4.2: TUMBLER
The tumbler connects to the lock shaft through a rectangular cutout at the centre of its arm. When rotated, the tumbler actuates the lock shaft, locking and unlocking the door. The microswitches, as described previously, are mounted on the platforms at either end of the arm rotation. As illustrated on the right, the tumbler and SmartLock are presently in the unlocked position.
�27
Formal Report for SmartLock
FIGURE 4.3: BODY HOUSING
The body housing provides compartments for each AA battery and the servo, in addition to holes for the LEDs, supporting screw holes, a slot for programming and indentations for alignment of the top cover (to be discussed in the next section). Adjacent to the servo, the round PCB is mounted behind the battery compartments. The battery pins are soldered directly to the PCB and light pipes extend up towards the LED holes. The rectangular programming hole at the base is for a 6x1 pin header used during manufacturing and debugging of the device.
�28
Formal Report for SmartLock
FIGURE 4.4: TOP COVER
The top cover of the SmartLock is the cap of the device and transmits the glow from the LEDs and conceals the electromechanical components. The centre hole allows it to be screwed into the body housing. On the back of the top cover are three tabs which align the with the body housing. It was designed to be easily removable, allowing the user quick access to replace the batteries.
�29
Formal Report for SmartLock
4.2 3D Printing
As discussed earlier, the SmartLock prototype was constructed using 3D printing. The initial plan was to use Albert’s personal 3D printer; however, during the manufacturing process it encountered technical difficulties. As a result, we were forced to seek an alternative, and Integral Dental Lab generously offered to print the prototype.
4.2.1 First Prototype
The first prototype was constructed from resin using a process called stereolithography (SLA). While allowing for incredibly high resolution prints, the material proved to be extremely brittle and unsuitable for our applications. Figure 4.5 shows the initial prototype cracked in multiple places. Another disadvantage of the material was a tacky surface which inhibited rotation.
FIGURE 4.5: FIRST PROTOTYPE, PRINTED IN RESIN
�30
Formal Report for SmartLock
4.2.2 Second Revision
The second revision was printed with acrylonitrile butadiene styrene (ABS) plastic using the process fused deposition modelling (FDM) at the BCIT Tech Centre by Dan Leland. These parts were much stronger and more durable than our first prototype, while also having a much lower coefficient of friction. Figure 4.6 shows the printed ABS pieces screwed together into the door.
FIGURE 4.6: SECOND PROTOTYPE, PRINTED IN ABS PLASTIC
�31
Formal Report for SmartLock
5. BLUETOOTH LOW ENERGY
Bluetooth Low Energy (BLE), commonly referred to as Bluetooth Smart, is a subset of the Bluetooth standard and is marketed by the Bluetooth Special Interest Group (Bluetooth SIG, Inc., 2014). The standard was designed with high power efficiency in mind, making it an ideal candidate for devices with limited power.
We utilize BLE in the SmartLock for the following reasons:
1. It is power efficient which is of the utmost importance to our project as we must power all the components with two AA batteries.
2. It is implemented in the vast majority of current generation smartphones.
3. It is relatively simple to implement when compared to other wireless communications standards, including classic Bluetooth, expediting the development process.
The BLE stack defines two layers for communication: the Generic Access Profile (GAP) and the Generic Attribute Profile (GATT) (Texas Instruments Inc., 2013).
5.1 Generic Access Profile
According to Texas Instruments Inc. (2013), “The GAP layer of the BLE Protocol Stack is responsible for handling the device’s access modes and procedures, including device discovery, link establishment, link termination, initiation of security features, and device configuration” (p. 12).
The GAP layer defines two primary roles for devices: peripherals and centrals. Peripheral devices are defined as small, low power accessories; in this instance, the SmartLock. Central devices generally have much more processing power, such as a smartphone or tablet.
�32
Formal Report for SmartLock
During the GAP advertising process, the peripheral device advertises itself and waits for a response from a central device. At this point, the central device can send a scan response request for more information, or seek a connection with the peripheral. If it requests further information, the peripheral can send an optional scan response data packet. A peripheral device may advertise itself to multiple central devices concurrently, and can send scan response data packets to all of them.
5.2 Generic Attribute Profile
Once a central device has established a connection with a peripheral device, the GATT layer is utilized for all communication between the two devices (Texas Instruments Inc., 2013). When connected to a central device, a peripheral is exclusively connected to that specific central and ceases advertising itself to other centrals; however, a central device may have multiple peripheral connections.
When referring to the GATT layer of communication, the devices are no longer technically referred to as peripheral and central, but instead, client and server. Furthermore, there is no direct correlation between peripheral/central and client/server, as either a peripheral or a central can be a client or a server (Texas Instruments Inc., 2013). In our usage scenario, the SmartLock is acting as the GATT server as it has the data we are reading: the lock/unlock status of the device and door. As a result, our central device, the smartphone, is fulfilling the role of GATT client, which reads and writes data to the GATT server.
5.3 Profile, Services and Characteristics
A GATT server defines the terms of communication between itself and the GATT client by creating a profile for itself. This profile outlines all the services available for communication between the server and client, and each service’s characteristics.
�33
Formal Report for SmartLock
Services and characteristics are defined by Adafruit (2014) as follows:
Services are used to break data up into logic entities, and contain specific chunks of data called characteristics. A service can have one or more characteristics, and each service distinguishes itself from other services by means of a unique numeric ID called a UUID, which can be either 16-bit (for officially adopted BLE Services) or 128-bit (for custom services).
The lowest level concept in GATT transactions is the Characteristic, which encapsulates a single data point (though it may contain an array of related data, such as X/Y/Z values from a 3-axis accelerometer, etc.).
Similarly to Services, each Characteristic distinguishes itself via a pre-defined 16-bit or 128-bit UUID, and you're free to use the standard characteristics defined by the Bluetooth SIG (which ensures interoperability across and BLE-enabled HW/SW) or define your own custom characteristics which only your peripheral and SW understands.
The SmartLock has a single service that is a software implementation of UART for all communication between the SmartLock app and device. The service has two characteristics: TX for transmitting data and RX for receiving data. The UUIDs for the service and its characteristics are as follows:
UART Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E TX Characteristic: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E RX Characteristic: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E
�34
Formal Report for SmartLock
6. FIRMWARE
The SmartLock is controlled using an Arduino Uno, with an ATMega328P microcontroller. The firmware is written in C and compiled using the Arduino libraries and compiler. See Appendix D for the Firmware source code.
The firmware for the SmartLock initializes all of the I/O as well as the BLE module, and begins advertising the device. Once the SmartLock is connected to a central device, the firmware interprets all received commands and calls the appropriate functions. Please refer to the lock and unlock functions in Figure 6.1, and a high level flowchart for the firmware process in Figure 6.2.
FIGURE 6.1: FLOWCHART FOR FIRMWARE LOCK AND UNLOCK FUNCTIONS
�35
Formal Report for SmartLock
FIGURE 6.2: FLOWCHART FOR MICROCONTROLLER FIRMWARE
�36
Formal Report for SmartLock
7. SOFTWARE
We have designed a custom mobile app for SmartLock that runs on the iPhone making use of Apple’s latest hardware, operating system, and programming language (Swift). Using BLE, the app is able to lock and unlock the device using either button controls or proximity detection. Refer to Appendix E for the iOS source code.
7.1 Swift
At its World Wide Developers Conference in June of this year, Apple unveiled a brand new programming language for its desktop and mobile platforms. As described on Apple’s website (2014), “Swift is a powerful and intuitive new programming language created by Apple for building iOS and Mac apps. It’s designed to give advanced developers the freedom and capabilities they need to create a new generation of cutting-edge apps. It also opens up a whole new world of possibilities for everyone else. Swift is easy to learn and use — even if you’ve never coded before. So now anyone with an idea can create something incredible.”
By using the newest programming language, the SmartLock app is forward-looking, ensuring future compatibility with Apple products. Furthermore, Swift is a clean programming language and allows for quick prototyping using the storyboard feature. As the language is only six months old, there were limited resources available during development of the app. Consequently, most documentation was provided in Apple’s old programming language Objective-C, and had to be converted to the new language.
�37
Formal Report for SmartLock
7.2 SmartLock Class
The SmartLock app makes use of a SmartLock class which inherits from the NSObject base class and implements the protocols for CBCentralManagerDelegate and CBPeripheralDelegate. This allows a SmartLock object to implement all the necessary functions to act as a central manager while having functions to communicate with the SmartLock peripheral. In addition to these required functions, the SmartLock class also implements the functions to perform the following actions:
1. Locking and unlocking the door,
2. Determining the RSSI (signal strength),
3. Enabling/disabling the RSSI timer,
4. Generating console and view output strings.
The lock and unlock functions ensure the iPhone is still connected to a SmartLock and that it is in the correct lock position. If these conditions are met, they send the appropriate command to the SmartLock (as described previously in the SmartLock Firmware).
For more information on all of the functions, refer to the iOS app source code in Appendix E.
�38
Formal Report for SmartLock
7.3 SmartLock Mobile App
The SmartLock mobile app has two separate views. See Figure 7.1 for the primary view and the debug view. The app creates one instance of a SmartLock object which is shared between both views and handles all communication to the device. For detailed instructions on how to install the SmartLock and communicate to it using the SmartLock mobile app, refer to Appendix F.
FIGURE 7.1: PRIMARY VIEW AND DEBUG VIEW, RESPECTIVELY
In the following flowcharts, we illustrate the connection process (Figure 7.2), the flow of controlling the SmartLock using button controls (Figure 7.3), and the flow of controlling the SmartLock using proximity detection (Figure 7.4).
�39
Formal Report for SmartLock
FIGURE 7.2: FLOWCHART FOR CONNECTING TO SMARTLOCK
FIGURE 7.3: FLOWCHART FOR APP BUTTON CONTROLS
�40
Formal Report for SmartLock
FIGURE 7.4: FLOWCHART FOR PROXIMITY DETECTION
Proximity detection works by using the RSSI of the peripheral device with respect to the central device. When proximity mode is enabled (currently controlled through a toggle in the debug view) a half-second timer is engaged, which calls a function to update the RSSI values on timeout. This function stores the RSSI dBm values in an array which it then uses to determine the current average RSSI value, effectively eliminating inconsistencies in the readings. Once the values are averaged, that value is compared against threshold values to determine what actions to perform. The lock and unlock threshold are staggered similarly to voltage hysteresis to prevent rapid lock and unlock fluctuations. In testing, it was determined that an approximate hysteresis of 6dBm was sufficient to prevent this behaviour. The precise threshold values are dependent upon the environment in which the SmartLock resides.
�41
Formal Report for SmartLock
8. TEST PLANS AND RESULTS
8.1 Servo Drain and Battery Test
The purpose of the test was to measure the servo current draw.
8.1.1 Results
The servo was found to draw substantially more current than had been anticipated. This resulted in the Arduino resetting whenever the servo was engaged. The current draw was measured on an oscilloscope using a current sense resistor, and peak current was measured at 1.3A. The boost controller selected for the demo provided a maximum output of 600mA, which was insufficient.
8.1.2 Solutions Attempted
1. Used capacitors to minimize current spikes which did not have the desired effect.
2. Added an inductor in series with the servo which successfully prevented the Arduino from resetting; however, it reduced the speed of the servo.
8.1.3 Recommendations
Selecting a boost converter with a higher current output should resolve these issues. Further inquiry into the electromechanical actuation is also required to minimize current spikes caused by resistance in the deadbolt.
�42
Formal Report for SmartLock
8.2 First Assembly of 3D Printed Parts
The purpose of this test was to assemble the first version of the 3D printed pieces.
8.2.1 Results
1. Resin used was too brittle causing pieces to crack,
2. Tumbler ring tolerance was insufficient for smooth rotation against the ring guide,
3. Servo container was too shallow and narrow due to insufficient tolerance,
4. Backplane supports were insufficient for handling device torque,
5. Servo horn attachment required redesign for correct actuation.
8.2.2 Revisions
1. Changed to ABS printed pieces,
2. Updated all component tolerances, particularly the tumbler,
3. Increased the height of the SmartLock to accommodate the Servo,
4. Modified the supports from pillars to large blocks for increased rigidity.
�43
Formal Report for SmartLock
8.3 Second Assembly of 3D Printed Parts
The purpose of this test was to assemble the second revision of the printed parts and to ensure correct electromechanical actuation.
8.3.1 Results
1. The majority of parts fit together correctly; however, there was a slight issue with the tolerance on the body housing ring guide.
2. The servo horn attachment was attempting to translate laterally as opposed to expending all force in the rotation which was causing the tumbler ring to torque, thus preventing the deadbolt from actuating.
8.3.2 Revisions
1. The body housing ring guide was sanded, allowing all parts to seat correctly,
2. A channel was carved into the tumbler arm,
3. The servo horn attachment was outfitted with a ring.
When coupled with the channel in the tumbler arm, the servo horn attachment was forced to rotate exclusively resulting in correct electromechanical actuation of the deadbolt.
�44
Formal Report for SmartLock
8.4 Bluetooth Control Testing
The purpose of this test was to confirm successful wiring of the various modules and communication between the custom Arduino firmware and the custom iOS app.
8.4.1 Verification of Hardware
Procedure:
Test the Adafruit iOS app in conjunction with the Adafruit Arduino firmware to ensure working hardware.
Result:
With the Arduino wired correctly, we were able to control the LEDs.
8.4.2 Verification of Firmware
Procedure:
Upload the custom SmartLock firmware, and verify correct operation using the known-good Adafruit iOS app and hardware configuration.
Result:
We were able to verify correct operation when sending ‘L’ and ‘U’ through the UART view.
�45
Formal Report for SmartLock
8.4.3 Verification of Software
Procedure:
Run the custom SmartLock app on iPhone, and verify correct operation using the known-good SmartLock firmware and hardware configuration.
Result:
We were able to verify correct operation when sending lock and unlock commands. Verified proximity detection using debug mode also performed correctly.
8.4.4 Revisions
During proximity testing, we concluded that the RSSI readings provided by the peripheral fluctuated wildly. To accommodate this, we introduce hysteresis into our proximity thresholds and recorded four RSSI readings every half second to obtain an average.
�46
Formal Report for SmartLock
9. SCOPE CHANGES
The following scope changes were made to the project as development progressed or are suggestions for changes going forward.
1. WiFi was not implemented,
2. Encryption was not implemented,
3. Microswitches were not installed,
4. Boost controller selection needs to be revised.
Due to timing constraints, WiFi implementation was not possible; however, this is definitely a feature that would need to be implemented in a final product as it allows the SmartLock to truly differentiate itself from competitors. Similarly, proper encryption was not implemented for lack of time and experience with true encryption. This would also have to be implemented in the final product.
In the second revision of the prototype, adequate tolerance was not provided for the microswitches preventing us from successfully installing them. Modifications were made to the 3D model; however, we were unable to print a third revision.
After extensive testing, it was determined that the current requirements of the servo exceeded our initial estimates. As a result, it is necessary to select a boost controller capable of outputting a sufficient amount of current.
�47
Formal Report for SmartLock
10. ANALYSIS OF SUCCESS AND FAILURE
10.1 Successes
10.1.1 iOS App
The custom mobile app for iOS allows the user to successfully control the SmartLock using button controls and proximity detection. While the proximity detection is not perfect, improving it will be difficult without acquiring more accurate RSSI values which most likely involves sourcing a better BLE module.
10.1.2 3D Printed Parts
As with any prototyping, constant iteration is necessary to create a functioning product. With the SmartLock project, multiple revisions were required for correct electromechanical functionality and proper alignment of all 3D printed pieces. However, the final printed prototype, the second revision, functioned correctly and should be considered a success.
10.2 Failures
10.2.1 Boost Converters
As discussed in the test reports, the servo drew much more current than expected which resulted in the power electronics being inadequate. If provided the opportunity to reselect components, components with a larger tolerance would have been selected. Furthermore, additional testing of the power components should have been performed earlier as the mechanical components were largely irrelevant in this testing.
�48
Formal Report for SmartLock
11. CONCLUSION
With this project, we sought to create a replacement for the deadbolt thumbturn that could be controlled using Bluetooth on a mobile device. In this endeavour, we were successful. We were also exposed to the interplay of electromechanical components and software. Each team member was assigned a specific set of tasks relating to the global design of the device, and each was successful in implementing and testing his duties.
In the initial planning stages of the SmartLock, we had the following primary design goals:
1. Create a Bluetooth controlled thumbturn to electronically actuate a deadbolt,
2. Implement proximity detection to simplify locking and unlocking the door.
During our presentation of the SmartLock, we were able to provide an effective and successful demonstration of the product locking and unlocking using a mobile device. In addition, we were also able to demonstrate proximity detection and manual operation. As a result, we consider the SmartLock project to be a huge success and we are thrilled with the results.
11.1 Electromechanical and Manual Operation
Both electromechanical and manual operation of the SmartLock worked correctly. Specifically, manual operation proved to be a very kinaesthetically-pleasing experience when compared with a regular thumbturn. As mentioned previously, however, redesign of the mechanical system may be necessary to improve reliability.
�49
Formal Report for SmartLock
11.2 Bluetooth Control and Proximity Detection
Bluetooth communication through the iOS app was successful and worked consistently. The proximity detection was affected by errant RSSI readings; however, this was largely due to the Bluetooth module.
11.3 Lessons Learned
The primary lesson learned is that hardware development is substantially more difficult and time consuming than software development. While the firmware and mobile app were able to be tested easily until proper operation was achieved, mechanical testing required all components to be obtained prior to proceeding. As a result, testing of the electromechanical actuation was fairly late with respect to the presentation and due date of the project, and this limited the amount of revision possible. Furthermore, project risk could be reduced by limiting reliance on 3D printers as they are prone to problems. Specifically we encountered issues with print tolerance, and in the case of Albert’s printer, catastrophic failure.
Each member of the team was responsible for a section of the development of the project. As a result, we each learned a tremendous amount of new information about our specific areas of focus.
James spent the majority of his time learning about coupling servos to other mechanical devices, and powering servos from various power sources.
Albert learned about boost converters, 3D printing, and 3D modelling with Autodesk Inventor. He also discovered the difficulty in assembling a personal 3D printer.
Elliot conducted extensive research into the operation of Bluetooth Low Energy and WiFi, in addition to learning Apple’s programming languages Swift and Objective-C. He was exposed to the difficulties of troubleshooting and debugging mobile app development, particularly mobile communication.
�50
Formal Report for SmartLock
12. RECOMMENDATIONS
Throughout the course of this report, there have been many recommendations for further development of the SmartLock.
Mechanically, the SmartLock design needs to be smaller, as its current footprint is borderline excessive. This can be accomplished by re-evaluating different types of motors for electromechanical actuation, as the servo took up the majority of the existing space in the prototype. Ideally, a custom motor could be manufactured with a small footprint while providing an adequate amount of torque. Selecting a different motor would require redesigning the mechanical aspect to work with the new device, while also making it compact.
As discussed extensively in the Tests and Results section, to meet the demands of the servo during actuation, selecting a different boost converter that can provide higher current is required.
The firmware and software need further revision to introduce extensive security and to implement the SmartLock WiFi functionality. Development of a web server platform would also be required.
Recommendations for improving the learning experience offered by the ELEX 4330 project course include providing students with access to experts in various fields. Allowing students to interact with mechanical and material engineers would reduce some of the burden of having electrical engineering students trying to devise complex mechanical solutions. This would also expose them to other disciplines of engineering. Furthermore, the extensive workload through Level Four does not take into consideration the necessary time to work on the project, despite the project’s immense time requirements. Finally, the equipment provided in the project room is entirely insufficient for adequate development. The analog oscilloscopes return inconsistent information, and the power supplies’ output voltages fluctuate wildly causing significant issues during testing.
�51
Formal Report for SmartLock
13. DOCUMENTATION REFERENCES
Adafruit. (2014, March 20). Introduction to Bluetooth Low Energy. Retrieved December 18, 2014, from https://learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt
Apple Inc. (2014, June). Swift. A new language that lets everyone build amazing apps. Retrieved December 18, 2014, from http://www.apple.com/swift/
Bluetooth SIG, Inc. (2014). Bluetooth Smart Technology: Powering the Internet of Things. Retrieved December 17, 2014, from http://www.bluetooth.com/Pages/Bluetooth-Smart.aspx
Robotzone, LLC. (n.d.). HS-225BB Mighty Mini. Retrieved December 12, 2014, from https://www.servocity.com/html/hs-225bb_mighty_mini.html#.VJJdQTHF97U
Texas Instruments Inc. (2013). BLE Protocol Stack. In Texas Instruments CC2540/41 Bluetooth® Low Energy Software Developer’s Guide v1.3.2 (Vol. 1.3.2). Retrieved December 17, 2014, from http://www.ti.com/lit/ug/swru271f/swru271f.pdf
�52
Formal Report for SmartLock
Appendices
Appendix A: Resources Appendix B: Bill of Materials Appendix C: Device Schematics Appendix D: SmartLock Firmware Source Code Appendix E: SmartLock iOS APP Source Code Appendix F: User Manual Appendix G: Gantt Chart Appendix H: Style Guide
Formal Report for SmartLock
APPENDIX A: RESOURCES
The following are links to datasheets and API references which we have used throughout our SmartLock project.
Datasheets:
• AAT1217 SMD Boost Converter: http://www.skyworksinc.com/uploads/documents/AAT1217_202050B.pdf
• Arduino Configuration: https://learn.adafruit.com/getting-started-with-the-nrf8001-bluefruit-le-breakout/testing-uart
• ATMega328 Microcontroller: http://www.atmel.com/images/atmel-8271-8-bit-avr-microcontroller-atmega48a-48pa-88a-88pa-168a-168pa-328-328p_datasheet.pdf
• CC3000 WiFi Module: http://www.ti.com/lit/ds/symlink/cc3000.pdf
• HS-225BB Servo: http://www.robotshop.com/media/files/pdf/hs225bb.pdf
• LT1302 Thru-hole Boost Converter (Demo): http://cds.linear.com/docs/en/datasheet/lt1302.pdf
• nRF8001 Bluetooth Module: http://www.nordicsemi.com/eng/content/download/2981/38488/file/nRF8001_PS_v1.2.pdf
Formal Report for SmartLock
Swift API References:
• Core Bluetooth Framework Reference: https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CoreBluetooth_Framework/index.html
• Bluetooth LE Connection Sequence: https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/PerformingCommonCentralRoleTasks/PerformingCommonCentralRoleTasks.html
• CBCentralManager Class API: https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBCentralManager_Class/index.html
• CBCentralManagerDelegate Protocol API: https://developer.apple.com/Library/mac/documentation/CoreBluetooth/Reference/CBCentralManagerDelegate_Protocol/index.html
• CBPeripheral Class API: https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBPeripheral_Class/index.html
• CBPeripheralDelegate Protocol API: https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBPeripheralDelegate_Protocol/index.html
• CBService Class API: https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBService_Class/index.html
• CBCharacteristic Class API: https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBCharacteristic_Class/index.html
• NSData Class API: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/index.html
Formal Report for SmartLock
APPENDIX B: BILL OF MATERIALS
The following parts were used in the creation of the SmartLock. Unless otherwise noted, all parts were ordered through Digi-Key.
Qty
Qty
to O
RD
ER
Par
tM
anuf
actu
rer P
art #
Dig
ikey
Par
t #P
acka
ge T
ype
Cos
t/Uni
tC
ost T
otal
Whe
reN
ote
Boo
st C
onve
rter P
arts
25
Boo
st C
onv
AD
JA
AT1
217I
CA
-1.2
-T1
863-
1495
-1-N
DS
OT2
3-6
$0.5
3$1
.06
Dig
ikey
2 B
oost
ers
210
4.7u
F 16
V C
aps
CL2
1A47
5KO
FNN
NE
1276
-106
5-1-
ND
805
$0.1
7$0
.34
Dig
ikey
Inpu
t and
O/P
Cap
s fo
r sw
itchi
ng C
ontro
ller
14
Sch
ottk
y 1A
Dio
deP
ME
G30
10E
R,1
1556
8-65
13-1
-ND
SO
D-1
23W
$0.5
8$0
.58
Dig
ikey
For s
witc
hing
30
10uH
indu
ctor
NR
6045
T100
M58
7-20
81-1
-ND
SM
D$0
.44
$1.3
2D
igik
eynr
6045
sm
d in
duct
or4
101.
02M
Res
isto
rE
RJ-
6EN
F102
4VP
1.02
BTC
T-N
D80
5$0
.13
$0.5
2D
igik
eyFe
edba
ck re
s an
d pu
lldow
ns1
1033
2k R
esis
tor
ER
J-6E
NF3
323V
P33
2KC
CT-
ND
805
$0.1
3$0
.13
Dig
ikey
5v fe
edba
ck re
s1
1060
4k R
esis
tor
ER
J-6E
NF6
043V
P60
4KC
CT-
ND
805
$0.1
3$0
.13
Dig
ikey
3.3v
feed
back
res
11
CC
3000
Wifi
$40.
00$4
0.00
Lees
Wifi
Mod
ule
brea
kout
11
Ser
voH
S-2
25B
B$1
9.99
$19.
99R
obot
shop
Tota
l$6
4.07
Thro
ughh
ole
pow
er e
lect
roni
csTh
ese
wer
e pu
rcha
sed
for p
roto
typi
ng o
nly
11
IC R
EG
BO
OS
T 5V
0.6
A 8
DIP
LT13
02C
N8-
5#P
BF-
ND
8-D
IP$7
.50
$7.5
0D
igik
ey1
1S
chot
tky
2A d
iode
SR
203-
TPC
T-N
DTH
$0.5
4$0
.54
Dig
ikey
11
10uH
2A
AIU
R-0
3-10
0K-N
DTH
$0.6
7$0
.67
Dig
ikey
22
100u
F 16
V C
apP
1629
2-N
DTH
$1.0
0$2
.00
Dig
ikey
11
1000
0pF
16V
Cap
399-
9794
-ND
TH$0
.37
$0.3
7D
igik
ey1
10.
1 uF
16V
Cap
399-
9796
-ND
TH$0
.37
$0.3
7D
igik
ey
Tota
l$1
1.45
Pric
es a
s of
Dec
embe
r 17,
201
4
Bill
of M
ater
ials
for t
he S
mar
tLoc
k
Formal Report for SmartLock
APPENDIX C: DEVICE SCHEMATICS
The following are device schematics for the overall project, including the ATMega328P microcontroller, headers for power, the nRF8001 Bluetooth module, and the CC3000 WiFi module. The attachments are as follows:
1. SmartLock Global Schematic: illustrates all module connections
2. Arduino Uno Schematic: illustrates all connections to the microcontroller
3. Power Schematic: illustrates both boost converters
4. Wireless Module Headers: illustrates connections to nRF8001 and CC3000
11
22
33
44
DD
CC
BB
AA
Title
Num
ber
Revisio
nSize A Date:
12/11/2014
Sheet of
File:
C:\Users\..\M
ain.SchD
ocDrawn By
:
A0
A1
A2
A3
A4
A5
A6
A7
D0/RX
DD1/TX
DD2/INT0
D3/INT1
D4
D5
D6
D7
D8
D9
D10/SS
D11/M
OSI
D12/M
ISO
D13/SCK
VCC
GND
ARE
F
RESE
T
D14/XTA
L1D15/XTA
L2
U_A
rduino
Arduino.SchDoc
VCC
GND
RSTb
IRQb
MISO
MOSI
SCLKCSb
CSw
IRQw
ENw
U_H
eaders
Headers.SchDoc
SERV
O
BAT+
BAT-
SERV
O+
SERV
O-
SW1aSW1b
SW2aSW2b
GND1 DSR2 VCC3 TX4 RX5 DTR6
JP0
1uF
C0
D11
D12
D13
68R
R11
68R
R12
68R
R13
GND
GND
LS1
Buzzer
GND
VBA
T
GND
aSD3V 5V 3V3
aSD5V
U_Pow
erPo
wer.SchDoc
PIC001
PIC002
COC0
PID1101
PID1102
COD11
PID1201
PID1202
COD12
PID1301
PID1302
COD13
PIJP001PIJP002PIJP003PIJP004PIJP005PIJP006 COJP0
PILS101
PILS101A
PILS102
PILS102A
COLS1
PIR110
1PIR
1102
COR11
PIR120
1PIR
1202
COR12
PIR130
1PIR
1302
COR13
POSERVO0
POSW1bPOSW2b
POSERVO
PID1102
PID1202
PID1302
PIJP001PIJP002
PILS101
PILS101A
POBAT0
POSERVO0
POSW1aPOSW2a
PIC001
PIJP006PIC
002
PID1101
PIR110
2 PID1201
PIR120
2 PID1301
PIR130
2
PIJP003PIJP004PIJP005
PILS102
PILS102A
PIR110
1
PIR120
1
PIR130
1
POBAT0
POBAT0
POSERVO
POSERVO0
POSW1APOSW1BPOSW2APOSW2B
11
22
33
44
DD
CC
BB
AA
Title
Num
ber
Revision
Size A Date:
12/11/2014
Sheet of
File:
C:\Users\..\Arduino.SchDoc
Drawn By:
PC6
aRES
ET/PCIN
T14)
29
PD0
aRXD/PCIN
T16)
30
PD1
aTXD/PCIN
T17)
31
PD2
aINT0
/PCIN
T18)
32
PD4
aPCIN
T20/XCK/T0)
2
VCC
6
GND
5PB
6 aPCIN
T6/XTA
L1/TOSC
1)7
PB7
aPCIN
T7/XTA
L2/TOSC
2)8
PD5
aPCIN
T21/OC0B
/T1)
9
PD6
aPCIN
T22/OC0A
/AIN
0)10
PD7
aPCIN
T23/AIN
1)11
PB0
aPCIN
T0/CLK
O/IC
P1)
12
PB1
aPCIN
T1/OC1A
)13
PB2
aPCIN
T2/SS/OC1B
)14
PB3
aPCIN
T3/OC2A
/MOSI)
15
PB4
aPCIN
T4/M
ISO)
16
PB5
aSCK/PCIN
T5)
17
AVCC
18
ARE
F20
GND
21
PC0
aADC0/PC
INT8
)23
PC1
aADC1/PC
INT9
)24
PC2
aADC2/PC
INT1
0)25
PC3
aADC3/PC
INT1
1)26
PC4
aADC4/SD
A/PCIN
T12)
27
PC5
aADC5/SC
L/PC
INT1
3)28
GND
3
VCC
4ADC6
19
ADC7
22
PD3
aPCIN
T19/OC2B
/INT1
)1
U1
ATmega328P-AU
A0
A1
A2
A3
A4
A5
A6
A7
D0/RXD
D1/TX
DD2/IN
T0D3/IN
T1D4
D5
D6
D7
D8
D9
D10/SS
D11/M
OSI
D12/M
ISO
D13/SCK
VCC
GND
ARE
F
100nF
C1
10K
R7
VCC
D3
RESE
T
D14/XTA
L1D15/XTA
L2
100nF
C2
GND
GND
GND
VCC
VCC
PIC101PIC102COC
1
PIC201PIC202COC
2PID301PID302 COD
3
PIR701PIR702 COR7
PIU101
PIU102
PIU103
PIU104
PIU105
PIU106
PIU107
PIU108
PIU109
PIU1010
PIU1011
PIU1012
PIU1013
PIU1014
PIU1015
PIU1016
PIU1017
PIU1018
PIU1019
PIU1020
PIU1021
PIU1022
PIU1023
PIU1024
PIU1025
PIU1026
PIU1027
PIU1028
PIU1029
PIU1030
PIU1031
PIU1032
COU1
PIC101PIC201
PIU103
PIU105
PIU1021
POGND
PIC202PIU1020
POAREF
PID301PIR701
PIU1029
PORESET
PIU101
POD30INT1
PIU102
POD4
PIU107
POD140XTAL1
PIU108
POD150XTAL2
PIU109
POD5
PIU1010
POD6
PIU1011
POD7
PIU1012
POD8
PIU1013
POD9
PIU1014
POD100SS
PIU1015
POD110MOSI
PIU1016
POD120MISO
PIU1017
POD130SCK
PIU1019
POA6
PIU1022
POA7
PIU1023
POA0
PIU1024
POA1
PIU1025
POA2
PIU1026
POA3
PIU1027
POA4
PIU1028
POA5
PIU1030
POD00RXD
PIU1031
POD10TXD
PIU1032
POD20INT0
PIC102
PID302PIR702
PIU104
PIU106
PIU1018
POVCC
POA0
POA1
POA2
POA3
POA4
POA5
POA6
POA7
POAREF
POD00RXD
POD10TXD
POD20INT0
POD30INT1
POD4
POD5
POD6
POD7
POD8
POD9
POD100SS
POD110MOSI
POD120MISO
POD130SCK
POD140XTAL1
POD150XTAL2
POGND
PORESET
POVCC
11
22
33
44
DD
CC
BB
AA
Title
Num
ber
Revision
Size A Date:
12/11/2014
Sheet of
File:
C:\Users\..\Pow
er.SchDoc
Drawn By:
SW1
GND
2FB
3
aSHDN
4
VOUT
5
VIN
6
IC1
AAT
1217
SW1
GND
2FB
3
aSHDN
4
VOUT
5
VIN
6
IC2
AAT
1217
VBA
T
GND
10uH
L1 10uH
L2
aSD3V
1.02M
R3
1.02M
R6
1.02M
R1
1.02M
R4
604k
R2
332k
R5
5V
3V3
D1
D2
aSD5V
PID101
PID102
COD1
PID201
PID202
COD2
PIIC101
PIIC102
PIIC103
PIIC104
PIIC105
PIIC106COI
C1
PIIC201
PIIC202
PIIC203
PIIC204
PIIC205
PIIC206COI
C2
PIL101
PIL102
COL1
PIL201
PIL202
COL2
PIR101PIR102 COR1
PIR201PIR202 COR2
PIR301
PIR302
COR3
PIR401PIR402 COR4
PIR501PIR502 COR5
PIR601
PIR602
COR6
PID101
PIIC101
PIL102
PID102
PIIC105 PIR102
PO5V
PID201
PIIC201
PIL202
PID202
PIIC205 PIR402
PO3V3
PIIC102
PIIC202
PIR201 PIR501
POGND
PIIC103PIR101 PIR202
PIIC104
PIR301
PO!SD5V
PIIC106
PIIC206
PIL101
PIL201
PIR302
PIR602
POVBAT
PIIC203PIR401 PIR502
PIIC204
PIR601
PO!SD3V
PO!SD3V
PO!SD5V
PO3V3
PO5V
POGND
POVBAT
1
1
2
2
3
3
4
4
D D
C C
B B
A A
Title
Number RevisionSizeA
Date: 12/11/2014 Sheet ofFile: C:\Users\aa\HeadersaSchDoc Drawn By:
IRQ1
VBEN2CS3
MOSI4MISO5
CLK6VIN7
3V38GND9
JP2
VIN1GND23Vo3RST4ACT5RDY6REQ7MOSI8
MISO9SCLK10
JP1VCCGND
RSTb
IRQb
MISOMOSI
SCLK
CSb
CSw
IRQwENw
PIJP101PIJP102PIJP103PIJP104PIJP105PIJP106PIJP107PIJP108PIJP109PIJP1010
COJP1
PIJP201PIJP202PIJP203PIJP204PIJP205PIJP206PIJP207PIJP208PIJP209
COJP2
PIJP101
PIJP208
POVCCPIJP102
PIJP209
POGNDPIJP103PIJP104PORSTbPIJP105PIJP106POIRQbPIJP107POCSbPIJP108
PIJP204
POMOSIPIJP109
PIJP205
POMISOPIJP1010
PIJP206
POSCLK
PIJP201POIRQwPIJP202POENwPIJP203POCSw
PIJP207
POCSB
POCSWPOENW
POGND
POIRQB
POIRQW
POMISOPOMOSI
PORSTB
POSCLK
POVCC
Formal Report for SmartLock
APPENDIX D: SMARTLOCK FIRMWARE SOURCE CODE
The following appendix is the source code for the SmartLock Firmware including the Adafruit BLE UART class. The attachments are as follows:
1. SmartLock Firmware
2. Adafruit BLE UART header (.h)
3. Adafruit BLE UART implementation (.cpp)
//// SmartLock.ino// SmartLock Firmware//// Created by Elliot Barer on 2014-10-09.// Copyright (c) 2014 Elliot Barer. All rights reserved.// Modified from Adafruit BLE UART example code//
#include <SPI.h>#include <Servo.h>#include "Adafruit_BLE_UART.h"
//*******************************************************// Pin Definitions//*******************************************************#define SCK 13#define MISO 12#define MOSI 11#define REQ 10#define RST 9#define RDY 2#define PIN_LOCK 0#define PIN_UNLOCK 1#define LED_UNLOCK 3#define LED_LOCK 4#define SPEAKER 5#define SERVO 6
//*******************************************************// Servo and Audio Definitions//*******************************************************#define SERVO_LOCK 2696#define SERVO_UNLOCK 556#define SERVO_NEUTRAL ((SERVO_LOCK - SERVO_UNLOCK) / 2 + SERVO_UNLOCK)#define SERVO_DELAY 500
#define VOLUME 100#define CHIRP_DELAY 100
//*******************************************************// Lock Status
//*******************************************************typedef enum { LOCK = 76, UNLOCK = 85} LockState;
LockState lockStatus = LOCK;
//*******************************************************// Objects//*******************************************************Adafruit_BLE_UART smartLock = Adafruit_BLE_UART(REQ, RDY, RST);Servo lockServo;
//*******************************************************// Configure the Arduino and begin advertising//*******************************************************void setup(void) { // Setup serial monitor Serial.begin(115200); Serial.println(F("SmartLock - Serial Debugger")); // Setup servo lockServo.attach(SERVO); // Setup control pins pinMode(LED_UNLOCK, OUTPUT); pinMode(LED_LOCK, OUTPUT); pinMode(SPEAKER, OUTPUT); pinMode(PIN_LOCK, INPUT); pinMode(PIN_UNLOCK, INPUT); // Setup BLE advertising smartLock.setDeviceName("SMRTLCK"); /* 7 characters max! */ smartLock.setACIcallback(aciCallback); smartLock.setRXcallback(rxCallback); smartLock.begin(); smartLock.flush(); // Lock the door (default, for safety) lockSmartLock();}
//*******************************************************// Constantly checks for new events on the nRF8001//*******************************************************void loop() { smartLock.pollACI();}
//*******************************************************// SmartLock Response//*******************************************************void smartLockResponse() { uint8_t buffer[20]; String response; switch(lockStatus) { case LOCK: response = "L"; break; case UNLOCK: response = "U"; break; } // Send lock status response.getBytes(buffer, 20); uint8_t buffer_size = min(20, response.length()); smartLock.write(buffer, buffer_size); // Clear buffer smartLock.flush();}
//*******************************************************// Mechanical Functions//*******************************************************void speakerChirp() { Serial.println("\tChirp"); analogWrite(SPEAKER, VOLUME); delay(CHIRP_DELAY); analogWrite(SPEAKER, 0); delay(CHIRP_DELAY);}
//*******************************************************// Lock SmartLock//*******************************************************void lockSmartLock() { Serial.println("Lock"); digitalWrite(LED_UNLOCK, LOW); digitalWrite(LED_LOCK, HIGH);
// Move servo to LOCK position lockServo.write(SERVO_LOCK); delay(SERVO_DELAY);
// Chirp once to acknolwedge lock speakerChirp(); // Move servo to NEUTRAL position lockServo.write(SERVO_NEUTRAL); delay(SERVO_DELAY); // Write status to SmartLock App lockStatus = LOCK; smartLockResponse();}
//*******************************************************// Unlock SmartLock//*******************************************************void unlockSmartLock() { Serial.println("Unlock"); digitalWrite(LED_UNLOCK, HIGH); digitalWrite(LED_LOCK, LOW); // Move servo to UNLOCK position lockServo.write(SERVO_UNLOCK); delay(SERVO_DELAY); // Chirp twice to acknolwedge unlock speakerChirp(); speakerChirp(); // Move servo to NEUTRAL position lockServo.write(SERVO_NEUTRAL);
delay(SERVO_DELAY); // Write status to SmartLock App lockStatus = UNLOCK; smartLockResponse();}
//*******************************************************// Handle ACI Events//*******************************************************void aciCallback(aci_evt_opcode_t event) { switch(event) { case ACI_EVT_DEVICE_STARTED: Serial.println(F("Advertising")); break; case ACI_EVT_CONNECTED: Serial.println(F("Connected")); break; case ACI_EVT_DISCONNECTED: smartLock.flush(); Serial.println(F("Disconnected")); break; default: Serial.println(F("Unknown")); break; }}
//*******************************************************// Handle RX Events//*******************************************************void rxCallback(uint8_t *buffer, uint8_t len) { // Get SmartLock App command switch(buffer[0]) { case LOCK: lockSmartLock(); break; case UNLOCK: unlockSmartLock(); break; }}
/********************************************************************* This is a library for our nRF8001 Bluetooth Low Energy Breakout Pick one up today in the adafruit shop! ------> http://www.adafruit.com/products/1697 These displays use SPI to communicate, 4 or 5 pins are required to interface Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Kevin Townsend/KTOWN for Adafruit Industries. MIT license, check LICENSE for more information All text above, and the splash screen below must be included in any
redistribution *********************************************************************/
#if ARDUINO >= 100#include "Arduino.h"#else#include "WProgram.h"#endif
#ifndef _ADAFRUIT_BLE_UART_H_#define _ADAFRUIT_BLE_UART_H_
#include "utility/aci_evts.h"
#define BLE_RW_DEBUG
extern "C" {/* Callback prototypes */typedef void (*aci_callback)(aci_evt_opcode_t event);typedef void (*rx_callback) (uint8_t *buffer, uint8_t len);
}
class Adafruit_BLE_UART : public Stream {public:
Adafruit_BLE_UART (int8_t req, int8_t rdy, int8_t rst);
bool begin ( uint16_t advTimeout = 0, uint16_t advInterval = 80 );void pollACI ( void );size_t write ( uint8_t * buffer, uint8_t len );size_t write ( uint8_t buffer);
size_t println(const char * thestr);size_t print(const char * thestr);size_t print(String thestr);size_t print(int theint);size_t print(const __FlashStringHelper *ifsh);
void setACIcallback(aci_callback aciEvent = NULL);void setRXcallback(rx_callback rxEvent = NULL);void setDeviceName(const char * deviceName);
// Stream compatibilityint available(void);int read(void);int peek(void);void flush(void);
aci_evt_opcode_t getState(void);
private:void defaultACICallback(aci_evt_opcode_t event);void defaultRX(uint8_t *buffer, uint8_t len);
// callbacks you can set with setCallback function for user extensionaci_callback aci_event;rx_callback rx_event;
bool debugMode;uint16_t adv_timeout;uint16_t adv_interval;char device_name[8];
aci_evt_opcode_t currentStatus;
// pins usdint8_t _REQ, _RDY, _RST;
};
#endif
/********************************************************************* This is a library for our nRF8001 Bluetooth Low Energy Breakout Pick one up today in the adafruit shop! ------> http://www.adafruit.com/products/1697 These displays use SPI to communicate, 4 or 5 pins are required to interface Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Kevin Townsend/KTOWN for Adafruit Industries. MIT license, check LICENSE for more information All text above, and the splash screen below must be included in any
redistribution *********************************************************************/#include <SPI.h>#include <avr/pgmspace.h>#include <util/delay.h>#include <stdlib.h>#include <ble_system.h>#include <lib_aci.h>#include <aci_setup.h>#include "uart/services.h"
#include "Adafruit_BLE_UART.h"
/* Get the service pipe data created in nRFGo Studio */#ifdef SERVICES_PIPE_TYPE_MAPPING_CONTENTstatic services_pipe_type_mapping_tservices_pipe_type_mapping[NUMBER_OF_PIPES] = SERVICES_PIPE_TYPE_MAPPING_CONTENT;#else#define NUMBER_OF_PIPES 0static services_pipe_type_mapping_t * services_pipe_type_mapping = NULL;#endif
/* Length of the buffer used to store flash strings temporarily when printing. */#define PRINT_BUFFER_SIZE 20
/* Store the setup for the nRF8001 in the flash of the AVR to save on RAM */static const hal_aci_data_t setup_msgs[NB_SETUP_MESSAGES] PROGMEM =
SETUP_MESSAGES_CONTENT;
static struct aci_state_t aci_state; /* ACI state data */static hal_aci_evt_t aci_data; /* Command buffer */static bool timing_change_done = false;
// This is the Uart RX buffer, which we manage internally when data is available!#define ADAFRUIT_BLE_UART_RXBUFFER_SIZE 64uint8_t adafruit_ble_rx_buffer[ADAFRUIT_BLE_UART_RXBUFFER_SIZE];volatile uint16_t adafruit_ble_rx_head;volatile uint16_t adafruit_ble_rx_tail;
int8_t HAL_IO_RADIO_RESET, HAL_IO_RADIO_REQN, HAL_IO_RADIO_RDY, HAL_IO_RADIO_IRQ;
/**************************************************************************//*! Constructor for the UART service *//**************************************************************************/// default RX callback!
void Adafruit_BLE_UART::defaultRX(uint8_t *buffer, uint8_t len){
for(int i=0; i<len; i++){
uint16_t new_head = (uint16_t)(adafruit_ble_rx_head + 1) % ADAFRUIT_BLE_UART_RXBUFFER_SIZE;
// if we should be storing the received character into the location// just before the tail (meaning that the head would advance to the// current location of the tail), we're about to overflow the buffer// and so we don't write the character or advance the head.if (new_head != adafruit_ble_rx_tail) {
adafruit_ble_rx_buffer[adafruit_ble_rx_head] = buffer[i];
// debug echo print// Serial.print((char)buffer[i]);
adafruit_ble_rx_head = new_head;}
}
/* Serial.print("Buffer: "); for(int i=0; i<adafruit_ble_rx_head; i++)
{ Serial.print(" 0x"); Serial.print((char)adafruit_ble_rx_buffer[i], HEX); }
Serial.println(); */}
/* Stream stuff */
int Adafruit_BLE_UART::available(void){
return (uint16_t)(ADAFRUIT_BLE_UART_RXBUFFER_SIZE + adafruit_ble_rx_head - adafruit_ble_rx_tail)
% ADAFRUIT_BLE_UART_RXBUFFER_SIZE;}
int Adafruit_BLE_UART::read(void){
// if the head isn't ahead of the tail, we don't have any charactersif (adafruit_ble_rx_head == adafruit_ble_rx_tail) {
return -1;} else {
unsigned char c = adafruit_ble_rx_buffer[adafruit_ble_rx_tail];adafruit_ble_rx_tail ++;adafruit_ble_rx_tail %= ADAFRUIT_BLE_UART_RXBUFFER_SIZE;return c;
}}
int Adafruit_BLE_UART::peek(void){
if (adafruit_ble_rx_head == adafruit_ble_rx_tail) {return -1;
} else {return adafruit_ble_rx_buffer[adafruit_ble_rx_tail];
}}
void Adafruit_BLE_UART::flush(void){
// MEME: KTOWN what do we do here?}
//// more callbacks
void Adafruit_BLE_UART::defaultACICallback(aci_evt_opcode_t event){
currentStatus = event;}
aci_evt_opcode_t Adafruit_BLE_UART::getState(void) {return currentStatus;
}
/**************************************************************************//*! Constructor for the UART service *//**************************************************************************/Adafruit_BLE_UART::Adafruit_BLE_UART(int8_t req, int8_t rdy, int8_t rst){
debugMode = true;
HAL_IO_RADIO_REQN = req;HAL_IO_RADIO_RDY = rdy;HAL_IO_RADIO_RESET = rst;
rx_event = NULL;aci_event = NULL;
memset(device_name, 0x00, 8);
adafruit_ble_rx_head = adafruit_ble_rx_tail = 0;
currentStatus = ACI_EVT_DISCONNECTED;}
void Adafruit_BLE_UART::setACIcallback(aci_callback aciEvent) {aci_event = aciEvent;
}
void Adafruit_BLE_UART::setRXcallback(rx_callback rxEvent) {rx_event = rxEvent;
}
/**************************************************************************//*! Transmits data out via the TX characteristic (when available) *//**************************************************************************/size_t Adafruit_BLE_UART::println(const char * thestr){
uint8_t len = strlen(thestr),written = len ? write((uint8_t *)thestr, len) : 0;if(written == len) written += write((uint8_t *)"\r\n", 2);
return written;}
size_t Adafruit_BLE_UART::print(const char * thestr){
return write((uint8_t *)thestr, strlen(thestr));}
size_t Adafruit_BLE_UART::print(String thestr){
return write((uint8_t *)thestr.c_str(), thestr.length());}
size_t Adafruit_BLE_UART::print(int theint){
char message[4*sizeof(int)+1] = {0};itoa(theint, message, 10);return write((uint8_t *)message, strlen(message));
}
size_t Adafruit_BLE_UART::print(const __FlashStringHelper *ifsh){
// Copy bytes from flash string into RAM, then send them a buffer at a time.char buffer[PRINT_BUFFER_SIZE] = {0};const char PROGMEM *p = (const char PROGMEM *)ifsh;size_t written = 0;int i = 0;unsigned char c = pgm_read_byte(p++);// Read data from flash until a null terminator is found.while (c != 0) {
// Copy data to RAM and increase buffer index.buffer[i] = c;i++;if (i >= PRINT_BUFFER_SIZE) {
// Send buffer when it's full and reset buffer index.written += write((uint8_t *)buffer, PRINT_BUFFER_SIZE);i = 0;
}// Grab a new byte from flash.c = pgm_read_byte(p++);
}if (i > 0) {
// Send any remaining data in the buffer.written += write((uint8_t *)buffer, i);
}return written;
}
size_t Adafruit_BLE_UART::write(uint8_t * buffer, uint8_t len){
uint8_t bytesThisPass, sent = 0;
#ifdef BLE_RW_DEBUGSerial.print(F("\tWriting out to BTLE:"));for (uint8_t i=0; i<len; i++) {
Serial.print(F(" 0x")); Serial.print(buffer[i], HEX);}Serial.println();
#endif
while(len) { // Parcelize into chunksbytesThisPass = len;if(bytesThisPass > ACI_PIPE_TX_DATA_MAX_LEN)
bytesThisPass = ACI_PIPE_TX_DATA_MAX_LEN;
if(!lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX))
{pollACI();continue;
}
lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &buffer[sent], bytesThisPass);
aci_state.data_credit_available--;
delay(35); // required delay between sends
if(!(len -= bytesThisPass)) break;sent += bytesThisPass;
}
return sent;}
size_t Adafruit_BLE_UART::write(uint8_t buffer){#ifdef BLE_RW_DEBUG
Serial.print(F("\tWriting one byte 0x")); Serial.println(buffer, HEX);#endif
if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)){
lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &buffer, 1);aci_state.data_credit_available--;
delay(35); // required delay between sendsreturn 1;
}
pollACI();
return 0;}
/**************************************************************************//*! Update the device name (7 characters or less!) *//**************************************************************************/void Adafruit_BLE_UART::setDeviceName(const char * deviceName){
if (strlen(deviceName) > 7){
/* String too long! */return;
}else{
memcpy(device_name, deviceName, strlen(deviceName));}
}
/**************************************************************************//*! Handles low level ACI events, and passes them up to an application level callback when appropriate *//**************************************************************************/void Adafruit_BLE_UART::pollACI(){
// We enter the if statement only when there is a ACI event available to be processed
if (lib_aci_event_get(&aci_state, &aci_data)){
aci_evt_t * aci_evt;
aci_evt = &aci_data.evt;switch(aci_evt->evt_opcode){
/* As soon as you reset the nRF8001 you will get an ACI Device Started Event */
case ACI_EVT_DEVICE_STARTED:aci_state.data_credit_total = aci_evt->params.device_started.
credit_available;switch(aci_evt->params.device_started.device_mode){
case ACI_DEVICE_SETUP:/* Device is in setup mode! */if (ACI_STATUS_TRANSACTION_COMPLETE != do_aci_setup(&
aci_state)){
if (debugMode) {Serial.println(F("Error in ACI Setup"));
}}break;
case ACI_DEVICE_STANDBY:/* Start advertising ... first value is advertising time
in seconds, the *//* second value is the advertising interval in 0.625ms
units */if (device_name[0] != 0x00){
/* Update the device name */lib_aci_set_local_data(&aci_state,
PIPE_GAP_DEVICE_NAME_SET , (uint8_t *)&device_name, strlen(device_name));
}lib_aci_connect(adv_timeout, adv_interval);defaultACICallback(ACI_EVT_DEVICE_STARTED);if (aci_event)
aci_event(ACI_EVT_DEVICE_STARTED);}break;
case ACI_EVT_CMD_RSP:/* If an ACI command response event comes with an error -> stop
*/if (ACI_STATUS_SUCCESS != aci_evt->params.cmd_rsp.cmd_status){
// ACI ReadDynamicData and ACI WriteDynamicData will have status codes of
// TRANSACTION_CONTINUE and TRANSACTION_COMPLETE// all other ACI commands will have status code of
ACI_STATUS_SUCCESS for a successful commandif (debugMode) {
Serial.print(F("ACI Command "));Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX);Serial.println(F("Evt Cmd respone: Error. Arduino is in
an while(1); loop"));}while (1);
}if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.
cmd_opcode){
// Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic
lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET,
(uint8_t *)&(aci_evt->params.cmd_rsp.
params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t));
}break;
case ACI_EVT_CONNECTED:aci_state.data_credit_available = aci_state.data_credit_total;/* Get the device version of the nRF8001 and store it in the
Hardware Revision String */lib_aci_device_version();
defaultACICallback(ACI_EVT_CONNECTED);if (aci_event)
aci_event(ACI_EVT_CONNECTED);
case ACI_EVT_PIPE_STATUS:if (lib_aci_is_pipe_available(&aci_state,
PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done))
{lib_aci_change_timing_GAP_PPCP(); // change the timing on the
link as specified in the nRFgo studio -> nRF8001 conf. -> GAP.
// Used to increase or decrease bandwidth
timing_change_done = true;}break;
case ACI_EVT_TIMING:/* Link connection interval changed */break;
case ACI_EVT_DISCONNECTED:/* Restart advertising ... first value is advertising time in
seconds, the *//* second value is the advertising interval in 0.625ms units */
defaultACICallback(ACI_EVT_DISCONNECTED);if (aci_event)
aci_event(ACI_EVT_DISCONNECTED);
lib_aci_connect(adv_timeout, adv_interval);
defaultACICallback(ACI_EVT_DEVICE_STARTED);if (aci_event)
aci_event(ACI_EVT_DEVICE_STARTED);break;
case ACI_EVT_DATA_RECEIVED:defaultRX(aci_evt->params.data_received.rx_data.aci_data, aci_evt
->len - 2);if (rx_event)
rx_event(aci_evt->params.data_received.rx_data.aci_data,
aci_evt->len - 2);break;
case ACI_EVT_DATA_CREDIT:aci_state.data_credit_available = aci_state.data_credit_available
+ aci_evt->params.data_credit.credit;break;
case ACI_EVT_PIPE_ERROR:/* See the appendix in the nRF8001 Product Specication for
details on the error codes */if (debugMode) {
Serial.print(F("ACI Evt Pipe Error: Pipe #:"));Serial.print(aci_evt->params.pipe_error.pipe_number, DEC);Serial.print(F(" Pipe Error Code: 0x"));Serial.println(aci_evt->params.pipe_error.error_code, HEX);
}
/* Increment the credit available as the data packet was not sent */
aci_state.data_credit_available++;break;
}}else{
// Serial.println(F("No ACI Events available"));// No event in the ACI Event queue and if there is no event in the ACI
command queue the arduino can go to sleep// Arduino can go to sleep now// Wakeup from sleep from the RDYN line
}}
/**************************************************************************//*! Configures the nRF8001 and starts advertising the UART Service @param[in] advTimeout The advertising timeout in seconds (0 = infinite advertising) @param[in] advInterval The delay between advertising packets in 0.625ms units *//**************************************************************************/bool Adafruit_BLE_UART::begin(uint16_t advTimeout, uint16_t advInterval){
/* Store the advertising timeout and interval */adv_timeout = advTimeout; /* ToDo: Check range! */adv_interval = advInterval; /* ToDo: Check range! */
/* Setup the service data from nRFGo Studio (services.h) */if (NULL != services_pipe_type_mapping){
aci_state.aci_setup_info.services_pipe_type_mapping = &services_pipe_type_mapping[0];
}
else{
aci_state.aci_setup_info.services_pipe_type_mapping = NULL;}aci_state.aci_setup_info.number_of_pipes = NUMBER_OF_PIPES;aci_state.aci_setup_info.setup_msgs = (hal_aci_data_t*)setup_msgs;aci_state.aci_setup_info.num_setup_msgs = NB_SETUP_MESSAGES;
/* Pass the service data into the appropriate struct in the ACI */lib_aci_init(&aci_state);
/* ToDo: Check for chip ID to make sure we're connected! */
return true;}
Formal Report for SmartLock
APPENDIX E: SMARTLOCK IOS APP SOURCE CODE
The following appendix is the source code for the SmartLock iOS App. The attachments are as follows:
1. AppDelegate: backbone of the iOS app
2. SmartLock (Class): the SmartLock implementation
3. MainViewController: global view controller
4. SmartLockViewController: the primary view controller
5. LockViewControl: used to implement the animated circle class on the SmartLockViewController
6. DebugViewController: implement the debugging view
//// AppDelegate.swift// SmartLock iOS Application//// Created by Elliot Barer on 2014-10-09.// Copyright (c) 2014 Elliot Barer. All rights reserved.//
import UIKit
@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate {
var window:UIWindow?var mainViewController:MainViewController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {window?.tintColor = UIColor.greenColor()return true
}
func applicationWillResignActive(application: UIApplication) {// Sent when the application is about to move from active to inactive
state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {// Use this method to release shared resources, save user data,
invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
mainViewController?.gblSmartLock.discoverDevices()}
func applicationWillEnterForeground(application: UIApplication) {// Called as part of the transition from the background to the inactive
state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {// Restart any tasks that were paused (or not yet started) while the
application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {// Called when the application is about to terminate. Save data if
appropriate. See also applicationDidEnterBackground:.}
}
//// SmartLock.swift// SmartLock//// Created by Elliot Barer on 2014-12-03.// Copyright (c) 2014 Elliot Barer. All rights reserved.//
import UIKitimport CoreBluetooth
enum Status {case Lockingcase Lockedcase Unlockingcase Unlockedcase Unknown
}
class SmartLock: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
// Prevent multiple instances of SmartLock from being createdclass var sharedInstance:SmartLock {
struct Static {static let instance:SmartLock = SmartLock()
}
return Static.instance}
// Bluetooth Peripheral Heirarchy://// CBPeripheral// |// |---- CBService// | |// | |---- CBCharacteristic// | |// | |---- CBCharacteristic// | |// | | ...// |// |---- CBService// |// | ...
//*******************************************************// Class members//*******************************************************
var centralManager:CBCentralManager! // Bluetooth central manager (iOS Device)
var smartLock:CBPeripheral! // Bluetooth peripheral device (SmartLock)
var rxCharacteristic:CBCharacteristic! // Bluetooth RX characteristic
var txCharacteristic:CBCharacteristic! // Bluetooth TX characteristic
var bluetoothState:Bool! // Bluetooth statusvar scanState:Bool! // Scan statusvar connectState:Bool! // Connection statusvar connectTimer:NSTimer! // Connection timeout
timervar lockStatus:Status! // Lock statusdynamic var activity:String! // Lock activitydynamic var debugActivity:String! // Lock activity (debug)
// Signal strength (RSSI) in dBmvar proximityEnable:Bool! // Proximity detection
statusvar rssiTimer:NSTimer! // RSSI update timervar rssiNow:Int! // Current RSSI valuevar rssiOld = [Int](count: 3, repeatedValue: 0) // Previous RSSI valuesvar lockThreshold = -73 // Locking RSSI thresholdvar unlockThreshold = -67 // Unlocking RSSI
threshold
// UUIDs for SmartLock UART Service and Characteristics (RX/TX)var smartLockNSUUID:NSUUID!let uartServiceUUID = CBUUID(string:"6E400001-B5A3-F393-E0A9-E50E24DCCA9E")let txCharacteristicUUID = CBUUID(string:"6E400002-B5A3-F393-E0A9-
E50E24DCCA9E")let rxCharacteristicUUID = CBUUID(string:"6E400003-B5A3-F393-E0A9-
E50E24DCCA9E")
override init() {super.init()
bluetoothState = falsescanState = falseconnectState = falselockStatus = .LockedproximityEnable = falserssiNow = 0
}
//*******************************************************// Central Manager (iPhone) Functions//*******************************************************
// Initializes the central manager with a specified delegate.func startUpCentralManager() {
centralManager = CBCentralManager(delegate: self, queue: nil)}
// Connect to SmarLockfunc connectToSmartLock(peripheral: CBPeripheral) {
centralManager.connectPeripheral(peripheral as CBPeripheral, options: [CBConnectPeripheralOptionNotifyOnNotificationKey: true])
}
// Disconnect from SmartLockfunc disconnectFromSmartLock() {
if(smartLock != nil) {centralManager.cancelPeripheralConnection(smartLock)smartLock = nil
}}
// Invoked when the central manager’s state is updated.func centralManagerDidUpdateState(central: CBCentralManager!) {
switch (central.state) {case .PoweredOff:
bluetoothState = falseoutput("Bluetooth Off")disconnectFromSmartLock()
case .PoweredOn:bluetoothState = trueoutput("Bluetooth On")discoverDevices()
default:bluetoothState = falseoutput("Bluetooth Unknown")
}}
// Scans for SmartLocks by searching for advertisements with UART services.func discoverDevices() {
// Avoid scanning by reconnecting to known good SmartLock// If not found, scan for other devicesif (bluetoothState == true && scanState == false) {
scanState = trueoutput("Searching...", UI: true)
if (smartLockNSUUID != nil) {var peripherals = centralManager.
retrievePeripheralsWithIdentifiers([smartLockNSUUID!])for peripheral in peripherals {
smartLock = peripheral as CBPeripheralconnectToSmartLock(peripheral as CBPeripheral)
}} else {
centralManager.scanForPeripheralsWithServices([uartServiceUUID], options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
}}
}
// Invoked when the central manager discovers a SmartLock while scanning.func centralManager(central: CBCentralManager!, didDiscoverPeripheral
peripheral: CBPeripheral!, advertisementData: (NSDictionary), RSSI: NSNumber!) {// Conserve batterycentralManager.stopScan()scanState = false
// Connect to SmartLockoutput("Discovered", UI: true)smartLock = peripheralsmartLockNSUUID = peripheral.identifierconnectTimer = NSTimer.scheduledTimerWithTimeInterval(30.0, target: self,
selector: Selector("cancelConnect"), userInfo: nil, repeats: false)connectToSmartLock(peripheral)
}
// Invoked when a connection is successfully created with a SmartLock.func centralManager(central: CBCentralManager!, didConnectPeripheral
peripheral: CBPeripheral!) {// Set peripheral delegate so it can receive appropriate callbacks// Check peripheral RSSI value// Investigate UART ServiceconnectState = trueconnectTimer.invalidate()output("Connected", UI: true)
peripheral.delegate = selfperipheral.readRSSI()peripheral.discoverServices([uartServiceUUID])
}
// Invoked when an existing connection with a SmartLock failsfunc centralManager(central: CBCentralManager!, didDisconnectPeripheral
peripheral: CBPeripheral!, error: NSError!) {connectState = falsescanState = falseoutput("Disconnected", UI: true)
}
//*******************************************************// Peripheral (SmartLock) Functions//*******************************************************
// Invoked when the SmartLock's UART service has been discoveredfunc peripheral(peripheral: CBPeripheral!, didDiscoverServices error:
NSError!) {for service in peripheral.services {
// Investigate UART Service RX and TX Characteristicsperipheral.discoverCharacteristics([txCharacteristicUUID,
rxCharacteristicUUID], forService: service as CBService)}
}
// Invoked when the SmartLock's UART RX and TX characteristics have been discovered
// Setup notification for RX characteristicfunc peripheral(peripheral: CBPeripheral!,
didDiscoverCharacteristicsForService service: CBService!, error: NSError!) {for characteristic in service.characteristics as [CBCharacteristic] {
switch(characteristic.UUID) {case rxCharacteristicUUID:
rxCharacteristic = characteristicsmartLock.readValueForCharacteristic(rxCharacteristic)peripheral.setNotifyValue(true, forCharacteristic:
rxCharacteristic)case txCharacteristicUUID:
txCharacteristic = characteristicdefault:
break}
}}
// Invoked when the SmartLock receives a request to start or stop providing notifications for a specified characteristic’s value.
func peripheral(peripheral: CBPeripheral!, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {if (error != nil) {
output("Error: \(error.localizedDescription)")}
}
// Invoked when the SmartLock notifies the app that the RX characteristic's value has changed
func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {if var data:NSData = characteristic.value {
var response:String = NSString(data: data, encoding: NSUTF8StringEncoding)!
switch(response) {case "L":
lockStatus = .Lockedoutput("Locked", UI: true)
case "U":lockStatus = .Unlockedoutput("Unlocked", UI: true)
default:lockStatus = .Unknownoutput("Bad Data: \(data)")
}}
}
// Cancel connectionfunc cancelConnect() {
connectTimer.invalidate()output("Connection timeout", UI: true)disconnectFromSmartLock()
}
// Determine lock statusfunc getConnectionState() -> Bool {
if (smartLock != nil) {if (smartLock.state == CBPeripheralState.Connected) {
connectState = truereturn true
} else {discoverDevices()connectState = falsereturn false
}} else {
connectState = falsereturn false
}}
// Lock SmartLockfunc lockSmartLock() {
if(getConnectionState() == true) {if(lockStatus == .Unlocked) {
let txString = "L"let txData = txString.dataUsingEncoding(NSUTF8StringEncoding)lockStatus = Status.Lockingoutput("Locking...", UI: true)smartLock.writeValue(txData, forCharacteristic: txCharacteristic,
type: CBCharacteristicWriteType.WithoutResponse)}
}}
// Unlock SmartLockfunc unlockSmartLock() {
if(getConnectionState() == true) {if(lockStatus == .Locked) {
let txString = "U"let txData = txString.dataUsingEncoding(NSUTF8StringEncoding)lockStatus = Status.Unlockingoutput("Unlocking...", UI: true)smartLock.writeValue(txData, forCharacteristic: txCharacteristic,
type: CBCharacteristicWriteType.WithoutResponse)}
}}
// Enable the RSSI timer for proximity modefunc rssiTimerEnable() {
// Initialize a timer to check RSSI value every 0.5 seconds while connected
rssiTimer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("updateRSSI"), userInfo: nil, repeats: true)
proximityEnable = true}
// Disable the RSSI timer
func rssiTimerDisable() {if (rssiTimer != nil) {
rssiTimer.invalidate()proximityEnable = false
}}
// Proximity detectionfunc updateRSSI() {
var rssiAverage:Int
if (smartLock != nil && getConnectionState() == true) {smartLock.readRSSI()if(smartLock.RSSI != nil) {
// Take 4 values for accurate average of RSSI valuerssiOld[2] = rssiOld[1]rssiOld[1] = rssiOld[0]rssiOld[0] = rssiNowrssiNow = Int(smartLock.RSSI)rssiAverage = ((rssiNow + rssiOld[0] + rssiOld[1] + rssiOld[2])/
4)
// Output proximity equationif (lockStatus == .Locked) {
output("RSSI: \(rssiAverage) > \(unlockThreshold) = \(rssiAverage > unlockThreshold)")
} else {output("RSSI: \(rssiAverage) < \(lockThreshold) = \
(rssiAverage < lockThreshold)")}
// If locked, within range, and moving toward lock: unlockif ((lockStatus == .Locked) && (rssiAverage > unlockThreshold)) {
unlockSmartLock()}
// If unlocked, leaving range, and moving away from lock: lockif ((lockStatus == .Unlocked) && (rssiAverage < lockThreshold)) {
lockSmartLock()}
}}
}
//*******************************************************// Debug Functions//*******************************************************
func output(description: String, UI: Bool = false) {let timestamp = generateTimeStamp()
if (UI.boolValue == true) {activity = "\(description)"
}
println("[\(timestamp)] \(description)")debugActivity = "\(description)"
}
func generateTimeStamp() -> NSString {let timestamp = NSDateFormatter.localizedStringFromDate(NSDate(),
dateStyle: .NoStyle, timeStyle: .MediumStyle)return timestamp
}
}
//// MainViewController.swift// SmartLock//// Created by Elliot Barer on 2014-12-08.// Copyright (c) 2014 Elliot Barer. All rights reserved.//
import UIKit
class MainViewController: UITabBarController {
var gblSmartLock = SmartLock()
override func viewDidLoad() { super.viewDidLoad() }
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { // segue.destinationViewController. }
}
//// SmartLockViewController.swift// SmartLock iOS Application//// Created by Elliot Barer on 2014-10-09.// Copyright (c) 2014 Elliot Barer. All rights reserved.//
import UIKit
class SmartLockViewController: UIViewController {
var smrtLock = SmartLock()private var myContext = 0
// UI Elements@IBInspectable var lckControlView:LockControlView!@IBOutlet weak var activityLabel: UILabel!
// When application loads, and when view appears or disappearsoverride func viewDidLoad() {
super.viewDidLoad()self.setNeedsStatusBarAppearanceUpdate()
// Start Bluetooth Central ManagersmrtLock.startUpCentralManager()
// Add LockControlvar lockControlTap = UITapGestureRecognizer(target: self, action:
Selector("lockControlTapped:"))lckControlView = LockControlView(frame: CGRectMake(view.center.x - 150.0,
view.center.y - 150.0, 300.0, 300.0))lckControlView.addGestureRecognizer(lockControlTap)lckControlView.lockStatus = smrtLock.lockStatusview.addSubview(lckControlView)
// Watch for changes in "activity" from SmartLock modelsmrtLock.addObserver(self, forKeyPath: "activity", options: .New,
context: &myContext)}
override func viewDidAppear(animated: Bool) {smrtLock.discoverDevices()
}
override func viewDidDisappear(animated: Bool) {smrtLock.disconnectFromSmartLock()
}
// Set status bar to lightoverride func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent}
// Update lockControl text with activity changes in SmartLock model (MVC)override func observeValueForKeyPath(keyPath: String, ofObject object:
AnyObject, change: [NSObject: AnyObject], context: UnsafeMutablePointer<Void>) {if context == &myContext {
activityLabel.text = "\(smrtLock.activity)\n"lckControlView.determineColor(smrtLock.connectState, lockStatus:
smrtLock.lockStatus)} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}}
// Toggle lock/unlockfunc lockControlTapped(recognizer: UITapGestureRecognizer) {
let servoDelay = 1.25lckControlView.lockStatus = smrtLock.lockStatus
if (smrtLock.connectState == true) {if (smrtLock.lockStatus == Status.Locked) {
smrtLock.unlockSmartLock()lckControlView.determineColor(smrtLock.connectState, lockStatus:
smrtLock.lockStatus)lckControlView.animateLockControl(servoDelay)
} else if (smrtLock.lockStatus == Status.Unlocked) {smrtLock.lockSmartLock()lckControlView.determineColor(smrtLock.connectState, lockStatus:
smrtLock.lockStatus)lckControlView.animateLockControl(servoDelay)
}} else {
lckControlView.determineColor(smrtLock.connectState, lockStatus: smrtLock.lockStatus)
smrtLock.discoverDevices()}
}
}
//// LockControlView.swift// SmartLock//// Created by Elliot Barer on 2014-12-05.// Copyright (c) 2014 Elliot Barer. All rights reserved.//
import UIKit
class LockControlView: UIView {
let lockControlShape = CAShapeLayer()let ringAnimation = CABasicAnimation(keyPath: "strokeEnd")var lockStatus:Status!
override init(frame: CGRect) {super.init(frame: frame)self.backgroundColor = UIColor.clearColor()
lockControlShape.path = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: true).CGPath
lockControlShape.fillColor = UIColor.clearColor().CGColor
lockControlShape.lineWidth = 6.0;lockControlShape.strokeEnd = 1.0
layer.addSublayer(lockControlShape)}
required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented")}
func animateLockControl(duration: NSTimeInterval) {
// Set the animation duration appropriatelyringAnimation.duration = duration
// Animate from 0 to 1, then set endpointringAnimation.fromValue = 0ringAnimation.toValue = 1lockControlShape.strokeEnd = 1.0
// Perform linear animationringAnimation.timingFunction = CAMediaTimingFunction(name:
kCAMediaTimingFunctionLinear)
// Add animation to objectlockControlShape.addAnimation(ringAnimation, forKey:
"animateLockControl")}
// Determine ring colour based on lock status
func determineColor(connectState: Bool, lockStatus: Status) {if(connectState == true) {
switch (lockStatus) {case .Locked:
lockControlShape.strokeColor = UIColor.redColor().CGColorcase .Locking:
lockControlShape.strokeColor = UIColor.redColor().CGColorcase .Unlocked:
lockControlShape.strokeColor = UIColor.greenColor().CGColorcase .Unlocking:
lockControlShape.strokeColor = UIColor.greenColor().CGColordefault:
lockControlShape.strokeColor = UIColor.grayColor().CGColor}
} else {lockControlShape.strokeColor = UIColor.grayColor().CGColor
}}
}
//// DebugViewController.swift// SmartLock iOS Application//// Created by Elliot Barer on 2014-10-09.// Copyright (c) 2014 Elliot Barer. All rights reserved.//
import UIKit
class DebugViewController: UIViewController {
var smrtLock = SmartLock()private var myContext = 0
// UI Elements@IBOutlet weak var textField:UITextView!@IBOutlet weak var proximitySwitch:UISwitch!@IBOutlet weak var lockThresholdSlider:UISlider!@IBOutlet weak var lockThresholdLabel:UILabel!@IBOutlet weak var unlockThresholdSlider:UISlider!@IBOutlet weak var unlockThresholdLabel:UILabel!
// When application loads, and when view appears or disappearsoverride func viewDidLoad() {
super.viewDidLoad()self.setNeedsStatusBarAppearanceUpdate()
// Start Bluetooth Central ManagersmrtLock.startUpCentralManager()
// Disable proximity (for demonstration)proximitySwitch.on = smrtLock.proximityEnablelockThresholdSlider.value = Float(smrtLock.lockThreshold)lockThresholdLabel.text = "Lock Threshold = \(smrtLock.lockThreshold)"unlockThresholdSlider.value = Float(smrtLock.unlockThreshold)unlockThresholdLabel.text = "Unlock Threshold = \(smrtLock.
unlockThreshold)"
// Watch for changes in "debugActivity" from SmartLock model (for debug console)
smrtLock.addObserver(self, forKeyPath: "debugActivity", options: .New, context: &myContext)
}
override func viewDidAppear(animated: Bool) {smrtLock.discoverDevices()proximitySwitch.on = smrtLock.proximityEnable
}
override func viewDidDisappear(animated: Bool) {smrtLock.disconnectFromSmartLock()
}
// Set status bar to lightoverride func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent}
// Update debug console with activity changes in SmartLock model (MVC)override func observeValueForKeyPath(keyPath: String, ofObject object:
AnyObject, change: [NSObject: AnyObject], context: UnsafeMutablePointer<Void>) {if context == &myContext {
textField.selectable = falsetextField.text = "\(smrtLock.debugActivity)\n" + textField.text
} else {super.observeValueForKeyPath(keyPath, ofObject: object, change:
change, context: context)}
}
// Toggle lock@IBAction func lockButton() {
smrtLock.lockSmartLock()}
// Toggle unlock@IBAction func unlockButton() {
smrtLock.unlockSmartLock()}
// Conncet to existing SmartLock, or search for new@IBAction func connectSmartLock(sender: UIButton) {
smrtLock.discoverDevices()}
// Diconncet SmartLock@IBAction func disconnectSmartLock(sender: UIButton) {
smrtLock.disconnectFromSmartLock()}
// Toggle proximity mode by enabling/disabling the RSSI timer@IBAction func toggleProximity(proximity: UISwitch) {
if (smrtLock.proximityEnable == false) {smrtLock.rssiTimerEnable()
} else {smrtLock.rssiTimerDisable()
}}
// Adjust lock threshold value for proximity mode@IBAction func adjustLockThreshold(threshold: UISlider) {
smrtLock.lockThreshold = Int(threshold.value)lockThresholdLabel.text = "Lock Threshold = \(Int(threshold.value))"
}
// Adjust unlock threshold value for proximity mode@IBAction func adjustUnlockThreshold(threshold: UISlider) {
smrtLock.unlockThreshold = Int(threshold.value)unlockThresholdLabel.text = "Unlock Threshold = \(Int(threshold.value))"
}
// Clear debug log@IBAction func clearLog(sender: UIButton) {
textField.text = ""}
}
Formal Report for SmartLock
APPENDIX F: USER MANUAL
This manual refers to the SmartLock as if it were a finished product.
Parts Included • The SmartLock Device
• 2 AA batteries
• SmartLock App (downloadable from the Apple App Store)
Installation 1. Remove your existing thumbturn
i. Unscrew the 2 bolts holding in the thumbturn of your existing dead bolt lock, save the screws
2. Remove the top cover from the SmartLock via the centre screw
3. Position the SmartLock over the metal plate of the lock
I. Ensure the lock and unlock symbols are at the top of the device for correct orientation
II. Align the tumbler arm with the lock shaft
4. Using the screws from Step 1, screw through the two holes in the backplane of the SmartLock
5. Install the AA batteries into the SmartLock
6. Reattach the top cover by tightening the screw in the centre
7. Open the SmartLock App on your iPhone and wait for a connection
8. Congratulations, you are now ready to use the SmartLock!
Formal Report for SmartLock
Electronically Locking and Unlocking 1. Open the SmartLock app, ensuring a connection with the SmartLock, and tap the unlock or lock
button.
2. The button context will change depending on the orientation of the device.
Manual Locking and Unlocking 1. Rotate the tumbler to the lock or unlock positions.
Calibrating Proximity Detection Mode 1. Tap the calibrate button in the SmartLock app.
2. Determine the radius in which you would like the door to unlock and move to the edge.
3. Tap the accept button.
4. Determine the radius in which you would like the door to lock and move to the edge.
5. Tap the accept button.
Formal Report for SmartLock
APPENDIX G: GANTT CHART
The following appendix contains the initial and revised gantt charts outlining the timeline for all activities related to this project. The attachments are as follows:
1. Initial Gantt Chart
2. Revised Gantt Chart
IDTa
sk N
ame
Dur
atio
nSt
art
Fini
shPr
edRe
sour
ce
Nam
es
0ELEX
4330 Technical Project
74 days
Wed 9/3/14
Fri 12/19/14
1Prelim
inary Reports
31 days
Wed 9/3/14
Fri 10/17/14
Team
2Write "P
roject Propo
sal" Rep
ort
11 days
Wed
9/3/14
Wed
9/17/14
Team
3"Project Propo
sal" Due
0 days
Wed
9/17/14
Wed
9/17/14
2Team
4Write "F
unctional Req
uiremen
ts" R
eport
6 days
Thu 9/18
/14
Thu 9/25
/14
3Team
5"Fun
ctional Req
uiremen
ts" D
ue0 days
Thu 9/25
/14
Thu 9/25
/14
4Team
6Write "D
esign Specification
" Rep
ort
14 days
Fri 9/26/14
Thu 10/16/14
5Team
7"D
esign Specification
" Due
0 days
Fri 10/17
/14
Fri 10/17
/14
6Team
8Design
Product
27 days
Fri 9/26/14
Wed 11/5/14
4Team
9Firm
ware
23 days
Fri 9/26/14
Wed 10/29/14
Elliot
10Re
search BLE and
WiFi
12 days
Fri 9/26/14
Tue 10
/14/14
Elliot
11Im
plem
ent initializtion
7 days
Wed
10/15
/14
Thu 10/23/14
10Elliot
12Im
plem
ent e
ncryption algorithm
4 days
Fri 10/24
/14
Wed
10/29
/14
11Elliot
13Power
22 days
Fri 9/26/14
Tue 10/28/14
Albert
14Re
search m
odules
12 days
Fri 9/26/14
Tue 10
/14/14
Albert
15Design sche
matic fo
r boo
st con
verter
3 days
Wed
10/15
/14
Fri 10/17
/14
14Albert
16Co
nstruct a
nd te
st circuit
0 days
Mon
10/20/14
Mon
10/20/14
15Albert
17Mod
ification
s to circuit
7 days
Mon
10/20/14
Tue 10
/28/14
16Albert
18Lock Controller
27 days
Fri 9/26/14
Wed 11/5/14
James
19Re
search se
rvos and
motors
12 days
Fri 9/26/14
Tue 10
/14/14
James
20Source com
pone
nts
5 days
Wed
10/15
/14
Tue 10
/21/14
19James
21Im
plem
ent e
lectromechanical actuation
3 days
Wed
10/22
/14
Fri 10/24
/14
20James
22Mod
ification
s to controller
7 days
Mon
10/27/14
Wed
11/5/14
21James
23Design
enclosure
11 days
Thu 11/6/14
Fri 11/21/14
8Team
24Design PC
B4 days
Thu 11/6/14
Wed
11/12
/14
Elliot,James
25Mod
el enclosure
4 days
Thu 11/6/14
Wed
11/12
/14
Albert
26Print e
nclosure
1 day
Thu 11/13/14
Thu 11/13/14
25Albert
27Validate en
closure
1 day
Fri 11/14
/14
Fri 11/14
/14
26Team
28Mod
ification
s to de
sign
5 days
Mon
11/17/14
Fri 11/21
/14
27Team
29Prepare fo
r Presentation
6 days
Mon 12/8/14
Tue 12/16/14
23
Team
30Prep
are speaker n
otes & overheads
2 days
Mon
12/8/14
Tue 12
/9/14
Team
31Practice presentation
2 days
Fri 12/12
/14
Mon
12/15/14
30Team
32Presen
tation
0 days
Tue 12
/16/14
Tue 12
/16/14
31Team
33Write "P
roject Rep
ort"
24 days
Thu 11/6/14
Wed
12/10
/14
8Team
34"Project Rep
ort" Due
0 days
Fri 12/19
/14
Fri 12/19
/14
Team
Team
9/17
Team
9/25
Team
10/1
7
Ellio
t Ellio
t Ellio
t
Alb
ert
Alb
ert
10/2
0 Alb
ert
Jam
es Jam
esJa
mes
Jam
es Ellio
t,Jam
esA
lber
tA
lber
tTe
amTe
am
Team Te
am12
/16
Team
12/1
9
SW
ST
MF
TS
WS
TM
FT
SW
ST
MF
TS
WS
TM
FT
SW
ST
M17
, '14
Aug
31, '
14Se
p 14
, '14
Sep
28, '
14O
ct 1
2, '1
4O
ct 2
6, '1
4N
ov 9
, '14
Nov
23,
'14D
ec 7
, '14
Dec
21,
'1
Task
Split
Mile
ston
e
Sum
mar
y
Proj
ect S
umm
ary
Inac
tive
Task
Inac
tive
Mile
ston
e
Inac
tive
Sum
mar
y
Man
ual T
ask
Dur
atio
n-on
ly
Man
ual S
umm
ary
Rollu
p
Man
ual S
umm
ary
Star
t-on
ly
Fini
sh-o
nly
Exte
rnal
Tas
ks
Exte
rnal
Mile
ston
e
Dea
dlin
e
Criti
cal
Criti
cal S
plit
Prog
ress
Man
ual P
rogr
ess
Page
1
Proj
ect:
ELEX
433
0 Te
chni
cal P
rD
ate:
Fri
10/1
7/14
Team
Ellio
t Ba
rer,
Jam
es E
sau,
Alb
ert
Phan
,'7DVN�1
DPH
'XUDWLR
Q6WDUW
)LQLVK
3UH5HVRX
UFH�
1DPHV
��>�y
�ϰϯϯ
Ϭ�dĞ
ĐŚŶŝĐĂů�W
ƌŽũĞĐƚ
ϳϰ�ĚĂLJƐ
tĞĚ
�ϵϯϭϰ
&ƌŝ�ϭϮϭϵ
ϭϰ
�WƌĞůŝŵ
ŝŶĂƌLJ�ZĞ
ƉŽƌƚƐ
ϯϭ�ĚĂLJƐ
tĞĚ
�ϵϯϭϰ
&ƌŝ�ϭϬϭϳ
ϭϰ
dĞĂŵ
�tƌŝƚĞ�ΗWƌŽũĞĐƚ�WƌŽƉŽ
ƐĂůΗ�ZĞ
ƉŽƌƚ
ϭϭ�ĚĂLJƐ
tĞĚ
�ϵϯϭϰ
tĞĚ
�ϵϭϳϭϰ
dĞĂŵ
�ΗWƌŽũĞĐƚ�WƌŽƉŽ
ƐĂůΗ��Ƶ
ĞϬ�ĚĂ
LJƐtĞĚ
�ϵϭϳϭϰ
tĞĚ
�ϵϭϳϭϰ
ϮdĞ
Ăŵ�
tƌŝƚĞ�Η&ƵŶ
ĐƚŝŽŶĂ
ů�ZĞƋ
ƵŝƌĞŵĞŶ
ƚƐΗ�Z
ĞƉŽƌϲ�ĚĂ
LJƐdŚ
Ƶ�ϵϭϴ
ϭϰ
dŚƵ�ϵϮϱ
ϭϰ
ϯdĞ
Ăŵ�
Η&ƵŶ
ĐƚŝŽŶĂ
ů�ZĞƋ
ƵŝƌĞŵĞŶ
ƚƐΗ��
ƵĞϬ�ĚĂ
LJƐdŚ
Ƶ�ϵϮϱ
ϭϰ
dŚƵ�ϵϮϱ
ϭϰ
ϰdĞ
Ăŵ�
tƌŝƚĞ�Η�
ĞƐŝŐŶ�^Ɖ
ĞĐŝĨŝĐĂƚŝŽ
ŶΗ�ZĞƉ
Žƌƚ
ϭϰ�ĚĂLJƐ
&ƌŝ�ϵ
Ϯϲϭϰ
dŚƵ�ϭϬ
ϭϲϭϰ
ϱdĞ
Ăŵ�
Η�ĞƐŝŐŶ�^Ɖ
ĞĐŝĨŝĐĂƚŝŽ
ŶΗ��ƵĞ
Ϭ�ĚĂ
LJƐ&ƌŝ�ϭ
Ϭϭϳ
ϭϰ
&ƌŝ�ϭ
Ϭϭϳ
ϭϰ
ϲdĞ
Ăŵ�
�ĞƐŝŐ
Ŷ�WƌŽĚ
ƵĐƚ
ϱϱ�ĚĂLJƐ
&ƌŝ�ϵϮϲϭϰ
dƵĞ�ϭϮ
ϭϲϭϰ
ϰdĞ
Ăŵ�
&ŝƌŵ
ǁĂƌĞ
ϱϯ�ĚĂLJƐ
&ƌŝ�ϵϮϲϭϰ
&ƌŝ�ϭϮϭϮ
ϭϰ
�ůůŝŽ
ƚ��
ZĞƐĞĂƌĐŚ��>��ĂŶĚ
�tŝ&ŝ
ϰ�ĚĂ
LJƐ&ƌŝ�ϵ
Ϯϲϭϰ
tĞĚ
�ϭϬϭϭϰ
�ůůŝŽ
ƚ��
>ĞĂƌŶ�^ǁ
ŝĨƚ�ĂŶĚ
�KďũĞĐƚŝǀ
ĞͲ�
ϯϮ�ĚĂLJƐ
dŚƵ�ϭϬ
Ϯϭϰ
tĞĚ
�ϭϭϭϵ
ϭϰϭϬ
�ůůŝŽ
ƚ��
dĞƐƚ��>��ĐŽ
ŶŶĞĐƚŝŽ
Ŷϳ�ĚĂ
LJƐdŚ
Ƶ�ϭϭ
ϮϬϭϰ
&ƌŝ�ϭ
ϭϮϴ
ϭϰ
ϭϭ�ůůŝŽ
ƚ��
�ƌĞĂ
ƚĞ�^ŵĂƌƚ>ŽĐŬ��ůĂƐƐ
Ϯ�ĚĂ
LJƐdƵ
Ğ�ϭϮ
Ϯϭϰ
tĞĚ
�ϭϮϯϭϰ
ϭϮ�ůůŝŽ
ƚ��
�ƌĞĂ
ƚĞ��Ğď
ƵŐsŝĞǁ
�ŽŶƚƌŽůůĞƌ
Ϯ�ĚĂ
LJƐdŚ
Ƶ�ϭϮ
ϰϭϰ
&ƌŝ�ϭ
Ϯϱϭϰ
ϭϯ�ůůŝŽ
ƚ��
�ƌĞĂ
ƚĞ�^ŵĂƌƚ>ŽĐŬs
ŝĞǁ�Ž
ŶƚƌŽůůĞƌϭ
�ĚĂLJ
^Ăƚ�ϭ
Ϯϲϭϰ
^Ăƚ�ϭ
Ϯϲϭϰ
ϭϰ�ůůŝŽ
ƚ��
/ŵƉůĞŵ
ĞŶƚ�Ɖ
ƌŽdžŝŵŝƚLJ
�ĚĞƚĞĐƚŝŽ
Ŷϯ�ĚĂ
LJƐ^Ƶ
Ŷ�ϭϮ
ϳϭϰ
dƵĞ�ϭϮ
ϵϭϰ
ϭϱ�ůůŝŽ
ƚ��
�ĚĚ�ƉƌŽdžŝŵ
ŝƚLJ�ƚŚ
ƌĞƐŚŽůĚ�ŵŽĚ
ŝĨŝĐĂϯ�ĚĂ
LJƐtĞĚ
�ϭϮϭϬ
ϭϰ&ƌŝ�ϭ
ϮϭϮ
ϭϰ
ϭϲ�ůůŝŽ
ƚ��
WŽǁĞƌ
ϱϯ�ĚĂLJƐ
&ƌŝ�ϵϮϲϭϰ
&ƌŝ�ϭϮϭϮ
ϭϰ
�ůďĞ
ƌƚ��
ZĞƐĞĂƌĐŚ�ŵ
ŽĚƵůĞƐ
ϭϮ�ĚĂLJƐ
&ƌŝ�ϵ
Ϯϲϭϰ
dƵĞ�ϭϬ
ϭϰϭϰ
�ůďĞ
ƌƚ��
�ĞƐŝŐ
Ŷ�ƐĐŚĞ
ŵĂƚŝĐ�ĨŽƌ�ď
ŽŽƐƚ�ĐŽ
ŶǀĞƌƚĞ
ϯ�ĚĂ
LJƐtĞĚ
�ϭϬϭϱ
ϭϰ
&ƌŝ�ϭ
Ϭϭϳ
ϭϰ
ϭϵ�ůďĞ
ƌƚ��
^ŽƵƌĐĞ�ůĂƐƚ�ŵ
ŝŶƵƚĞ�ƚŚƌƵͲŚŽůĞ�ƉĂ
ƌƚƐ
ϭ�ĚĂ
LJdƵ
Ğ�ϭϮ
ϵϭϰ
dƵĞ�ϭϮ
ϵϭϰ
:ĂŵĞƐ
��Kƌ
ĚĞƌ�ůĂƐƚ�ŵ
ŝŶƵƚĞ�ƉĂ
ƌƚƐ
ϯ�ĚĂ
LJƐtĞĚ
�ϭϮϭϬ
ϭϰ
&ƌŝ�ϭ
ϮϭϮ
ϭϰ
Ϯϭ�ůůŝŽ
ƚ��
>ŽĐŬ��ŽŶ
ƚƌŽůůĞƌ
ϱϱ�ĚĂLJƐ
&ƌŝ�ϵϮϲϭϰ
dƵĞ�ϭϮ
ϭϲϭϰ
:ĂŵĞƐ
��ZĞ
ƐĞĂƌĐŚ�ƐĞ
ƌǀŽƐ�ĂŶĚ
�ŵŽƚŽƌƐ
ϭϮ�ĚĂLJƐ
&ƌŝ�ϵ
Ϯϲϭϰ
dƵĞ�ϭϬ
ϭϰϭϰ
:ĂŵĞƐ
��^Ž
ƵƌĐĞ�ĐŽ
ŵƉŽ
ŶĞŶƚƐ
ϱ�ĚĂ
LJƐtĞĚ
�ϭϬϭϱ
ϭϰ
dƵĞ�ϭϬ
Ϯϭϭϰ
Ϯϰ:ĂŵĞƐ
��/ŵ
ƉůĞŵ
ĞŶƚ�Ğ
ůĞĐƚƌŽŵĞĐŚĂ
ŶŝĐĂů�ĂĐƚƵĂ
ƚϯ�ĚĂLJƐ
tĞĚ
�ϭϬϮϮ
ϭϰ
&ƌŝ�ϭ
ϬϮϰ
ϭϰ
Ϯϱ:ĂŵĞƐ
��DŽĚ
ŝĨŝĐĂƚŝŽ
ŶƐ�ƚŽ
�ĐŽŶƚƌŽůůĞƌ
ϱ�ĚĂ
LJƐtĞĚ
�ϭϮϭϬ
ϭϰ
dƵĞ�ϭϮ
ϭϲϭϰ
ϯϭ:ĂŵĞƐ
���Ğ
ƐŝŐŶ�ĞŶ
ĐůŽƐƵƌĞ
ϱϯ�ĚĂLJƐ
&ƌŝ�ϵϮϲϭϰ
^ƵŶ�ϭϮ
ϭϰϭϰ
ϱdĞ
Ăŵ��
DŽĚ
Ğů�ĞŶĐůŽƐƵƌĞ
ϯϴ�ĚĂLJƐ
&ƌŝ�ϵ
Ϯϲϭϰ
&ƌŝ�ϭ
ϭϮϭ
ϭϰ
�ůďĞ
ƌƚ��
WƌŝŶƚ�Ğ
ŶĐůŽƐƵƌĞ
Ϯ�ĚĂ
LJƐ&ƌŝ�ϭ
Ϯϱϭϰ
DŽŶ
�ϭϮϴϭϰ
Ϯϵ�ůďĞ
ƌƚ��
sĂůŝĚ
ĂƚĞ�ĞŶ
ĐůŽƐƵƌĞ
ϭ�ĚĂ
LJdƵ
Ğ�ϭϮ
ϵϭϰ
dƵĞ�ϭϮ
ϵϭϰ
ϯϬdĞ
Ăŵ��
ZĞĚĞ
ƐŝŐŶ�ĞŶ
ĐůŽƐƵƌĞ
ϭ�ĚĂ
LJtĞĚ
�ϭϮϭϬ
ϭϰ
tĞĚ
�ϭϮϭϬ
ϭϰ
ϯϭdĞ
Ăŵ��
ZĞƉƌŝŶƚ�Ğ
ŶĐůŽƐƵƌĞ
Ϯ�ĚĂ
LJƐdŚ
Ƶ�ϭϮ
ϭϭϭϰ
&ƌŝ�ϭ
ϮϭϮ
ϭϰ
ϯϮdĞ
ĐŚ��ĞŶ
ƚĞ��
>ĂƐƚ�ŵ
ŝŶƵƚĞ�ĞŶ
ĐůŽƐƵƌĞ�ĂůƚĞ
ƌĂƚŝŽ
ŶƐϮ�ĚĂ
LJƐ^Ăƚ�ϭ
Ϯϭϯ
ϭϰ
^ƵŶ�ϭϮ
ϭϰϭϰ
ϯϯ:ĂŵĞƐ
7HDP ����
7HDP
����
7HDP
�����
(OOLR
W(OOLR
W(OOLR
W (OOLR
W(OOLR
W(OOLR
W(OOLR
W(OOLR
W
$OEH
UW$OEH
UW-DPHV (OOLR
W
-DPHV-DPHV -DPHV
-DPHV
$OEH
UW$OEH
UW7H
DP 7HDP 7HFK
�&HQ
WHU
-DPHV
6:
67
0)
76
:6
70
)7
6:
67
0)
76
:6
70
)7
6:
67
�����
$XJ���
����
6HS���
����
6HS���
����
2FW��
�����
2FW��
�����
1RY��
����
1RY��
�����
'HF��
����
'HF��
����
7DVN
6SOLW
0LOHVWR
QH
6XPPDU\
3URMHFW�6
XPPDU\
,QDFWLY
H�7D
VN
,QDFWLY
H�0LOHVWR
QH
,QDFWLY
H�6XP
PDU\
0DQ
XDO�7DVN
'XUDWLR
Q�RQ
O\
0DQ
XDO�6
XPPDU\�5
ROOXS
0DQ
XDO�6
XPPDU\
6WDUW�R
QO\
)LQLVK
�RQO\
([WHUQDO�7D
VNV
([WHUQDO�0LOHVWR
QH
'HDG
OLQH
&ULWLFDO
&ULWLFDO�6
SOLW
3URJ
UHVV
0DQ
XDO�3
URJUHVV
3DJH
��
3URMHFW��(/(;
����
��7H
FKQLFDO�3
U'D
WH��:
HG������
���d
ĞĂŵ
(OOLR
W�%DUHU��-DP
HV�(VDX�
$OEH
UW�3K
DQ
,'7DVN�1
DPH
'XUDWLR
Q6WDUW
)LQLVK
3UH5HVRX
UFH�
1DPHV
��WƌĞƉ
ĂƌĞ�ĨŽƌ�W
ƌĞƐĞŶƚĂƚŝŽŶ�
Ϯ�ĚĂ
LJƐDŽŶ
�ϭϮϭϱ
ϭϰ
dƵĞ�ϭϮ
ϭϲϭϰ
ϮϴdĞĂŵ
��WƌĞƉ
ĂƌĞ�ƐƉĞĂŬĞƌ�Ŷ
ŽƚĞƐ�Θ�ŽǀĞƌŚĞĂĚƐ�
ϭ�ĚĂ
LJDŽŶ
�ϭϮϭϱ
ϭϰ
DŽŶ
�ϭϮϭϱ
ϭϰ
dĞĂŵ
��WƌĂĐƚŝĐĞ�ƉƌĞƐĞŶ
ƚĂƚŝŽ
Ŷ�ϭ�ĚĂ
LJdƵ
Ğ�ϭϮ
ϭϲϭϰ
dƵĞ�ϭϮ
ϭϲϭϰ
ϯϲdĞĂŵ
��WƌĞƐĞŶ
ƚĂƚŝŽ
Ŷ�Ϭ�ĚĂ
LJƐdƵ
Ğ�ϭϮ
ϭϲϭϰ
dƵĞ�ϭϮ
ϭϲϭϰ
ϯϳdĞĂŵ
��tƌŝƚĞ�ΗWƌŽũĞĐƚ�ZĞƉ
ŽƌƚΗ
ϳ�ĚĂ
LJƐtĞĚ
�ϭϮϭϬ
ϭϰ
dŚƵ�ϭϮ
ϭϴϭϰ
dĞĂŵ
��ΗWƌŽũĞĐƚ�ZĞƉ
ŽƌƚΗ��ƵĞ
Ϭ�ĚĂ
LJƐ&ƌŝ�ϭϮϭϵ
ϭϰ
&ƌŝ�ϭϮϭϵ
ϭϰ
dĞĂŵ
7HDP 7HDP
�����
7HDP
�����
6:
67
0)
76
:6
70
)7
6:
67
0)
76
:6
70
)7
6:
67
�����
$XJ���
����
6HS���
����
6HS���
����
2FW��
�����
2FW��
�����
1RY��
����
1RY��
�����
'HF��
����
'HF��
����
7DVN
6SOLW
0LOHVWR
QH
6XPPDU\
3URMHFW�6
XPPDU\
,QDFWLY
H�7D
VN
,QDFWLY
H�0LOHVWR
QH
,QDFWLY
H�6XP
PDU\
0DQ
XDO�7DVN
'XUDWLR
Q�RQ
O\
0DQ
XDO�6
XPPDU\�5
ROOXS
0DQ
XDO�6
XPPDU\
6WDUW�R
QO\
)LQLVK
�RQO\
([WHUQDO�7D
VNV
([WHUQDO�0LOHVWR
QH
'HDG
OLQH
&ULWLFDO
&ULWLFDO�6
SOLW
3URJ
UHVV
0DQ
XDO�3
URJUHVV
3DJH
��
3URMHFW��(/(;
����
��7H
FKQLFDO�3
U'D
WH��:
HG������
���d
ĞĂŵ
(OOLR
W�%DUHU��-DP
HV�(VDX�
$OEH
UW�3K
DQ
Formal Report for SmartLock
APPENDIX H: STYLE GUIDE
Header & Footer (Helvetica Neue, Bold, 10pt, Gray)
Title (Helvetica Neue, UltraLight, 28pt)
HEADING 1 (HELVETICA NEUE, LIGHT, 18PT, GRAY) Heading 2 (Helvetica Neue, Bold, 15pt, Blue)
Heading 3 (Helvetica Neue, Bold, 13pt, Gray)
Body text will look like this, block format with 1.5x line spacing for paragraphs and a single line after each paragraph. There is one space following a period in a sentence. (Helvetica Neue, Light, 11pt, Black, Canadian English)
Block quotations have the same formatting as the body; however, they are inset by one tab (36pt) the entire way along the left side of the paragraph and are italicized.
Sample list, use of colon dependent on whether lead-in is a complete sentence:
• Point 1 • Point 2 • Point 3 (period at the end of each list item if it’s a complete sentence)
CAPTION FOR FIGURES AND TABLES, PLACED ABOVE (HELVETICA NEUE, BOLD, 11PT, GREY, ALL CAPS)
Footnote for Referencing Materials (Helvetica Neue, Light, 8pt, Right Justification)