IoT for Beginners
Connecting the virtual world with the physical world
Show & Tell


https://github.com/Zefiro
Think about the possibilities
Phyiscal
LED Strip
Virtual
Bit Pulse Signal
Raspberry PI
Node JS Server
Device
Front-end
Physical Side
What do we need?

ws2811/ws2812




Title Text


https://sigrok.org/wiki/VKTECH_saleae_clone




Raspberry PI 3
Arduino
Shopping List
5m Ledstrip | ~30 € |
Logic Analyzer | ~10 € |
Raspberry Pi | ~35 € |
Soldering material | ~5 € |
LED Power supply | ~5 € |
85 € |
Where to start?







https://webofthings.org
https://element14.com

Data
Virtual Side
Client
Server
LED Strip
HTTP
Websocket
GPIO
The Server

https://github.com/jgarff/rpi_ws281x
function set(pixels = {r: 0, g: 0, b: 0}, rgborder = 'rgb') {
this.currentPixels = pixels
const order = rgborder.split('')
const pixels = pixels
.map(pixel => util.rgb2Int(pixel[order[0]], pixel[order[1]], pixel[order[2]]))
const pixelInts = new Uint32Array(pixels)
ws281x.render(pixelInts)
}


function render(canvas) {
let deltaT = new Date() - this._startTime
let slowDeltaT = deltaT / 200
let transition = slowDeltaT % 100
let transitionJump = slowDeltaT - transition
if (transitionJump != self.anim.lastTransitionJump) {
self.anim.lastTransitionJump = transitionJump
for (var i = 0; i < this.numLeds; i++) {
this.pixels[1][i].counter = this.pixels[0][i].counter
}
this.pixels[0] = this.pixels[1]
this.pixels[1] = createAllPixels(self.layout.fxLength)
}
for (var i = 0; i < self.layout.fxLength; i++) {
// TODO this still relies on calling-frequency instead of Date()
this.pixels[0][i].counter +=
(Math.random() + 0.5)
* util.map(this.pixels[0][i].speed, this.pixels[1][i].speed, transition)
if (this.pixels[0][i].counter > 200) this.pixels[0][i].counter = 0
var variants =
this.pixels[0][i].counter > 100
? 200 - this.pixels[0][i].counter
: this.pixels[0][i].counter
var maxTemp = util.map(this.pixels[0][i].maxTemp, this.pixels[1][i].maxTemp, transition)
var minTemp = util.map(this.pixels[0][i].minTemp, this.pixels[1][i].minTemp, transition)
var temp = util.map(maxTemp, minTemp, variants)
if (this.type == 'linear') {
temp = (255 * (i + self.layout.fxStart)) / (self.layout.fxSize - 1)
}
temp = Math.max(0, Math.min(Math.floor(temp), 255))
let targetIdx = this.layout.canvasStart + (this.layout.reverse
? self.layout.fxLength - i - 1
: i)
canvas[targetIdx] = temperatureColorMap[temp]
}
return canvas
}
We used to hardcode effects
We can level up
Frame
Step
Scene
How would the data look like?
[
{
duration: 1,
pixels: [
{r: 0, g: 255, b: 0},
{r: 0, g: 255, b: 0},
{r: 0, g: 255, b: 0},
{r: 0, g: 255, b: 0},
{r: 0, g: 255, b: 0},
]
},
{
duration: 1,
pixels: [
{r: 255, g: 255, b: 0},
{r: 255, g: 255, b: 0},
{r: 255, g: 255, b: 0},
{r: 255, g: 255, b: 0},
{r: 255, g: 255, b: 0},
]
},
]
import { ledstrip } from '../index'
import Pixel from './pixel'
export default class Step {
constructor(pixels = [], options = {}) {
this.pixels = pixels
this.duration = parseFloat(options.duration) || 1
this.fps = 50
this.frame = 0
}
async tween(nextStep) {
const frames = this.getFrames()
for (let frame of frames) {
// for 1 second - this is 1/60 of a second
await new Promise(resolve => setTimeout(resolve, 1000 / this.fps))
this.frame = frame.index
let pixels = this.pixels.map((pixel, index) => {
let next = nextStep.pixels[index]
if (!next || !pixel) {
return new Pixel()
}
// mapColor fades between two colors based on percentage
return pixel.mapColor(next, frame.percent)
})
ledstrip.set(pixels)
}
}
* getFrames() {
const frameLength = this.fps * this.duration
yield* Array.from(new Array(frameLength)).map((v, index) => {
index += 1
return {
index,
percent: 100 / frameLength * index,
}
})
}
}
import http from 'http'
import Pixels from './classes/pixels'
import io from 'socket.io'
export const ledstrip = new Pixels({
size: 50,
rgborder: 'gbr',
ledstrip: {
invert: 0,
frequency: 400000,
}
})
process.on('SIGINT', () => {
ledstrip.reset()
process.nextTick(() => { process.exit(0) })
})
const socketServer = http.createServer()
const socketIo = io(socketServer)
socketIo.on('connection', function(socket) {
socket.emit('current', JSON.stringify(ledstrip.get()))
socket.on('setPixels', data => {
ledstrip.set(JSON.parse(data))
})
})
socketServer.listen(3000)
The Client

Ingredients
- Color Picker
- Effect buttons
- Add/Remove/Copy buttons
- Pixels
- Some rendering mechanism (I use Vue)
- SocketIO Client
methods: {
isPixelActiveClass(pixel, index) {
return {
'pixel--selected': this.selectedPixelIndexes.includes(index)
}
},
getPixelColor(pixel) {
return { backgroundColor: `rgb(${pixel.r}, ${pixel.g}, ${pixel.b})` }
},
setActivePixel(event, index) {
const pixel = this.pixels.get(index)
this.selectedPixel = pixel
if (!event.shiftKey) {
this.selectedPixelIndexes = [index]
} else {
const startIndex = this.selectedPixelIndexes[0]
const selectionLength = (startIndex > index ? startIndex - index : index - startIndex) + 1
const directionUp = startIndex > index
this.selectedPixelIndexes = [
...this.selectedPixelIndexes[0],
...Array.from(Array(selectionLength)).map((element, selectIndex) => index + (directionUp ? selectIndex : -selectIndex))
]
}
this.color = {
rgba: {
r: pixel.r,
g: pixel.g,
b: pixel.b,
a: 1
}
}
},
}

Client
Server
LED Strip
HTTP
Websocket
GPIO
Thank you!

https://wireupyourfrontend.com
https://gps-stuttgart.de/

https://github.com/MartinMuzatko/ledstrip-animator/
Code
Questions?
IoT for Beginners
By Martin Muzatko
IoT for Beginners
- 343