Monsters, mailboxes and other nonsense

A presentation at IndieWebCamp in May 2017 in Düsseldorf, Germany by Niels Leenheer

Slide 1

Slide 1

monsters, mailboxes and other non-sense

Slide 2

Slide 2

a new home

Slide 3

Slide 3

Slide 4

Slide 4

Slide 5

Slide 5

10 meter

Slide 6

Slide 6

the house of the future

Slide 7

Slide 7

Slide 8

Slide 8

Slide 9

Slide 9

433MHz

Slide 10

Slide 10

Slide 11

Slide 11

Slide 12

Slide 12

Slide 13

Slide 13

Slide 14

Slide 14

IoT is actually incredibly boring

Slide 15

Slide 15

Slide 16

Slide 16

raspberry pi with domoticz

Slide 17

Slide 17

Slide 18

Slide 18

Slide 19

Slide 19

chicken thermostat

Slide 20

Slide 20

brrrr!

Slide 21

Slide 21

kippenwaterdrinkbak (chicken water trough)

Slide 22

Slide 22

kippenwaterdrinkbakverwarmingselement (chicken water trough heater)

Slide 23

Slide 23

kippenwaterdrinkbakverwarmingselementschakelaar (chicken water trough heater switch)

Slide 24

Slide 24

kippenwaterdrinkbakverwarmingselementschakelaarthermometer (chicken water trough heater switch thermometer)

Slide 25

Slide 25

Slide 26

Slide 26

rfxcom

Slide 27

Slide 27

every 30 seconds a “ping” with the temperature

Slide 28

Slide 28

temperature below zero, turn on the heater

Slide 29

Slide 29

turn klikaanklikuit switch on

Slide 30

Slide 30

Slide 31

Slide 31

The “S” in IoT stands for security

Slide 32

Slide 32

Slide 33

Slide 33

the fiery witches kettle

Slide 34

Slide 34

Do-it-yourself IoT

Slide 35

Slide 35

brains (or microcontrollers)

Slide 36

Slide 36

Arduino Uno ATmega238 16 Mhz 2 KB RAM 32 KB Flash

Slide 37

Slide 37

ESP-01 ESP 8266 80 Mhz 128 KB RAM 512 KB Flash

Slide 38

Slide 38

NodeMCU ESP 8266 80 Mhz 128 KB RAM 4 MB Flash

Slide 39

Slide 39

NodeMCU

Slide 40

Slide 40

Neopixel 24 serial connected WS2812 RGB LEDs

Slide 41

Slide 41

#include <Adafruit_NeoPixel.h> #define PIN #define PIXELS D1 24 Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS, PIN, NEO_GRB + NEO_KHZ800); void setup(void) { strip.begin(); strip.setBrightness(255); strip.setPixelColor(0, strip.Color(0, 0, 255)); strip.show(); } void loop(void) { }

Slide 42

Slide 42

int i = 0; void setup(void) { strip.begin(); strip.setBrightness(255); } void loop(void) { i = (i + 1) % PIXELS; strip.setPixelColor(i % PIXELS, strip.Color(0, 0, 0)); strip.setPixelColor((i + 1) % PIXELS, strip.Color(0, 0, strip.setPixelColor((i + 2) % PIXELS, strip.Color(0, 0, strip.setPixelColor((i + 3) % PIXELS, strip.Color(0, 0, strip.setPixelColor((i + 4) % PIXELS, strip.Color(0, 0, strip.show(); delay(8); } 63)); 127)); 195)); 255));

Slide 43

Slide 43

?! JavaScript? And C? Kinda the same. Just about. Not quite. No.

Slide 44

Slide 44

IKEA SOMMAR 2017 lantern

Slide 45

Slide 45

Slide 46

Slide 46

Slide 47

Slide 47

Slide 48

Slide 48

Slide 49

Slide 49

WiFi must be very complicated…

Slide 50

Slide 50

const char* ssid = "........"; const char* password = "........"; ESP8266WebServer server(80); void setup(void) { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) delay(500); server.on("/on", { server.send(200, "text/plain", "on"); }); server.on("/off", { server.send(200, "text/plain", "off"); }); server.begin(); } void loop(void) { server.handleClient(); }

Slide 51

Slide 51

http://sparkle.local/api?command=power&status command=power&on command=power&off command=brightness&status command=brightness&set=50 command=color&status command=color&set=f34d0d

Slide 52

Slide 52

homebridge homebridge-better-http-rgb

Slide 53

Slide 53

siri

Slide 54

Slide 54

siri

Slide 55

Slide 55

pixel monsters

Slide 56

Slide 56

Prolight 12W ceiling lamp

Slide 57

Slide 57

Slide 58

Slide 58

Neopixel 64 serial connected WS2812 RGB LEDs

Slide 59

Slide 59

Slide 60

Slide 60

SD card Storage of monsters Lightsensitive resistor Night-mode Buzzer Beeps for notifications

Slide 61

Slide 61

Slide 62

Slide 62

Slide 63

Slide 63

Slide 64

Slide 64

Slide 65

Slide 65

progressive web app

Slide 66

Slide 66

http://pixel.local

Slide 67

Slide 67

http://pixel.local

Slide 68

Slide 68

Slide 69

Slide 69

editor.addEventListener('touchstart', handleTouch); editor.addEventListener('touchmove', handleTouch); function handleTouch(e) { for (var i = 0; i < e.changedTouches.length; i++) { let elem = document.elementFromPoint( e.changedTouches[i].pageX, e.changedTouches[i].pageY ); if (elem.tagName && elem.tagName == 'TD' && editor.contains(elem)) { drawPixel(elem); } } e.preventDefault(); }

Slide 70

Slide 70

editor.addEventListener('touchstart', handleTouch); editor.addEventListener('touchmove', handleTouch); function handleTouch(e) { for (var i = 0; i < e.changedTouches.length; i++) { let elem = document.elementFromPoint( e.changedTouches[i].pageX, e.changedTouches[i].pageY ); if (elem.tagName && elem.tagName == 'TD' && editor.contains(elem)) { drawPixel(elem); } } e.preventDefault(); }

Slide 71

Slide 71

let socket = new WebSocket( "ws://" + window.location.host + "/ws" ); function drawPixel(elem) { if (elem.dataset.color != currentColor) { elem.dataset.color = currentColor; elem.style.backgroundColor = '#' + currentColor; socket.send(JSON.stringify({ command: "draw", x: elem.dataset.x, y: elem.dataset.y, color: currentColor })); } }

Slide 72

Slide 72

let socket = new WebSocket( "ws://" + window.location.host + "/ws" ); function drawPixel(elem) { if (elem.dataset.color != currentColor) { elem.dataset.color = currentColor; elem.style.backgroundColor = '#' + currentColor; socket.send(JSON.stringify({ command: "draw", x: elem.dataset.x, y: elem.dataset.y, color: currentColor })); } }

Slide 73

Slide 73

{ "command": "draw", "x": 5, "y": 5, "color": "ffffff" }

Slide 74

Slide 74

{ "command": "draw", "x": 5, "y": 5, "color": "ffffff" }

Slide 75

Slide 75

Slide 76

Slide 76

Slide 77

Slide 77

Slide 78

Slide 78

socket.onmessage = function(msg) { let data = JSON.parse(msg.data); if (data.command == "draw") { let elem = document.querySelector( 'td[data-x=' + data.x + ']' + '[data-y=' + data.y + ']' ); elem.dataset.color = data.color; elem.style.backgroundColor = '#' + data.color }; } }

Slide 79

Slide 79

socket.onmessage = function(msg) { let data = JSON.parse(msg.data); if (data.command == "draw") { let elem = document.querySelector( 'td[data-x=' + data.x + ']' + '[data-y=' + data.y + ']' ); elem.dataset.color = data.color; elem.style.backgroundColor = '#' + data.color }; } }

Slide 80

Slide 80

demo

Slide 81

Slide 81

the mystery of the haunted mailbox

Slide 82

Slide 82

mail box

Slide 83

Slide 83

magnetic contact

Slide 84

Slide 84

when the mailbox opens it sends a signal

Slide 85

Slide 85

http://pixel.local/api?command=notify&icon=mailbox

Slide 86

Slide 86

Slide 87

Slide 87

Slide 88

Slide 88

Slide 89

Slide 89

combine the magnetic contact with a motion sensor? solution #1

Slide 90

Slide 90

turn off the magnetic contact with strong westerly winds? solution #2

Slide 91

Slide 91

solution #3

Slide 92

Slide 92

the fickle washing machine

Slide 93

Slide 93

Slide 94

Slide 94

Slide 95

Slide 95

Start program 24,9 watt Washing machine off 0,3 watt Standby usage 4,6 watt

Slide 96

Slide 96

Slide 97

Slide 97

Laundry is done

Slide 98

Slide 98

Laundry is done Laundry is done Laundry is done Laundry is done

Slide 99

Slide 99

Slide 100

Slide 100

2000 watt

Slide 101

Slide 101

20 - 200 watt

Slide 102

Slide 102

2 - 5 watt

Slide 103

Slide 103

Laundry is done Laundry is done Laundry is done Laundry is done

Slide 104

Slide 104

Slide 105

Slide 105

commandArray = {} if (uservariables['WasmachineBezig'] == 2) then s = uservariables_lastupdate['WasmachineBezig'] lastUpdate = os.time{ year=string.sub(s, 1, 4), month=string.sub(s, 6, 7), day=string.sub(s, 9, 10), hour=string.sub(s, 12, 13), min=string.sub(s, 15, 16), sec=string.sub(s, 18, 19) } difference = os.difftime (os.time(), lastUpdate) if (difference > 300) then commandArray['Variable:WasmachineBezig'] = '0' commandArray['OpenURL'] = 'pixel.local/api?command=notify&icon=shirt' end end return commandArray

Slide 106

Slide 106

Laundry is done

Slide 107

Slide 107

Slide 108

Slide 108

Slide 109

Slide 109

questions?