Skip to content

Instantly share code, notes, and snippets.

@ElectricImpSampleCode
Last active January 15, 2019 11:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ElectricImpSampleCode/738366b6dda0dad6aa182075766c30bd to your computer and use it in GitHub Desktop.
Save ElectricImpSampleCode/738366b6dda0dad6aa182075766c30bd to your computer and use it in GitHub Desktop.
Electric Imp Connected Factory Process Full Firmware Example
// ------------------------------------------------------------------------------
// File: factory.firmware.device.nut
// Version: 1.1.6
//
// Copyright 2015-18 Electric Imp
//
// SPDX-License-Identifier: MIT
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// ------------------------------------------------------------------------------
// ***************************************
// ***** SETUP *****
// ***************************************
// IMPORTS
// Load the Factory Tools Library, which simplifies detecting Fixture or DUT
#require "FactoryTools.lib.nut:2.2.0"
// Load the CFAx33KL Library, which abstracts the LCD/Keypad used on the impFactory
#require "CFAx33KL.device.lib.nut:2.0.0"
// Load the Button library to provide debouncing on the footswitch (if installed) and green button
#require "Button.class.nut:1.2.0"
// CONSTANTS
// Enter your factory WiFi credentials as the values of these constants
const SSID = "SSID";
const PASSWORD = "PASSWORD";
// Set the target WiFi Region code (see 'getRegionCode()', below, for values)
const WIFI_REGION = "US";
// Sets how long to wait (seconds) after triggering BlinkUp before allowing another
const BLINKUP_TIME = 10;
// GLOBALS
// Flag used to prevent new BlinkUp triggers while BlinkUp is running
local sendingBlinkUp = false;
local blinkUpCount = 0;
// ***************************************
// ***** FACTORY FIXTURE FUNCTIONS *****
// ***************************************
function blinkupTriggered() {
// Trigger only when BlinkUp is not already running
if (!sendingBlinkUp) {
sendingBlinkUp = true;
imp.wakeup(BLINKUP_TIME, function() {
sendingBlinkUp = false;
});
// Configure factory BlinkUp
// NOTE Depending on which LED you connect to your impFactory, you may need
// to remove the 'BLINKUP_ACTIVEHIGH' option (default is BLINKUP_ACTIVELOW)
local optionFlags = BLINKUP_FAST | BLINKUP_ACTIVEHIGH;
// Send factory BlinkUp
server.factoryblinkup(SSID, PASSWORD, blinkupPin, optionFlags);
// Signal the agent that BlinkUp has been performed
agent.send("blinkup.sent", true);
// Update the fixture display
blinkUpCount++;
lcd.setLine2(format("BlinkUp #%07i ", blinkUpCount));
}
}
function configureFactoryFixture() {
// Assign pins
greenBtn <- Button(hardware.pinC, DIGITAL_IN, Button.NORMALLY_HIGH, null, blinkupTriggered.bindenv(this));
footSwitch <- Button(hardware.pinH, DIGITAL_IN, Button.NORMALLY_HIGH, null, blinkupTriggered.bindenv(this));
ledGreen <- hardware.pinE;
ledRed <- hardware.pinF;
blinkupPin <- hardware.pinM;
// Initialize front panel LEDs to Off
ledRed.configure(DIGITAL_OUT, 0);
ledGreen.configure(DIGITAL_OUT, 0);
// Print a message on the LCD and store it as default
lcd <- CFAx33KL(hardware.uart2);
lcd.clearAll();
lcd.setLine1("Electric Imp");
lcd.setLine2("impFactory");
lcd.setBrightness(100);
lcd.storeCurrentStateAsBootState();
}
// ***************************************
// ** DEVICE UNDER TEST (DUT) FUNCTIONS **
// ***************************************
function blessDeviceUnderTest() {
// Run any tests you require for you DUT
local testSuccess = myTestFunction();
// Attempt to bless this device, and send the result to the Factory Test Results Webhook
server.bless(testSuccess, function(blessSuccess) {
// Send identifying info and result to the test results webhook
agent.send("test.result", { "device_id": hardware.getdeviceid(),
"success": (blessSuccess ? "SUCCEEDED" : "FAILED") });
// Clear the WiFi credentials and reboot if blessing completes successfully
if (blessSuccess) {
imp.clearconfiguration();
imp.setcountry(getRegionCode(WIFI_REGION));
// The imp will go idle at this point, allowing impOS to install
// application code and restart the Squirrel VM if the Production Device Group’s
// devices are set to receive application code immediately after blessing
// If you are installing your application upon device activation (first
// end-user BlinkUp), you can power down the device at this point
}
});
}
function getRegionCode(location = "US") {
// Pass in the region ID, eg. "UK", "US", to receive the code for that region
local type = imp.info().type;
local returnCode = 0;
// Region codes data organized by territory code
// Each region has two values: the first for imp001 through imp004m, the second for imp005
// NOTE select "OT" for all regions than those listed (US, Canada, Europe/UK, Japan)
local codes = { "US" : [0x00005355, 0x00115858],
"CA" : [0x00005355, 0x03B64143],
"EU" : [0x00004247, 0x037F3045],
"JA" : [0x00004247, 0x03B8504A],
"OT" : [0x00004247, 0x03D75658] }
if (location in codes) {
returnCode = codes[location];
returnCode = returnCode[(type == "imp005" ? 1 : 0)];
} else {
server.error("Invalid region ID supplied - choosing US");
returnCode = codes.US[(type == "imp005" ? 1 : 0)];
}
server.log(format("Region code chosen: 0x%08X", returnCode));
return returnCode;
}
// ***************************************
// ***** YOUR HARDWARE TEST CODE *****
// ***************************************
function myTestFunction() {
// Run your tests here
// Returning false will prevent blessing and pass a "FAILED" to the test results webhook
return true;
}
// ***************************************
// ***** RUNTIME START *****
// ***************************************
// Use the Factory Tools library's isFactoryImp() call asynchronously in order to be sure
// the impFactory is online and has received device status data from the server
FactoryTools.isFactoryImp(function(isImpFactory) {
if (isImpFactory) {
// Device is an impFactory unit
configureFactoryFixture();
} else {
// The next call need not be asynchronous since we can be sure
// at this point (we're executing in a callback) that the status
// data has now been received by the device (whatever it is)
if (FactoryTools.isDeviceUnderTest()) {
// Device is a production unit - test it
blessDeviceUnderTest();
} else {
throw "This firmware is not running in the factory environment";
}
}
});
// ------------------------------------------------------------------------------
// File: factory.firmware.factoryagent.nut
// Version: 1.1.6
//
// Copyright 2015-18 Electric Imp
//
// SPDX-License-Identifier: MIT
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// ------------------------------------------------------------------------------
// ***************************************
// ***** SETUP *****
// ***************************************
// IMPORTS
// Load the Factory Tools Library, which simplifies detecting Fixture or DUT
#require "FactoryTools.lib.nut:2.2.0"
// CONSTANTS
// Replace the following string with your server logging endpoint
const RESULTS_URL = "YOUR_RESULT_LOGGING_URL";
// GLOBALS
local blinkUpCount = 0;
// ***************************************
// ***** DUT AGENT FUNCTIONS *****
// ***************************************
// Set up an receiver for "test.result" messages from the device under test (DUT)
// This will NOT be called by a factory BlinkUp fixture, because our device-side
// firmware only sends this message from DUTs
device.on("test.result", function(data) {
local deviceID = imp.configparams.deviceid;
local headers = { "Content-Type": "application/json" };
local body = http.jsonencode(data);
// The following line is helpful for debugging factory firmware during development.
server.log(format("Posting message 'test results' for device %s: %s", deviceID, body));
// Send the test result data to your server
http.post(RESULTS_URL, headers, body).sendasync(function(response) {
if (response.statuscode >= 300) {
// The following line will not be called in a production environment
// unless you have enabled logging for the specific device via impCentral
server.error(format("Failed posting test results for device %s with response %d:%s", deviceID, response.statuscode, response.body));
}
});
});
// ***************************************
// ***** FACTORY FIXTURE AGENT CODE ****
// ***************************************
// Set up a receiver for "blinkup.sent" messages from the factory fixture
// This will NOT be called by a DUT, because our device-side firmare
// only sends this message from factory fixtures
device.on("blinkup.sent", function(value) {
// Increment the BlinkUp tally
blinkUpCount++;
// Prepare the notification
local deviceID = imp.configparams.deviceid;
local headers = { "Content-Type": "application/json" };
local data = {};
data.fixture_url <- FactoryTools.getFactoryFixtureURL();
data.blinkup_count <- blinkUpCount;
data.timestamp <- time();
data.message <- format("BlinkUp #%08i triggered by fixture ID %s", blinkUpCount, deviceID);
local body = http.jsonencode(data);
// The following line is helpful for debugging factory firmware during development
server.log(format("Posting message 'blinkup sent' for device %s: %s", deviceID, body));
// Send the notification to your server
http.post(RESULTS_URL, headers, body).sendasync(function(response) {
if (response.statuscode >= 300) {
// The following line will not be called in a production environment
// unless you have enabled logging for the specific device via impCentral
server.error(format("Failed posting blinkup notification for device %s with response %d:%s", deviceID, response.statuscode, response.body));
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment