Med hjälp av sensorer, 433Mhz RF moduler och Adafruit's BLE Bluefruit chip för att samla uppgifter om Smartphone med Evothings Studio (5 / 6 steg)
Steg 5: Smartphone app
Sista delen av projektet!
Som vi börjar alltid med biblioteken behöver du. Cordova.js, evothings.js och ui.js inkluderas automatiskt när du skapar ett nytt projekt i Evothings arbetsbänken. Jquery.js biblioteken är inte obligatoriskt, du kan ändra koden så att det inte skulle behöva det, men det underlättar.
För BLE kommunikation kommer vi att använda easyble.js, som är byggd ovanpå Cordova ble plugin (com.evothings.ble, som du behöver inkludera om du vill bygga app) och det krävs också att util.js biblioteket.
För att definiera gränserna, använder vi ett reglage. Jag använde den rangeSlider.js bibliotek, nedladdningsbara här, att det ser trevligare.
< script src="cordova.js" >< / script >
< script src="libs/jquery/jquery.js" >< / script >
< script src="libs/evothings/evothings.js" >< / script >
< script src="libs/evothings/util/util.js" >< / script >
< script src="libs/evothings/ui/ui.js" >< / script >
< script src="libs/evothings/easyble/easyble.js" >< / script >
< script src="libs/rangeSlider/rangeSlider.js" >< / script >
Vi skapar sedan vissa objekt. Den första en, app, kommer att innehålla vår app funktioner och variabler. Den andra en, BluefruitUART, innehåller objektet Bluefruit när vi har hittat det efter skanningen. Objektet BLEDevice kommer att hålla viss information som behövs för att kommunicera med Bluefruit styrelse.
var app = {}; Objekt som innehar funktioner och variabler
var BluefruitUART = {}; Objektet håller BLE enheten
var BLEDevice = {}; Objektet håller Bluefruit BLE enhetsinformation
Nästa fylla vi BLEDevice objektet med information. Egenskapen name innehåller strängen som sänds av Bluefruit chip som kan användas för att identifiera den. Tjänster, writeCharacteristicUUID och readCharacteristicUUID egenskaperna innehåller UUID som är specifika för den Bluefruit chipet. Den första som används för att läsa tjänsterna från chip och få tillgång till dem, den andra att skicka data till chipet och den tredje en ta emot data.
BLEDevice.name = 'Adafruit Bluefruit LE'; Bluefruit namn
BLEDevice.services = ["6e400001-b5a3-f393-e0a9-e50e24dcca9e"]; Bluefruit tjänster UUID
BLEDevice.writeCharacteristicUUID = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'; Bluefruit writeCharacteristic UUID
BLEDevice.readCharacteristicUUID = '6e400003-b5a3-f393-e0a9-e50e24dcca9e'; Bluefruit readCharacteristic UUID
Vi fyller nu app objektet med kodens globala variabler. Egenskapen värden lagrar värdena från "modern" Arduino och meddelande sparas rådata. nbRooms innehåller det totala antalet rum och msgLength längden på meddelandet som kommer att tas emot.
app.Values = []; För att lagra mottagna värden
app.Message = ""; För att lagra mottagna data
app.nbRooms = 3; Totalt antal rum
app.msgLength = 4 * app.nbRooms + 1. Längden på meddelandet från sändaren Arduino
Den huvudsakliga funktionen kallas när enheten är klar. Händelseavlyssnare läggs till knapparna Anslut och koppla från . Den första som ansluter till Bluefruit chip, läser sina tjänster, möjliggör anmälningar och skickar sedan gränserna till "modern" Arduino.
funktionen Main () {/ / Main funktion kallas när enheten är klar
var ansluta = document.getElementById('connect');
connect.addEventListener ("klick", function()
{
connect.innerHTML = "Ansluter";
app.connectToBluefruit(function() / / Anslut till Bluefruit enheten
{
app.readServices(function() / / Läs tjänster från Bluefruit enhet
{
app.enableNotifications(app.sendLimits); Aktivera meddelanden från Bluefruit enheten och skicka lagrade gränsvärden
$('#connect').hide();
$('#disconnect').show();
connect.innerHTML = "Anslut";
}
);
}
);
}
);
var koppla = document.getElementById('disconnect');
disconnect.addEventListener ("klick", function()
{
app.Disconnect(); Koppla från Bluefruit enhet
$('#roomList').empty();
$('#disconnect').hide();
$('#connect').show();
}
);
}
När enheten är klar, anropas den huvudsakliga funktionen.
document.addEventListener ('deviceready', viktigaste, false); Vänta tills enheten vara klar innan kod körs
Vi övergår nu till funktioner. Den första, connectToBluefruit söker efter BLE enheter och stannar när den hittar en med en med rätt namn. Sedan lagrar enheten i objektet BluefruitUART och använder en av dess metoder för att ansluta till den. När anslutningen har upprättats, kräver det en annan funktion skickas som en parameter, som är readServices.
app.connectToBluefruit = function(callback) / / Anslut till Bluefruit enheten
{
evothings.easyble.startScan / / börja avsökningen
(
function(Device)
{
om (device.name == BLEDevice.name) / / om enhetens namn motsvarar Bluefruit enhetens namn
{
evothings.easyble.stopScan(); Stoppa sökningen
BluefruitUART = enhet; Store Bluefruit enheten
Console.log ("Adafruit Bluefruit LE UART hittade!');
BluefruitUART.connect / / Anslut till Bluefruit enheten
(
function(Device)
{
Console.log ("Ansluten till BLE enhet" + BluefruitUART.name);
callback();
},
function(ErrorCode)
{
Console.log ("kunde inte ansluta till BLE enhet:" + errorCode);
}
)
}
},
function(errorString)
{
Console.log ("fel vid skanning:" + errorString);
}
);
};
Funktionen koppla använder metoden nära i BluefruitUART objekt för att koppla från Bluefruit enheten.
app.Disconnect = function() / / koppla från Bluefruit enhet
{
BluefruitUART.close();
Console.log ("Bortkopplad från BLE enhet" + BluefruitUART.name);
};
Funktionen readServices läser tjänsterna från BLE enheten när anslutningen har upprättats. Det använder tjänster UUID vi angett tidigare.
app.readServices = function(callback) / / Läs tjänster från Bluefruit enhet
{
BluefruitUART.readServices
(
BLEDevice.services,
function(Device)
{
Console.log ("BLE tjänster tillgängliga för enheten" + BluefruitUART.name);
callback();
},
function(errorString)
{
Console.log ('BLE tjänster fel: "+ errorString);
}
)
};
SendMessage funktionen skickar data till Bluefruit chip. Det använder writeCharacteristic UUID vi angett tidigare.
app.sendMessage = function(message) / / Skicka ett meddelande till Bluefruit enhet
{
var data = evothings.ble.toUtf8(message);
BluefruitUART.writeCharacteristic
(
BLEDevice.writeCharacteristicUUID,
data,
function()
{
Console.log ("skickat:" + meddelande);
},
function(errorString)
{
Console.log ('BLE writeCharacteristic fel: "+ errorString);
}
)
};
Funktionen enableNotifications används för att ta emot data från Bluefruit chip till Smartphone. Det första du kan göra är att skriva deskriptorn för att aktivera meddelanden när den ändras. Metoden writeDescriptor för objektet BluefruitUART tar flera parametrar. Den första är den readCharacteristicUUID som vi har angett tidigare. Den andra är deskriptor UUID, vilket är samma för varje BLE enhet. Den tredje är behållare för de data som ska läsas från Bluefruit chip.
När deskriptorn är skriven, behöver vi aktiverar de anmälningar som anropar en funktion varje gång data läsa från förändringarna som deskriptor. Detta görs med hjälp av metoden enableNotification för objektet BluefruitUART , som måste readCharacteristicUUID. Då kommer den funktion som anropas när data ändras. Det tolkar budskapet och sparar värdena. Tolkning kan tyckas lite knepigt och komplex, men jag ville vidta försiktighetsåtgärder för att se till att inga data går förlorade.
När värdena sparas, anropas funktionen fillRoomList , som anropar funktionen setupSlider som vi kommer att täcka nästa.
app.enableNotifications = function() / / Aktivera meddelanden för Bluefruit enhet
{
BluefruitUART.writeDescriptor / / Skriv beskrivningen av Bluefruit enhet
(
BLEDevice.readCharacteristicUUID,
"00002902-0000-1000-8000-00805f9b34fb', / / samma för varje BLE enhet
nya Uint8Array([1]),
function()
{
Console.log ('BLE deskriptor skriven.");
},
function(errorString)
{
Console.log ('BLE writeDescriptor fel: "+ errorString);
}
);
BluefruitUART.enableNotification / / Aktivera meddelanden för Bluefruit enhet
(
BLEDevice.readCharacteristicUUID,
function(data)
{
var meddelande = evothings.ble.fromUtf8(data); Meddelande från sändaren Arduino
/*
Denna del behandlar tolkning av det mottagna meddelandet (meddelande). Det kommer då att lagras i (app.message).
Beroende på sättet Bluetooth fungerar, kommer ibland att skicka meddelandet i två delar, därför skrev jag en kod som
kommer att sammanfoga de två delarna om det händer.
*/
Om för något skäl det lagrade meddelandet är längre än max längd (app.msgLength), töm den
om (app.message.length > app.msgLength)
{
app.Message = "";
}
Om både meddelandet och det lagrade meddelandet är kortare än väntat
om (app.message.length < app.msgLength & & message.length < app.msgLength)
{
/*
Om meddelandet innehåller en '#' (message.indexOf('#')! = -1), det innebär att det är den första delen
av meddelandet, så lagras meddelandet måste vara tom (app.message.length == 0).
Om meddelandet innehåller en "*" (message.indexOf('*')! = -1), det innebär att det är den andra delen
av meddelandet, så lagras meddelandet kan inte tömma (app.message.length > 0).
*/
om ((message.indexOf('#')! = -1 & & app.message.length == 0) || (message.indexOf('*')! = -1 & & app.message.length > 0))
{
app.Message = app.message.concat (meddelande); Sammanfoga det mottagna meddelandet till lagrade meddelande
}
}
/*
Om det mottagna meddelandet är lika långt som den borde vara (message.length == app.msgLength), det börjar med ett "#"
(message.indexOf('#') == 0) och slutar med en "*" (message.indexOf('*') == app.msgLength - 1), då är det
komplett och kan lagras i (app.message)
*/
annat if (message.length == app.msgLength & & message.indexOf('#') == 0 & & message.indexOf('*') == app.msgLength - 1)
{
app.Message = meddelande;
}
/*
Om det lagrade meddelandet är så länge som det ska vara (app.message.length == app.msgLength), det börjar med ett "#"
(app.message.indexOf ("#") == 0) och slutar med en "*" (app.message.indexOf('*') == app.msgLength - 1),
då är det fullständig
*/
om (app.message.length == app.msgLength & & app.message.indexOf ('#') == 0 & & app.message.indexOf('*') == app.msgLength - 1)
{
var slut = app.message.indexOf('*'); Få ställning som den sista röding
Skapa en array (split("/")) från meddelandet och lagra värdena i (app.values)
app.Values = app.message.substring (1, end).split("/");
app.Message = ""; Töm meddelandet
console.log('--------------------------------------');
Console.log ("Data för rum:");
för (var jag = 0; jag < app.values.length; i ++)
{
app.Values[i] = parseInt(app.values[i]); Konvertera värden från sträng till int
Console.log ("*" i "är" + + app.values[i]);
}
}
app.fillRoomList(app.setupSlider); Fyll i listan med värden som har lagrats och sedan konfigurera reglaget
},
function(errorString)
{
Console.log ('BLE enableNotification fel: "+ errorString);
}
);
Funktionen setupSlider konfigurerar reglagen. När en skjutreglaget flyttas, gränsen ändras och lagras i localStorage av funktionen utlöses av händelsen onSlide . Gränserna som sedan skickas till "modern" Arduino med funktionen sendLimits .
app.setupSlider = function() / / Skjut bar konfiguration
{
var reglaget = document.querySelectorAll('input[type="range"]');
rangeSlider.create (reglaget {
POLYfill: sant, / / boolesk, om sant, anpassade markup skapas
rangeClass: 'rangeSlider',
disabledClass: "rangeSlider--inaktiverat",
fillClass: 'rangeSlider__fill',
bufferClass: 'rangeSlider__buffer',
handleClass: 'rangeSlider__handle',
startEvent: ["mousedown', 'touchstart', 'pointerdown'],
moveEvent: ["mousemove', 'touchmove', 'pointermove'],
endEvent: ["mouseup', 'touchend', 'pointerup'],
min: null, / / antal, 0
Max: null, / / antal, 100
steg: null, / / antal, 1
värde: null, / / antal, centrera av slider
buffert: null, / / antal, i procent, 0 som standard
borderRadius: 10, / / nummer, om du använder buffert + border-radius i css för ser bra,
onInit: funktion () {
Console.info('onInit')
},
onSlideStart: funktion (position, värde) {
},
onSlide: funktionen (position) {/ / när skjutreglaget flyttas
för (var jag = 0; jag < app.values.length; i ++)
{
var slideBarValue = document.getElementById("slideBar" + i).value;
om (slideBarValue == position) / / om värdet motsvarar positionen för en av slideBars
{
localStorage.setItem ('begränsa' + i, position); Store nya gräns
}
}
app.sendLimits(); Skicka gränser till sändaren Arduino (för att lysa upp lamporna)
},
onSlideEnd: funktion (position, värde) {
}
});
};
Som ni nog minns, anropas funktionen fillRoomList när data har blivit analyserad från meddelandet som mottogs från "modern" Arduino. Det visar statusen för ljuset och ett skjutreglage för varje rum. Ett HTML-element skapas och läggs till i listan roomList .
Observera att reglaget värdet utgör gränsen och bufferten värdet läsa av sensorn. Bufferten är uttryckt i procent, därav uppdelningen av 10.
app.fillRoomList = function(callback) / / Fyll i listan
{
var roomList = $('#roomList');
roomList.empty(); Töm listan
om (app.values.length) / / om det finns några värden
{
för (var jag = 0; jag < app.values.length; i ++) / / för varje rum
{
om (localStorage.getItem ("begränsa" + i) === null) / / om gränsen inte ställts in ännu, satt till 100 (lägsta)
{
localStorage.setItem ('begränsa' + i, 100);
}
var gränsen = localStorage.getItem ('begränsa' + i); Gräns för rummet
var staten. Tillstånd av ljuset
om (app.values[i] > gräns)
{
State = "på";
}
annat
{
State = "off";
}
var elementet = $(/ / Element som ska läggas till i listan
"< li >"
+ "< h1 > rum" + i + "< / h1 >< br >"
+ "Ljus är < stark >" + statligt + "< / strong >"
+ "< div class ="slideBar">"
+ "Skjut bar för att ändra gränsen < br >< br >"
+ ''
+ "< br >"
+ "< / div >"
+ ''
+ "< br >"
);
roomList.append(element); Lägg till elementet
}
}
callback(); Konfigurera skjutreglaget när alla element läggs till i listan
};
Funktionen sendLimits skapar ett meddelande som börjar med en #, som innehåller de gränser som skiljs åt av en / och slutar med ett * och skickar det till "modern" Arduino.
app.sendLimits = function() / / skicka gränserna till sändaren Arduino
{
var meddelande = "#"; Börja meddelandet med ett "#"
för (var jag = 0; jag < app.values.length; i ++)
{
meddelande = message.concat (localStorage.getItem ('limit' + i));
om (jag < app.values.length - 1)
{
meddelande = message.concat('/'); Avgränsar du värdena med ett '/'
}
}
meddelande = message.concat('*'); Avslutar meddelandet med en "*"
app.sendMessage(message); Skicka meddelandet
}
};