IMP kock: Internet-Connected BBQ termometer (7 / 7 steg)
Steg 7: En närmare titt på hur det fungerar: Agent nummer
Det första agenten gör när det startar upp är att kontrollera och se om det är precis startat och redan vet enhets-ID. När agenten måste gå och få enhets-ID från enheten, sparas det i imp molnet med server.save() så fort det blir uppdateringen. Detta sätt om agenten startar någonsin om, kan det ta ID direkt utan att ens behöva kontrollera med enheten genom att ringa server.load():
Enhets-ID används för att skapa nya kanaler i detta foder för varje ny config Turkiet sonden < br > <-server.load();
om (! (" myDeviceId"i config)) {
ta pre-bevarat enhets-ID från servern om det finns
om det inte är, vi har aldrig sett denna enhet innan (eller servern glömde - osannolikt!)
Vi kommer att begära en enhets-ID från enheten om vi göra det förbi klassdeklarationer utan
enheten gör en "Jag bara vaknade upp" incheckning.
config.myDeviceId < - null.
} < br >
Nedanför detta kör vi till en jätte funktion med en mycket stor flerradig sträng i det. Denna funktion kallas prepWebpage, och allt det gör är att sammanfoga några strängar tillsammans. Dessa strängar bara så råkar vara en webbplats. Denna webbplats är web UI för BBQ termometern, och det är vad du ser när du begär agentURL i en webbläsare. Eftersom då han har förmågan att ställa in sina egna HTTP-hanteraren, svara det på vissa önskemål genom att servera upp denna mycket lång sträng - i grund och botten agenten fungerar som en liten webbserver. Webbplatsen innehåller även några enkla javascript som körs på klientdatorn.
Efter webbplatsen har då han en funktion som håller reda på aktivitet på enheten och använder en timer och några enkla heuristik för att räkna ut om enheten ska gå för att sova för att spara batteri.
funktion checkSleepTimer() {imp.wakeup (TIMER_DEC_INTERVAL, checkSleepTimer);
Insomningstimern-= TIMER_DEC_INTERVAL;
om (insomningstimern < 0) {insomningstimern = 0};
Server.log ("Sleep Timer =" + insomningstimern);
om ((sleepTimer == 0) & & device.isconnected()) {
om (lastTemp < MAX_AUTOSLEEP_TEMP) {
TODO: om app är öppna, inte sova
Device.send("Sleep",0);
}
}
}
Detta fungerar mycket lik hälla sand i toppen av ett timglas. Om temperaturen förändras snabbt, agenten lägger till mer sand till toppen av timglaset, ger enheten mer tid för att arbeta. Om temperaturen förändringstakten saktar, agenten slutar lägga sand, timglaset rinner så småningom ut och agenten berättar enheten för att somna. Om temperaturen är över en viss tröskel, förutsätter agenten enheten är fortfarande involverad i matlagning något, och väntar på att temperaturen att sjunka igen innan du skickar den sömn ordningen.
Efter detta finns det en stor bit av koden till att arbeta med Xively. Detta är en generisk klass, och du kan lära dig mer om det, liksom andra klasser för att arbeta med andra webbtjänster, genom att ta en titt på elektriska imp webservices github sida.
Nästa, vi ser den agent som registrerar vissa händelsehanterare för händelserna från enheten, precis som vi såg i styrkod som tidigare. Mest intressant här är "temp" händelsehanteraren, som gör allt det behöver göra för att skicka nya temperaturdata till Xively och uppdatera insomningstimern:
Device.on ("temp", function(data) {lokala delta = math.abs (data.temp - lastTemp);
lastTemp = data.temp;
om (delta > MIN_CHANGE) {
bara lägga tid till timer om vi har aktivitet
om (delta > 30) {
Insomningstimern += 60.
} annat {
Insomningstimern += delta * 2;
}
}
Låt inte insomningstimern överstiga förinställda max.
om (insomningstimern > MAX_SLEEP_TIMER) {insomningstimern = MAX_SLEEP_TIMER};
lokala tempStr = format("%.1f",data.temp);
Server.log ("Temp:" + tempStr + "F");
Bokför datapoint på Xively feed
postToXively (tempStr, "temperatur");
Kontrollera om låg batterinivå frågor
Server.log ("batteri:" + data.vbat+ "V");
om (! lowBattAlarm & & (data.vbat < LOW_BATT_THRESH)) {
alarmet låg batt och skicka den till xively
Server.log ("låg batterivarning!");
lowBattAlarm = 1;
postToXively (lowBattAlarm, "lowbatt")
} else om (lowBattAlarm & & (data.vbat > LOW_BATT_THRESH)) {
Rensa låg batt larmet och skicka den till xively
lowBattAlarm = 0;
postToXively (lowBattAlarm, "lowbatt")
Server.log ("låg batterivarning rensas.");
}
});
På grund av hur denna enhet är trådbunden upp, kommer inte det faktiskt någonsin Visa låg batterinivå alarmet; Detta var för en liknande enhet som drivs av ett par AA-litiumbatterier utan en regulator mellan batterierna och den integrerade havspolitiken, så den integrerade havspolitiken kunde titta på batterispänningen direkt. Koden var kvar i ifall någon blir intrepid och bygger en inuti den ursprungliga bostad!
Nära botten av agent firmware, ser vi en av de viktigaste delarna av agent: HTTP-begäran hanteraren. Denna handler tolkar inkommande HTTP-begäranden och definierar hur agenten ska svara.
http.OnRequest (funktion (begäran, res) {< br > server.log ("Agent fick ny HTTP-begäran");
Vi måste ställa in headers och besvara tomma som de är oftast preflight-kontroller
Res.header ("Access-kontroll-tillåta-ursprung", "*");
Res.header ("Access-kontroll-tillåta-Headers","ursprung, X-efterfrågades-med, innehållstyp, acceptera");
Res.header ("Access-kontroll-tillåta-metoder", "POST, få, alternativ");
om (request.path == "/ sova" || request.path == "/ sömn /") {
Device.send("Sleep",0);
Res.send (200, "gå till sömn");
} annat {
Server.log ("Agent fick okänd begäran");
Res.send (200, webbsida);
}
});
De flesta av förfrågningarna till agenten kommer att vara bara önska på webbsidan, så att begäranden utan ytterligare parametrar får bara webbsidan som ett svar. Det finns också en "krok" här för externa tjänster att berätta för den integrerade havspolitiken för att sova, som webbsidan inte använder.
Slutligen begär agenten instansierar ett Xively klient-objekt som används under körning för att anslå data på den Xively strömmen, enhets-ID om det behövs, och börjar köra insomningstimern:
Server.log ("Turkiet sonden Agent igång.");
initiera vår Xively kund
xivelyClient <-Xively.Client(XIVELY_API_KEY);
i de fall vi har bara startas om agenten, men inte enheten, kalla enheten för
enhets-ID 1 sekund om det inte pinga oss med ett "Jag bara startat" meddelande
IMP.wakeup (1, function() {
om (config.myDeviceId == null) {device.send("needDeviceId",0);} annat {prepWebpage();};
});
börja köra auto-insomningstimern vakthund
checkSleepTimer();
Och det är allt det finns det!
Bra lycka och bon appetit :)