# LED-strip met RPi
In deze toepassing vervang je de klassieke IR-module, die bij de meeste RGB LED-strips hoort, door een raspberry pi.
De RPi wordt via een tussenschakeling verbonden met de LED-strip.
De klassieke afstandsbediening ga je vervangen door een app en door een website die je eveneens op de RPi host.
Zodra de RPi met het internet verbonden is, kan je de LED’s wereldwijd bedienen.
- Maak in de map LesCordova een nieuw project aan:
$ cordova create PIstrip be.uwnaam.pi_strip "Pi Strip" $ cd PIstrip $ cordova platform add browser android
1
2
3 - Installeer de plugin waarmee je een schudbeweging kan detecteren.
$ cordova plugin add cordova-plugin-shake
1
# PubNub
Voor de communicatie tussen de app en de RPi gebruik je PubNub. PubNub is een realtime Data Stream Network (DSN) en een realtime infrastructure-as-a-service (IaaS) voor web-, mobiele en IoT-toepassingen. Met een gratis account kan je per maand tot 100 devices connecteren en tot 1M berichten zenden/ontvangen.
- Maak een (gratis) account aan op PubNub.
- Maak een nieuwe app aan, bijvoorbeeld PI-strip.
- Open de app PI-strip en klik op CREATE NEW KEYSET.
- Geef de keyset een naam, bijvoorbeeld PIstrip.
(De publish key en subscribe key heb je straks in je eigen app nodig.)
- Open PIstrip. (Klik op FREE.)
- Enable STORAGE & PLAYBACK en bewaar de wijzigingen.
- Klik links onderaan het menu op DEBUG CONSOLE.
- Vul PIstrip in onder Channel en klik op CREATE CLIENT.
De naam van het kanaal (PIstrip) heb je straks ook in je eigen app nodig.
In de console kan je alle berichten volgen. Je kan hier ook een nieuw bericht verzenden.
Voor deze toepassing zenden we een object met als key het woord color
en als value de HEX-kleurwaarde zonder hekje.
Om de LED-strip groen te laten oplichten zend je: {"color":"00ff00"}
.
# De hardware
Wil je deze opstelling thuis bouwen, volg dan hardware tutorial.
In de les hoef je enkel de app te maken. Deze kan je dan uittesten op de LED-strip die in het labo aanwezig is.
# Inhoud van de website
- Wis de volledige inhoud van de www-folder en vervang deze door de bestanden uit dit zip-bestand.
- Bestudeer de bestanden.
# index.html
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" />
<title>Pi strip</title>
<style>
.row div {
margin-top: 20px;
}
#colorWheel {
width: 100%;
}
#lightOff {
right: calc(100vw - 79px);
}
#colorBlock {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
#colorBlock span {
display: block;
width: 20%;
text-align: center;
padding: 0;
margin: 5px;
color: grey;
border-bottom-width: 8px;
border-bottom-style: solid;
}
</style>
</head>
<body class="lime lighten-4">
<!-- Fixed navbar -->
<div class="navbar-fixed">
<nav class="lime darken-3">
<div class="nav-wrapper container">
<a href="#!" class="brand-logo center">PI strip</a>
</div>
</nav>
</div>
<!-- Fixed Action Button -->
<div class="fixed-action-btn" id="vibrate">
<a class="btn-floating btn-large waves-effect waves-light lime darken-3">
<i class="material-icons">vibration</i>
</a>
</div>
<!-- Fixed Action Button (zie nieuwe positionering in CSS! -->
<div class="fixed-action-btn" id="lightOff">
<a class="btn-floating btn-large waves-effect waves-light black">
<i class="material-icons">highlight_off</i>
</a>
</div>
<!-- Grid -->
<div class="container">
<div class="row">
<div class="col s12" id="colorBlock"></div>
<div class="col s12 input-field">
<button id="colorWheel" onchange="update(this.jscolor)" class="s12 waves-effect waves-light btn jscolor {value:'000000'}"></button>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js"></script>
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.29.5.min.js"></script>
<script src="cordova.js"></script>
<script src="js/pubnub.js"></script>
<script src="js/shake.js"></script>
<script defer src="js/app.js"></script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
- Bovenaan de pagina staat een fixed navbar.
- De fixed action button
div#vibrate
zal straks een willekeurige kleur genereren. - De tweede fixed action button
div#lightOff
dooft de LED-strip.
(Deze button wordt via CSS onderaan links in het scherm geplaatst.) - In
div#colorBlock
komen straks enkele voorgedefinieerde kleuren te staan. Deze links worden vanuit de JavaScript-code gegenereerd. - De JavaScript color picker is via de class
.jscolor
verbonden metbutton#colorWheel
.
Zodra je een kleur selecteert en buiten het kleurpalet klikt, komt hetonChange
-event in actie.
De achtergrondkleur van de button wijzigt en de tekst wordt vervangen door de gekozen HEX-waarde.
LET OP
Het jscolor-script kan je niet via jQuery coderen. Alles gebeurt volledig in "pure" JavaScript!
# js/app.js
Deze pagina is volledig klaar. Hier hoef je niets meer aan te wijzigen.
$(function () {
document.addEventListener("deviceready", onDeviceReady, false);
});
function onDeviceReady() {
console.log('Device is ready');
Shake.init();
Pubnub.init();
const colors = [
'FF0000 255,0,0,1', '00FF00 0,255,0,1', '0000FF 0,0,255,1', 'FFFFFF 255,255,255,1',
'BB0000 255,0,0,.7', '00BB00 0,255,0,.7', '0000BB 0,0,255,.7', 'BBBBBB 255,255,255,.7',
'7A0000 255,0,0,.5', '007700 0,255,0,.5', '000077 0,0,255,.5', '7A7A7A 255,255,255,.5',
'2A0000 255,0,0,.3', '002400 0,255,0,.3', '000024 0,0,255,.3', '2B2B2B 255,255,255,.3',
'050000 255,0,0,.1', '000500 0,255,0,.1', '000005 0,0,255,.1', '050505 255,255,255,.1'
];
colors.forEach(function (value, key) {
const c = value.split(' ');
$('#colorBlock').append(`
<span class="waves-effect btn lime lighten-3" data-rgb="${c[0]}" style="border-bottom-color: rgba(${c[1]})">
<i class="material-icons">lightbulb_outline</i></span>
</span>
`);
});
$('#vibrate').click(function () {
const rgb = Shake.shuffle();
Pubnub.publish(rgb);
});
$('#colorWheel').blur(function () {
const rgb = $(this).text();
Pubnub.publish(rgb);
});
$('#colorBlock').on('click', 'span', function () {
const rgb = $(this).data('rgb');
Pubnub.publish(rgb);
});
$('#lightOff').click(function () {
Pubnub.publish('000000');
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
- Lijn 10:
De arraycolors
bevat een reeks voorgedefinieerde kleuren. Elke string binnen de array bestaat uit twee delen. Voor de spatie staat de HEX-kleur die je publiceert op PubNub en na de spatie een rgba-kleur die de rand van de buttons accentueert. - Lijn 18:
Doorloop met een forEach-lus alle elementen uit de array en splits de string op een spatie. De variabelec
is terug een array en deze bevat twee elementen.
Voor de eerste string uit de vierde rij wordt dit:c[0] = 2A0000
enc[1] = 255,0,0,.3
. Genereer vervolgens voor elke kleur eenspan
-tag en verwerk hierin de twee kleuren.
Bijvoorbeeld:
<span class="..." data-rgb="2A0000" style="border-bottom-color: rgba(255,0,0,.3)">...</span>
De span-tags worden één voor één aandiv#colorBlock
toegevoegd.
Merk op dat je aan de span-tag enkel deborder-bottom-color
meegeeft.
De twee overige eigenschappen (border-bottom-width
enborder-bottom-style
) zijn voor alle buttons hetzelfde. Deze vind je terug in de CSS-code op de indexpagina. - Lijn 27:
Telkens je op#vibrate
klikt, wordt een willekeurige kleur gegenereerd en vervolgens via PubNub gepubliceerd. - Lijn 32:
Zodra je een kleur in de color picker selecteert, wordt de HEX-waarde opgevraagd en gepubliceerd. - Lijn 37:
Klik je op één van de voorgedefinieerde kleuren, lees dan de waarde vandata-rgb
uit en publiceer deze. - Lijn 42:
Je kan de LED-stript doven door de waarde voor zwart (000000
) te publiceren.
# js/shake.js
const Shake = function () {
const digit1 = [0,1,2,3,4,5,6];
const digit2 = [0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'];
const init = function() {
shake.startWatch(function() {
const rgb = shuffle();
Pubnub.publish(rgb);
},40);
};
const shuffle = function () {
return 'FF0000';
};
return {
init: init,
shuffle: shuffle
}
}();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Met de plugin cordova-plugin-shake kan je een schudbeweging detecteren.
De gevoeligheid staat ingesteld op 40. Elke gedetecteerde beweging roept de functie shuffle()
op en publiceert deze waarde op PubNub.
Voorlopig genereert shuffle()
enkel een rode kleur.
Vervang de code van
shuffle()
door:const shuffle = function () { const rgb = ''; for (i = 0; i < 3; i++) { rgb += digit1[Math.floor(Math.random() * digit1.length)]; rgb += digit2[Math.floor(Math.random() * digit2.length)]; } console.log('Random color: ', rgb); return rgb; };
1
2
3
4
5
6
7
8
9
Deze functie genereert een random HEX-waarde voor rgb.
- De laagste HEX-waarde is
000000
, de hoogte HEX-waarde isFFFFFF
. - Om al te felle kleuren te vermijden, ga je niet het volledig spectrum gebruiken, maar ga je de maximale waarde beperken tot
6F6F6F
. - Helemaal bovenaan de pagina vind je twee arrays (
digit1
endigit2
).
Binnen de for-lus ga je driemaal een willekeurige waarde uit beide arrays plukken en deze aan de stringrgb
plakken. - Hiervoor gebruik je twee wiskundige functies van JavaScript.
Math.random()
genereert een getal tussen0
en0.999...
.- Vermenigvuldig dit getal nu met de lengte van de array.
Voordigit1
geeft dit een getal tussen0
en6.999...
.
Voordigit2
geeft dit een getal tussen0
en15,999...
. - Vervolgens ga je dit getal met
Math.floor()
naar beneden afronden.
Je houdt nu nog enkel een geheel getal (0
, , ... of15
) over. - Stel dat je op getal
11
uitkomt, dan isdigit2[11]
gelijk aanB
.
# js/pubnub.js
const Pubnub = function () {
const publishKey = 'myPublishKey';
const subscribeKey = 'mySubscribeKey';
const channel = 'PIstrip';
const init = function () {
pubnub = new PubNub({
subscribeKey: subscribeKey,
publishKey: publishKey,
ssl: true
});
pubnub.addListener({
message: function (m) {
console.log('addListener: message m', m);
if (m.message.color) {
_changeColorWheel(m.message.color);
}
}
});
pubnub.subscribe({
channels: [channel]
});
pubnub.history({
channel: channel,
count: 1
},
function (status, response) {
console.log('history response', response);
const color = response.messages[0].entry.color;
_changeColorWheel(color);
}
);
};
const publish = function (rgb) {
pubnub.publish({
channel: channel,
message: {
color: rgb
}
});
};
const _changeColorWheel = function (color) {
color = color.trim();
try {
$('#colorWheel').val(color);
document.getElementById('colorWheel').jscolor.fromString(color);
}
catch (err) {
console.log('ColorWheel error', err);
}
};
return {
init: init,
publish: publish,
};
}();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
De init
-functie bevat de volledige configuratie van PubNub.
- PubNub initialisatie:
Vervang op lijn 3 en 4myPublishKey
enmySubscribeKey
door de API-keys die bij het project horen. - Lijn 14: Listeners toevoegen:
Voor onze toepassing hebben we alleen de message nodig. Het verzonden object staat inm.message
.
Haal vervolgens de kleur op (m.message.color
) en geef de waarde door naar de functie_changeColorWheel(rgb)
. - Lijn 23:
Luister naar wijzigingen op het kanaal 'PIstrip'. - Lijn 27: Geschiedenis opvragen:
Enkel bij het starten van de app wordt deze functie (lijn 31) eenmalig uitgevoerd. Uit de response halen we de laatst gekozen kleur op en sturen deze naar_changeColorWheel(rgb)
. Dit is vooral handig als meerdere personen dezelfde app gebruiken. Zo blijven alle apps volledig synchroon met elkaar.
Verder bevat het script nog twee functies.
- Lijn 39: Kleur publiceren:
De functielet publish = function (rgb)
wordt bij elke kleurwijziging opgeroepen. De functie publiceert een zeer eenvoudig object op het kanaal PIstrip.
Stel dat je bijvoorbeeld blauw selecteert, dan wordt het gepubliceerd object{"color":"0000FF"}
.
Tip: je kan alle wijzingen opvolgen in de PubNub console. - Lijn 48:
De functielet _changeColorWheel = function (color)
wijzigt de laatst gekozen kleur en de tekst inbutton#colorWheel
.
Merk op dat we viatry-catch
werken. Het kleurenpalet van jscolor bevat niet alle 16M kleurcombinaties die je met RGB kan vormen.
Stel dat je een random kleur genereert die niet in het palet voorkomt, dan krijg je op lijn 52 een fout.Catch
zal de fout dan opvangen. Werk je niet metcatch
, dan "hangt" de toepassing en zal je de app volledig moeten herstarten.
# Installeer de app
- Zet alle overbodige logs (
console.log(...)
) in commentaar. - Maak een icoon voor de app en plaats dit in de map resources.
$ cordova-res android --type icon
1 - Installeer de meteo app op je smartphone en controleer de werking.
$ cordova run android
1