Gecko OS Security Camera Demo
This SDK app demonstrates how to take images with an Arducam module and display on a remote webpage. With the webpage, a user can view live images taken by the device, display the Hurricane sensor reads, view GPS location on interactive map, and adjust the camera settings.
A live demo may be found here: https://hurricane-security-camera.web.app/
Example device registration code:
43B4
Overview
The flow of data for this demo is as follows:
Hurricane + Camera/GPS daughtercard -> DMS Connection -> DMS -> DMS Connector -> Firebase Cloud Function -> Firebase Storage
- Image taken with Arducam module
- Image message sent to DMS via secure connection
- DMS webhook 'connector' processes image message. More details here
- DMS webhook 'connector' forwards image message to Google Firebase
- Firebase cloud function stores image to database.
At a later time, a user goes to the demo webpage and views the images stored on Firebase.
- More details about Firebase hosting here
Setup
To run this demo using GSS, execute the following steps:
-
Using GSS, create a project with this Hurricane Security Camera application GSS will automatically execute the following:
a. Create a project from thishurricane.security_camera
app
b. Create aproduct
in the DMS for the project. More details here .
c. Program the app to the Hurricane -
Go to the DMS and find the product that was created in the previous step
- Configure DMS product Firebase connector. More details here
- Run the application on Hurricane by pressing button 2
- Use the LCD menu to setup the device with Wi-Fi
-
If the previous steps were successfully completed, the LCD should display
aRegistration Code
(among other information) -
Go to
https://hurricane-security-camera.web.app
and enter the
Registration Code
-
The webpage should register the device and images from the Hurricane should be displayed on the webpage.
By default the app will post an image every 90s. Press button 2 to trigger the app to immediately post and image.
Create DMS Product
If you used GSS to create this project then this step is done automatically. To verify, go to the DMS and lookup your product based on the product code used when creating the project.
Otherwise, refer to this tutorial for instructions on how to create a product on the DMS.
Configure DMS Product Connector
A DMS product 'connector' is required to forward images from the device to Firebase.
Follow these instructions for configuring the connector:
- Go to the DMS
- Lookup your product in the DMS
-
Select the
Connectors
tab from the sidebar -
Click the
Create Connector
button
Create Product Connector
-
For the
Title
field enter any name you like -
For the
Code
field, enter:IMAGE
-
For the
Type
field, select:Webhook
-
For the
Endpoint
field, select:REST
-
For the
URL (POST)
field, enter:https://us-central1-hurricane-security-camera.cloudfunctions.net/addImage
-
Check the
Headers
checkbox -
For the
Key
field, enter:Authorization
-
For the
Value
field, enter:262bcb82-8942-4c2c-9c52-41eb2c1b3f43
-
Click the
Save
button
Create DMS Connector
Connect Device to Local Network
To run this demo, the device must connect to a local network with Internet access.
To connect the device to a Wi-Fi network, issue the following Gecko OS commands:
network_up -s
OR
set wlan.ssid <NETWORK NAME>
set wlan.passkey <NETWORK PASSWORD>
network_up
Activate Device to DMS Product
The device must be 'activated' to the DMS product from section:
Configure DMS Product Connector
.
To activate the device to this product, issue the following Gecko OS command:
dms_activate <product code>
Device Registration Code
When the demo app first starts, it prints its registration code to the console. The print statement looks something like:
*** Device registration code: 43B4
The code must be used to access the device from the demo webpage .
NOTE: By default, the registration code is the last four characters of the device's WLAN MAC address.
Next Steps
Now that the device is successfully posting images to the demo webpage , replicate the demo webpage on your own Firebase server and customize it.
Firebase Setup
The demo uses Google Firebase:
https://firebase.google.com
for the cloud 'backend',
and Quasar Framework:
https://v1.quasar-framework.org
for the GUI 'frontend'.
This README describes how to:
- Configure the Firebase backend
- Run a local server using Quasar to development the GUI frontend
- Deploy your changes to the cloud
IMPORTANT!
It is assumed you have already read the README at the root of this project. The following is assumed to already be working:
- Security Camera app running on device
- DMS product created and webhook configured
- Device activated to product
- Device successfully posting images to demo cloud
Prerequisites
Before we begin, you will need the following installed onto your computer:
NodeJS 8
Firebase uses NodeJS version 8.
You can download NodeJS v8 from here:
https://nodejs.org/dist/latest-v8.x
NOTE: x86 or x64 is fine.
Quasar CLI
The Quasar Command-Line Interface (CLI) needs to be globally installed for NodeJS.
Run the following command to install Quasar-CLI globally:
npm install -g @quasar/cli
NOTE: You must have NodeJS installed first
Firebase CLI
The Firebase Command-Line Interface (CLI) needs to be globally installed for NodeJS.
Run the following command to install Firebase-CLI globally:
npm install -g firebase-tools
NOTE: You must have NodeJS installed first
Webstorm JS Editor
This is 100% optional. However, if you are new to web development, this is recommended to help you edit the Javascript files.
https://www.jetbrains.com/webstorm/download
NOTE: Webstorm costs money, but there is a 30-day free evaluation, no credit card required.
Firebase Setup
This sections describes how to setup your Firebase project.
Sign into Firebase
To sign into Firebase, go to:
https://firebase.google.com
and click the
Sign in
button on the top right.
NOTE: If you don't already have one, you'll need to create Google account. You don't need a gmail email address, you can use your standard work email address.
Create Remote Firebase Project
After signing into Firebase, go to the Firebase console by clicking the
Go to console
on the top right.
Next, click the 'Add Project' button:
Create Firebase Project
Next, name the project anything you like, for this example we'll name it:
Security Camera
Next, check the licensing agreements checkboxes and click the 'Create Project' button.
Configure Local Firebase Project
Locally Log into Firebase
We now need to configure the remote Firebase project with our local project.
Log into Firebase by issuing the following commands:
cd <sdk app dir>/resources/cloud_server
firebase login
This will pop up a browser tab and request your Google account credentials.
After entering your Google account credentials your local project will have access to your remote Firebase account.
List Available Projects
Next, list the available remote Firebase projects with the commands:
cd <sdk app dir>/resources/cloud_server
firebase list
This will list your Firebase projects and corresponding IDs.
NOTE:
If the
list
command fails, try the following:
- Go to to the remote Firebase console, select the 'gear' icon on the upper left, then 'Project Settings'
- Note the 'Project ID'
Firebase Project ID
Configure Project ID
Now, we need to configure the local project with the remote Firebase project.
Issue the following commands:
cd <sdk app dir>/resources/cloud_server
firebase use <project id>
where
<project id>
is the ID from the previous step.
Configure Project Settings
Now, we need to retrieve and configure the Firebase project settings.
Issue the following commands:
cd <sdk app dir>/resources/cloud_server
firebase setup:web
This command should return something like:
...
firebase.initializeApp({
"apiKey": "AIzaSyDoSi5GFPz-NK5FeKPcjSKwhW4UYT-H3EI",
"databaseURL": "https://gecko-os-security-camera.firebaseio.com",
"storageBucket": "gecko-os-security-camera.appspot.com",
"authDomain": "gecko-os-security-camera.firebaseapp.com",
"messagingSenderId": "7260947856",
"projectId": "gecko-os-security-camera"
});
Copy everything between the curly brackets, e.g. copy all lines from
"apiKey"
to
projectId"
(inclusive).
After copying, open the following file with a text editor:
<sdk app dir>/resources/cloud_server/functions/config/firebase-config.js
And paste between the curly brackets of
exports.FIREBASE_CONFIG =
.
e.g. Update
exports.FIREBASE_CONFIG
to have all the fields from the above command.
Configure Cloud Function URL
Now, we need to determine the cloud function URL. This is the URL the the frontend and DMS use to invoke Cloud functions on the backend.
- Go to the remote Firebase console
-
Select the
Function
sidebar tab -
Select the
Dashboard
tab -
There should be two functions in the list:
-
/addImage
-
/registerDevice
-
-
Copy the URL of the
/addImage
function, exluding the last part:/addImage
e.g. If the URL is:
https://us-central1-gecko-os-security-camera.cloudfunctions.net/addImage
then only copy:
https://us-central1-gecko-os-security-camera.cloudfunctions.net
Cloud Function URL
With the URL copied, open the following file with a text editor:
<sdk app dir>/resources/cloud_server/functions/config/firebase-config.js
And paste the copied URL as the value of:
exports.FUNCTIONS_URL
.
e.g. Update
exports.FUNCTIONS_URL
to be the URL that points your Firebase project's server.
Configure Service Account
Next, we need to do is update the 'service account' settings.
- Go to the remote Firebase console
-
Select the 'gear' in the upper left, then select
Project Settings
from the menu -
Select the
Service accounts
tab -
Ensure the
Node.js
radio button is selected -
Click the
Generate new private key
button - A 'Save As' dialog should appear, save the file to (replacing the old one):
<sdk app dir>/resources/cloud_server/functions/config/service-account.json
Service Account Generation
Generate a DMS Webhook Auth Token
Next, we need to generate an authorization token the DMS must use to forward images from devices to Firebase.
You can generate a random token here: https://www.uuidgenerator.net/version4
- Copy the random token from the webpage
- Open the following file with a text editor:
<sdk app dir>/resources/cloud_server/functions/config/firebase-config.js
-
Replace the value of
exports.DMS_WEBHOOK_AUTH_TOKEN
with the copied token
Enable Cloud Firestore for Project
Next, we need to enable the 'Cloud Firestore' for our Firebase project.
Do this by:
- Go to remote Firebase console
-
Click the
Database
tab on the sidebar -
Click the
Create database
button -
A dialog will appear, select the
Start in locked mode
radio button (default) -
Click the
Enable
button
Firebase Database Tab
Enable Cloud Storage for Project
Next, we need to enable the 'Storage' for our Firebase project.
Do this by:
- Go to remote Firebase console
-
Click the
Storage
tab on the sidebar -
Click the
Get Started
button -
Just use the default rules by clicking the
Got it
button (we'll update the rules when we deploy the project later)
Firebase Storage Tab
Build GUI Frontend
Next, we need to build the GUI frontend with our updated Firebase configuration.
Do this by issuing the following commands:
cd <sdk app dir>/resources/cloud_server/public
npm install
quasar build
These commands install all JS dependencies then uses the Quasar-CLI to build the application.
Install Backend Dependencies
Next, we need to install all dependencies required by the backend.
Do this by issuing the following commands:
cd <sdk app dir>/resources/cloud_server/functions
npm install
Deploy Local Project to Cloud
Our local project should now be fully configured and ready for deployment to the remote Firebase server.
To deploy the local project, issue the following commands:
<sdk app dir>/resources/cloud_server
firebase deploy
This will deploy the following to your remote Firebase project:
-
Built GUI frontend (see
cloud_server/public/dist/spa
) -
Cloud functions backend (see
cloud_server/functions
) -
Database security rules (see
cloud_server/firestore.rules
) -
File storage security rules (see
cloud_server/storage.rules
)
Your Firebase project is now ready for local development.
Configure DMS Product
Now that the Firebase project is setup, we need to configure the DMS product to forward images from the device to the Firebase project.
NOTE:
This assumes you already have a product created on the DMS and that the device is activated to the DMS product.
If you used GSS to create this project then that is the default behavior.
Create DMS Connector
Next, we need to create a 'connector' that forwards images from the device to Firebase:
- Go to the DMS: https://dms.zentri.com
- Lookup your product in the DMS
-
Select the
Connectors
tab from the sidebar -
Click the
Create Connector
button
Create Product Connector
-
For the
Title
field enter any name you like -
For the
Code
field, enter:IMAGE
-
For the
Type
field, select:Webhook
-
For the
Endpoint
field, select:REST
-
For the
URL (POST)
field, enter the value fromexports.FUNCTIONS_URL
in the file:
<sdk app dir>/resources/cloud_server/functions/config/firebase-config.js
And append:
/addImage
. e.g. If
exports.FUNCTIONS_URL = 'https://us-central1-gecko-os-security-camera.cloudfunctions.net'
then this field's value should be:
https://us-central1-gecko-os-security-camera.cloudfunctions.net/addImage
-
Check the
Headers
checkbox -
For the
Key
field, enter:Authorization
-
For the
Value
field, enter the value ofexports.DMS_WEBHOOK_AUTH_TOKEN
found in the file:
<sdk app dir>/resources/cloud_server/functions/config/firebase-config.js
-
Click the
Save
button
Create DMS Connector
Verify Device -> DMS -> Firebase Working
If you haven't done so already, program the SDK application to the device and configure the device's network settings. When the device connects to the network, the device will open a secure connection to the DMS. Once the DMS connection is opened, it will begin capturing images and sending the images to the DMS connection. When the DMS receives the image, it will forward the image to Firebase (assuming everything is configured correctly).
Verify Device Connection
First verify the device is able to open a connection the DMS.
In the device's console, you should see something like:
...
[Associating to My Network]
*** Device registration code: 87EF
Ready.
Security type from probe: WPA2-AES
Opening DMS websocket connection ...
Resolving host: cmd.zentri.com
Connecting (WS): 54.165.31.10:80
Connection stream up
DMS websocket ready
Starting image capture
...
Verify Device Activated to DMS Product
It was assumed that the device is already activated to the DMS product, but just as a sanity check:
- Go to the DMS: https://dms.zentri.com
- Look up the product you created the 'connector' for in the DMS
-
Select the
Devices
tab - Ensure your device appears in the list
Product Devices
Note: You can retrieve the device's UUID by issuing the following Gecko OS command:
get system.uuid
Verify Firebase Cloud Functions Working
Next, verify that the DMS is able to forward images to Firebase:
- Go to the Firebase remote console
-
Select the
Database
sidebar tab - A device should appear in the database with default settings:
Device in Database
Note that this device is automatically created in the database the first time the device posts an image.
If you do not see a device in the database, then that likely means there is an issue with either:
- DMS Connector
-
/addImage
Firebase Cloud Function
Firebase Cloud Functions Log
You can view logs generated by the Firebase Cloud functions by:
- Go to the Firebase remote console
-
Select the
Functions
sidebar tab -
Select the
Logs
tab -
Press the
Play
button on the right
Functions Log
This will post logs generated by the cloud functions as they are invoked.
If you do not see the
addImage
function in this list then that means there is an issue with the DMS connector configuration.
If the
addImage
function is in the log list, then the DMS connector is working but there is likely an issue with the local project's configuration. Refer to the previous sections for configuring your local project.
NOTE: You may safely ignore the following warning in the log:
Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions
Verify GUI Working
Now that we've verified the backend is working (i.e. the device is able to post images to the Cloud), let's verify the GUI frontend is working:
- Go to the remote Firebase console
-
Select the
Hosting
tab -
In the first section, select the
<project id>.web.app
domain This will display launch the Demo webpage in your browser
Hosting Domain
- Enter your device's 'registration code' (the device prints the registration code to the Gecko OS console on startup)
- If everything worked correctly you should see images from the device posted to this page
Registration Dialog
Wrap Up
Take a deep breath, you did it!
Both the remote Firebase project and local project are ready for development.
Additionally, the device and DMS connector are fully configured and functioning.
The next step is to begin developing the backend Cloud and frontend GUI. Refer to the next sections for more details.
Backend Development
This section describes how to develop the backend and deploy to the Cloud (i.e. Firebase).
The backend consists of 'cloud function'. Basically, these a URLs that invoke a JS function when called. More details here: https://firebase.google.com/docs/functions
Webstorm Project
If you installed Webstorm, open the following 'existing' project:
-
<sdk app dir>/resources/cloud_server/functions
Webstorm Open Project
Install Dependencies
This should have been done during project configuration, but just to be sure, install all dependencies required by the backend.
This is done by issuing the following commands:
cd <sdk app dir>/resources/cloud_server/functions
npm install
Cloud Functions
There are two cloud functions used by this example:
-
/addImage
- called by DMS connector, adds image to database/storage -
/registerDevice
- called by frontend, registers demo webapp with specific device
/addImage
Function
This function is called by the DMS connector. When a device posts an image to its DMS connection, the DMS connector invokes its configured URL, e.g.:
https://us-central1-gecko-os-security-camera.cloudfunctions.net/addImage
When Firebase receives this request, the function in:
<sdk app dir>/resources/cloud_server/functions/addImage.js
is invoked.
So the chain of events is:
-
Device posts image request to DMS connection, see
arducam_data_writer_callback()
incamera.c
of the example app: The device's request has the following format:{ request: "webbook", code: "IMAGE", data: { uuid: "<device UUID string>", code: "<device registration code>", timestamp: <UTC timestamp in seconds>, img: "<binary image data>" } }
-
DMS receives request, forwards to 'webhook' connector that has code:
IMAGE
-
IMAGE
webhook connector invokes its configured URL,
e.g.:https://us-central1-gecko-os-security-camera.cloudfunctions.net/addImage
and forwards the device's request to the URL -
Firebase receives request and invokes the
addImage.js
cloud function - Cloud function executes and returns response to DMS connector
- DMS connector forwards cloud function response to device
- Device processes response and updates its camera settings if necessary
The
/addImage
cloud function does the following:
-
Verifies request has valid
Authorization: <DMS_WEBHOOK_AUTH_TOKEN>
header - Retrieves or creates device in database based on device's UUID
- Adds image to persistent storage
- Adds image details to database
- Deletes any old images from storage and database
- Returns device settings retrieved from database as response to request
/registerDevice
Function
This function is called by the GUI when the user 'registers' a device.
e.g. When the user clicks the 'Register Device' button the GUI invokes:
https://us-central1-gecko-os-security-camera.cloudfunctions.net/registerDevice
When Firebase receives this request, the function in:
<sdk app dir>/resources/cloud_server/functions/registerDevice.js
is invoked.
This function does the following:
- Retrieves the device from the database based on the 'registration code' provided by the user
- If the device exists, an custom authentication token is generated
- Auth token is returned in the response
The GUI uses the auth token to log into Firebase. With the auth token, the GUI is able to access the specific device in the database.
Cloud Functions Logging
When a cloud function is invoked, log are generated. You can view the logs by:
- Go to the Firebase remote console
-
Select the
Functions
sidebar tab -
Select the
Logs
tab -
Press the
Play
button on the right
Functions Log
You can add additional logs by adding:
console.log('... log msg here ...')
to the JS function.
Deploying Updates
Once you've made changes to the cloud functions, you need to deploy the changes to Firebase. From the command line, you can do this by issuing the commands:
cd <sdk app dir>/resources/cloud_server/functions
npm run deploy
Webstorm Deploy
If you are using Webstorm, you can deploy the cloud functions by running the
deploy
configuration in the top right:
Webstorm Functions Deploy
Cloud Function Local Debugging
While it is beyond the scope of this document, it should be noted that you can run and debug cloud functions locally.
More details here:
https://firebase.google.com/docs/functions/local-emulator
Frontend Development
This section describes how to develop the GUI frontend and deploy to the Cloud (i.e. Firebase).
Webstorm Project
If you installed Webstorm, open the following 'existing' project:
-
<sdk app dir>/resources/cloud_server/public
Webstorm Open Project
Quasar Framework
The GUI is a 'Single Page Application' (SPA) based on the Quasar Framework:
https://v1.quasar-framework.org/introduction-to-quasar
Quasar is based on VueJS: https://vuejs.org that provides GUI elements as well as a build system.
Refer to the following for a comprehensive list of all the GUI elements offer by Quasar:
https://v1.quasar-framework.org/vue-components
Install Dependencies
This should have been done during project configuration, but just to be sure, install all dependencies required by the frontend.
This is done by issuing the following commands:
cd <sdk app dir>/resources/cloud_server/public
npm install
Local Development Server
Development of the GUI is done by running a local development server. With the development server, you can make changes to the GUI source files and immediately see the changes reflected in the GUI.
The basic flow for local development is as follows:
-
Start development server with command:
npm run dev
- Open URL to local dev server in web browser
- Modify GUI source files, all changes will immediately be reflected in the web browser
- Once local dev is done, deploy to cloud
To start the local development server, issue the following commands:
cd <sdk app dir>/resources/cloud_server/public
npm run dev
Webstorm Dev Server
If you are using Webstorm, you can start the development server by starting the
dev
configuration:
Webstorm Start Dev Server
Web Browser
With the dev server started, open a browser tab to the URL printed when the dev server was started, e.g.:
http://localhost:8080
NOTE: By default the browser tab should open automatically.
In the web browser is a local copy of the GUI. Any changes you make to the source files will automatially be reflected in the browser.
Note that while the GUI is running locally, the GUI will still access the remote Firebase server.
Chrome Debugging
While most browsers are supported for local development, the README will describe how to debug the GUI using Chrome Development Tools:
https://developers.google.com/web/tools/chrome-devtools
With the GUI displaying in a Chrome tab, open the Chrome development tools:
- Click the settings button on the top right
-
Select
More tools
menu entry -
Select the
Developer tools
menu entry
Chrome Dev Tools
This should open a sidebar providing various development features.
Debug Console
Click the
Console
tab to view logs from the GUI.
Be sure to enable
All levels
to see verbose logs.
Chrome Log Console
This console will display all logger statements found in the GUI source files, e.g.:
-
logger.debug()
-
logger.info()
-
logger.warn()
-
logger.error()
More details about the Chrome debug console here:
https://developers.google.com/web/tools/chrome-devtools/console
Breakpoints
Using Chrome Development tools, you can also set breakpoints in the JS and view the context when breakpoint is hit.
As an example of setting breakpoints, try the following:
-
Select the
Sources
tab in the development tools -
Select the
webpack://
from the sidebar -
Select
Display.vue?xxxx
in the list - Set a breakpoint at line 46
Chrome Breakpoints
Then refresh the GUI tab. When the GUI reloads, execution should stop at line 46 of
Display.vue
.
Here you can see the callstack and all variables.
More details about using Breakpoints in Chrome here:
https://developers.google.com/web/tools/chrome-devtools/javascript/breakpoints
Deploying GUI to the Cloud
Once the GUI is working locally, it is time to deploy to the Cloud.
Deploying to the cloud can be done with the following commands:
cd <sdk app dir>/resources/cloud_server/public
npm run build:deploy
Webstorm Deploy
If you are using Webstorm, you can deploy using the
build:deploy
configuration:
Webstorm Deploy
Source Files
-
resources
-
cloud_server
- functions
-
public
-
src
- boot
-
components
-
controls
-
location
- index.vue
-
sensors
- index.vue
- SensorChart.vue
-
settings
- Dropdown.vue
- index.vue
- Slider.vue
- Toggle.vue
- index.vue
-
location
-
display
- Gauge.vue
- index.vue
- Sensors.vue
- Timeline.vue
- DeviceDetails.vue
-
controls
-
css
- app.styl
- quasar.variables.styl
- helpers
-
layouts
- desktop.vue
- LayoutMixin.js
- mobile.vue
-
pages
-
desktop
- index.vue
-
mobile
- DeviceDetails.vue
- Display.vue
- Location.vue
- Sensors.vue
- Settings.vue
- ErrorDialog.vue
- Register.vue
-
desktop
- router
-
statics
-
icons
- favicon-16x16.ico
-
icons
- store
- App.vue
- index.template.html
- .editorconfig
- .eslintignore
- .eslintrc.js
- .postcssrc.js
- .stylintrc
- babel.config.js
- package-lock.json
- package.json
- quasar.conf.js
- README.md
-
src
- firebase.json
- firestore.indexes.json
- firestore.rules
- README.md
- storage.rules
- settings.ini
-
cloud_server
- camera.c
- common.h
- main.c
- README.md
- security_camera.mk
- sensor.c
- settings.c