Forked from ElectricImpSampleCode/webserver.agent.nut
Last active
August 25, 2020 20:09
-
-
Save androng/6306a5cfb608ef4982d6f570b4a538b3 to your computer and use it in GitHub Desktop.
Example code showing how an agent can serve a dynamic web page
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Updated: 14 July 2020 | |
// IMPORTS | |
#require "rocky.agent.lib.nut:3.0.0" | |
// CONSTANTS | |
const HTML_STRING = @"<!DOCTYPE html><html lang='en-US'><meta charset='UTF-8'> | |
<html> | |
<head> | |
<title>Environment Data</title> | |
<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css' integrity='sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk' crossorigin='anonymous'> | |
<link href='//fonts.googleapis.com/css?family=Abel' rel='stylesheet'> | |
<meta name='viewport' content='width=device-width, initial-scale=1.0'> | |
<style> | |
.center { margin-left: auto; margin-right: auto; margin-bottom: auto; margin-top: auto; } | |
body {background-color: #3366cc} | |
p {color: white; font-family: Abel} | |
h2 {color: #99ccff; font-family: Abel; font-weight:bold; padding: 20px;} | |
h4 {color: white; font-family: Abel} | |
a:link {color: white; font-family: Abel} | |
a:visited {color: #cccccc; font-family: Abel} | |
a:hover {color: black; font-family: Abel} | |
a:active {color: black; font-family: Abel} | |
</style> | |
</head> | |
<body> | |
<div class='container' style='padding: 20px'> | |
<div style='border: 2px solid white'> | |
<h2 class='text-center'>Environment Data</h2> | |
<div> | |
<h4 class='temp-status text-center'>Current Temperature: <span></span>°C</h4> | |
<h4 class='humid-status text-center'>Current Humidity: <span></span> per cent</h4> | |
<h4 class='locale-status text-center'>Sensor Location: <span></span></h4> | |
<p class='timestamp text-center'>Last reading: <span></span></p> | |
</div> | |
<br /> | |
<div class='update-button'> | |
<p class='text-center'>Update Location Name<br /><input id='location' style='width:200px;color:CornflowerBlue'></input><br /> | |
<button style='font-family:Abel' type='submit' class='btn btn-light btn-sm'>Set Location</button></p> | |
</div> | |
<br /> | |
<p class='text-center'><a href='https://developer.electricimp.com/examples/webserver'><small>Powered by Electric Imp</small></a></p> | |
</div> | |
</div> | |
<script src='https://code.jquery.com/jquery-3.5.1.min.js'></script> | |
<script> | |
// Store the agent URL | |
var agenturl = '%s'; | |
// Set the 'Set Location' button's action | |
$('.update-button button').click(getStateInput); | |
// Get the current state of the device, calling 'updateReadout()' when we have it | |
getState(updateReadout); | |
// Get State entry | |
function getStateInput(e){ | |
e.preventDefault(); | |
var place = $('#location').val(); | |
setLocation(place); | |
$('#name-form').trigger('reset'); | |
} | |
// Update the display when we receive device state information | |
function updateReadout(data) { | |
// Update the readouts | |
$('.temp-status span').text(data.temp); | |
$('.humid-status span').text(data.humid); | |
$('.locale-status span').text(data.locale); | |
// Display the current time and date (when the thermal data was received) | |
var date = new Date(); | |
$('.timestamp span').text(date.toTimeString()); | |
// Auto-update in 2 minutes' time | |
setTimeout(function() { | |
getState(updateReadout); | |
}, 120000); | |
} | |
// Send the content of the location field - ie. where the user has said the device | |
// is placed - to the agent using Ajax | |
function setLocation(place){ | |
$.ajax({ | |
url : agenturl + '/location', | |
type: 'POST', | |
data: JSON.stringify({ 'location' : place }), | |
success : function(response) { | |
if ('locale' in response) { | |
$('.locale-status span').text(response.locale); | |
} | |
} | |
}); | |
} | |
// Get the device state from the agent | |
function getState(callback) { | |
$.ajax({ | |
url : agenturl + '/state', | |
type: 'GET', | |
success : function(response) { | |
if (callback) { | |
callback(response); | |
} | |
} | |
}); | |
} | |
</script> | |
</body> | |
</html>"; | |
// GLOBAL VARIABLES | |
api <- null; | |
savedData <- null; | |
debug <- true; | |
// FUNCTIONS | |
function postReading(reading) { | |
// Format and save the data | |
savedData.temp = "temp" in reading ? format("%.2f", reading.temp) : "0.0"; | |
savedData.humid = "humid" in reading ? format("%.2f", reading.humid) : "0.0"; | |
local result = server.save(savedData); | |
if (result != 0) server.error("Could not back up data"); | |
} | |
// RUNTIME START | |
// Instantiate Rocky | |
api = Rocky.init(); | |
// Set up the app's API | |
api.get("/", function(context) { | |
// Root request: just return standard HTML string | |
local url = http.agenturl(); | |
context.send(200, format(HTML_STRING, url)); | |
}); | |
api.get("/state", function(context) { | |
// Request for data made to the /state endpoint | |
context.send(200, savedData); | |
}); | |
api.post("/location", function(context) { | |
// Sensor location string submission at the /location endpoint | |
local data = http.jsondecode(context.req.rawbody); | |
if ("location" in data) { | |
if (data.location != "") { | |
savedData.locale = data.location; | |
context.send(200, { "locale" : savedData.locale }); | |
local result = server.save(savedData); | |
if (result != 0) server.error("Could not back up data"); | |
return; | |
} | |
} | |
context.send(200, "OK"); | |
}); | |
// Set up the backup data | |
savedData = {}; | |
savedData.temp <- "TBD"; | |
savedData.humid <- "TBD"; | |
savedData.locale <- "Unknown"; | |
local backup = server.load(); | |
if (backup.len() != 0) { | |
savedData = backup; | |
} else { | |
local result = server.save(savedData); | |
if (result != 0) server.error("Could not back up data"); | |
} | |
// Register the function to handle data messages from the device | |
device.on("reading", postReading); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Updated: 14 July 2020 | |
// IMPORTS | |
#require "HTS221.device.lib.nut:2.0.2" | |
// CONSTANTS | |
const SLEEP_TIME = 120; | |
// GLOBAL VARIABLES | |
sensor <- null; | |
// FUNCTIONS | |
function getData() { | |
// Create a Squirrel table to hold the data - handy if we | |
// later want to package up other data from other sensors | |
local sendData = {}; | |
// Get the sensor data | |
local reading = sensor.read(); | |
// Add the temperature using Squirrel’s 'new key' operator | |
sendData.temp <- reading.temperature; | |
sendData.humid <- reading.humidity; | |
// Send the packaged data to the agent | |
agent.send("reading", sendData); | |
server.log("Temperature: " + reading.temperature); | |
server.log(" Humidity: " + reading.humidity); | |
// All done, we can put the device to sleep for 'SLEEP_TIME' minutes, | |
imp.onidle(function() { | |
server.sleepfor(SLEEP_TIME); | |
}); | |
} | |
// RUNTIME START | |
// Configure I2C bus and the sensor connected to it | |
// NOTE Updated for the imp006 Breakout Kit | |
// https://developer.electricimp.com/hardware/resources/reference-designs/imp006breakout | |
// Change the value of 'i2c' for other imps | |
local i2c = hardware.i2cLM; | |
i2c.configure(CLOCK_SPEED_400_KHZ); | |
sensor = HTS221(i2c); | |
sensor.setMode(HTS221_MODE.ONE_SHOT); | |
// Take a temperature reading as soon as the device starts up | |
// NOTE When the device wakes from sleep (caused by line 28) | |
// it runs its device code afresh - ie. it does a warm boot | |
getData(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I revised the Agent code to make it easier to add more outputs: https://gist.github.com/androng/6306a5cfb608ef4982d6f570b4a538b3/revisions