Stap 7: Een nauwere kijken hoe het werkt: expediteur
Het eerste wat dat de agent doet wanneer op zelfstart opwaarts is te controleren en zien of het gewoon opnieuw wordt opgestart en al de apparaat-ID weet. Wanneer de agent heeft te gaan en krijgen de apparaat-ID van het apparaat, bewaart het het in de cloud imp met server.save() zodra het wordt de update. Deze manier, als de agent ooit opnieuw begint, kan het grijpen de ID meteen zonder zelfs te inchecken met het apparaat door te bellen naar server.load():
// Device ID used to create new channels in this feed for each new turkey probe<br>config <- server.load(); if (!("myDeviceId" in config)) { // grab the pre-saved device ID from the server if it's there // if it isn't, we've never seen this device before (or the server forgot - unlikely!) // we will request a device ID from the device if we make it past class declarations without // the device doing an "I just woke up" check-in. config.myDeviceId <- null; }<br>
Net onder dit lopen we in een gigantische functie met een zeer grote meerlijnige string in het. Deze functie heet prepWebpage, en alles wat het doet is een paar tekenreeksen samen samenvoegen. Deze tekenreeksen gebeuren net zo als een website. Deze website is het web UI voor de BBQ-thermometer, en het is wat u ziet wanneer u de agentURL in een browser opvraagt. Omdat de agent de mogelijkheid heeft om het opzetten van een eigen HTTP-handler, kan het reageren op bepaalde aanvragen door serveren op deze zeer lange tekenreeks - Kortom, de agent werkt als een kleine webserver. De website bevat ook enkele eenvoudige javascript dat wordt uitgevoerd op de machine van de client.
Na de website heeft de agent een functie die houdt van activiteit op het apparaat en maakt gebruik van een timer en sommige eenvoudige heuristiek om erachter te komen als het apparaat moet gaan slapen om op te slaan batterij.
function checkSleepTimer() {imp.wakeup(TIMER_DEC_INTERVAL, checkSleepTimer); sleepTimer -= TIMER_DEC_INTERVAL; if (sleepTimer < 0) {sleepTimer = 0}; //server.log("Sleep Timer = "+sleepTimer); if ((sleepTimer == 0) && device.isconnected()) { if (lastTemp < MAX_AUTOSLEEP_TEMP) { // TODO: if app is open, don't sleep device.send("sleep",0); } } }
Dit werkt graag gieten zand in de bovenkant van een zandloper. Als de temperatuur snel verandert, voegt de agent meer zand aan de bovenkant van de zandloper, zodat het apparaat meer tijd om te werken. Als de mate van temperatuurverandering vertraagt, de agent toevoegend zand, de zandloper uiteindelijk afloopt, en de agent vertelt het apparaat om te gaan slapen. Als de temperatuur zich boven een bepaalde drempel, neemt de agent het apparaat is nog steeds betrokken bij het koken van iets, en wacht tot de temperatuur dalen opnieuw voordat u de volgorde van de slaap.
Na dit is er een grote brok van code gewijd aan het werken met Xively. Dit is een algemene klasse, en je kunt het leren van meer over, evenals andere klassen voor het werken met andere webservices, door het nemen van een kijkje op de elektrische imp webservices github pagina.
Vervolgens zien we de registratie van sommige gebeurtenis-handlers voor gebeurtenissen van het apparaat, net zoals we eerder ook hebben gezien in de apparaatcode agent. De meest interessant hier is de "temp" gebeurtenis-handler, die doet alles wat het moet doen om te posten van de nieuwe temperatuur gegevens naar Xively en bijwerken van de sluimer-timer:
device.on("temp", function(data) {local delta = math.abs(data.temp - lastTemp); lastTemp = data.temp; if (delta > MIN_CHANGE) { // only add time to the timer if we have activity if (delta > 30) { sleepTimer += 60; } else { sleepTimer += delta * 2; } } // don't let the sleep timer exceed the preset max. if (sleepTimer > MAX_SLEEP_TIMER) {sleepTimer = MAX_SLEEP_TIMER}; local tempStr = format("%.1f",data.temp); server.log("Temp: "+tempStr+" F"); // post the datapoint to the Xively feed postToXively(tempStr, "temperature"); // check for low-battery issues server.log("Battery: "+data.vbat+" V"); if (!lowBattAlarm && (data.vbat < LOW_BATT_THRESH)) { // set the low batt alarm and post it to xively server.log("Low battery alert!"); lowBattAlarm = 1; postToXively(lowBattAlarm, "lowbatt") } else if (lowBattAlarm && (data.vbat > LOW_BATT_THRESH)) { // clear the low batt alarm and post it to xively lowBattAlarm = 0; postToXively(lowBattAlarm, "lowbatt") server.log("Low battery alert cleared."); } });
Vanwege hoe dit apparaat is bekabeld, het eigenlijk niet zal ooit leiden tot de laag energieniveau; Dit was voor een vergelijkbaar apparaat die werd aangedreven op een tweetal AA lithiumbatterijen zonder een regelgever tussen de batterijen en het GMB, zodat het GMB naar de accuspanning direct kijken kon opgenomen. De code werd achtergelaten in geval iedereen intrepid krijgt en een in de oorspronkelijke behuizing bouwt!
In de buurt van de onderkant van de firmware van de agent, we zien een van de belangrijkste onderdelen van de agent: de HTTP-aanvraag-handler. Deze handler parseert binnenkomende HTTP-aanvragen en wordt gedefinieerd hoe de agent moet reageren.
http.onrequest(function(request, res) {<br> server.log("Agent got new HTTP Request"); // we need to set headers and respond to empty requests as they are usually preflight checks res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept"); res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); if (request.path == "/sleep" || request.path == "/sleep/") { device.send("sleep",0); res.send(200, "Going to Sleep"); } else { server.log("Agent got unknown request"); res.send(200, WEBPAGE); } });
Het merendeel van de verzoeken om de agent gonna be verzoeken alleen voor de webpagina, zodat aanvragen zonder extra parameters alleen de webpagina als een reactie krijgen. Er is ook een "haak" hier voor externe diensten om te vertellen van het GMB om te gaan slapen, die maakt geen gebruik van de webpagina.
Tot slot, de agent instantieert een Xively Client-object die tijdens runtime wordt gebruikt voor het posten van gegevens naar de Xively Beek, verzoekt de apparaat-ID, indien nodig, en begint met de sluimer-timer:
server.log("Turkey Probe Agent Started."); // instantiate our Xively client xivelyClient <- Xively.Client(XIVELY_API_KEY); // in case we've just restarted the agent, but not the device, call the device for // the device ID in 1 second if it doesn't ping us with an "I just booted" message imp.wakeup(1, function() { if (config.myDeviceId == null) { device.send("needDeviceId",0); } else { prepWebpage(); }; }); // start running the auto-sleep watchdog timer checkSleepTimer();
En dat is allen daar is aan het!
Goed geluk en bon appetit :)