Skip to content

Latest commit

 

History

History
552 lines (398 loc) · 12.4 KB

deck.mdx

File metadata and controls

552 lines (398 loc) · 12.4 KB

import { Split, Horizontal, Invert, SplitRigh, FullScreenCode} from 'mdx-deck/layouts' import { Head, Image } from 'mdx-deck/dist' import { Box, Text, Card, Flex } from 'rebass'

export { condensed as theme } from 'mdx-deck/themes'

import { library } from '@fortawesome/fontawesome-svg-core' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faRaspberryPi, faNodeJs, faGithub, faSketch, faBluetoothB, faJs } from '@fortawesome/free-brands-svg-icons' import { faRunning, faToilet, faThermometerHalf, faMobileAlt, faWifi, faUndo, faCode, faBatteryThreeQuarters, faPlus, faBed, faInfinity, faMousePointer } from '@fortawesome/free-solid-svg-icons'

Remote Sensor Monitoring and Data Distribution

or

How to Freak Out All Your CoWorkers!


eng·in·eer

a person that solves problems you did not know you had


The Problem


export default Horizontal


IoT to the Rescue


Design Challenges

Sensing

Acquisition & Presentation


Presence Sensing

  • Temperature - Infrared
  • Distance - Ultrasonics
  • Pressure - Switch on Seat
  • Machine Vision

... Taking a step back

Do we really need to measure PRESENCE

or just AVAILABILITY?


What about ...

Door Position?


What about ...

Door Position?

Lock Position!


What about ...

Door Position?

Lock Position!

Because who doesn't lock the door??


export default Invert

But in all seriousness, the lock is a rotating disc, which was super simple to measure with a tilt sensor



Source: http://blog.vidianindhita.com/2018/02/27/all-about-tilt-switches/ Source: https://learn.adafruit.com/tilt-sensor/overview


Data Acquisition and Presentation


export default Split

Arduino


Raspberry Pi



export default Horizontal

Pi Zero W

WiFi


export default Horizontal

NodeJS + Express + RPIO

HTML + CSS + JS


export default FullScreenCode

const rpio = require('rpio');
const express = require('express');
const app = express();

const STATUS_PIN = 11;

app.use(express.static('public'))

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

app.get('/stall', (req, res) => {
  const status = Boolean(rpio.read(STATUS_PIN));
  console.log(`${req.connection.remoteAddress} // Status: ${status}`);
  res.send({occupied: status});
});

rpio.open(STATUS_PIN, rpio.INPUT);

app.listen(3000, () => {
  console.log('stall-monitor is "Watching the Stall"');
}); 

Final Product



*Artist Rendering. Sadly no pictures remain of this monstrosity.
Source: http://www.se.edu/staff/cwood/2011/11/09/datacenter-remodel-complete/ ---

Design Challenges V2

Battery

Performance / Stability

Aesthetic


Battery = Low Power


export default Horizontal

(Deep) Sleep Mode

Wifi vs. Bluetooth


Power Management


Source: https://www.electronicdesign.com/embedded-revolution/sleep-sense-connect-low-power-iot-design

export default Split

Embedded Controllers

Espressif


ESP8266

ESP32


Nordic


nRF51/52

Worth Mentioning: nRF91

  ESP32 - Wifi, Bluetooth 4, Encryption, ADC/DAC, GPIO, Protocols
  nRF51/52 - Bluetooth 5, NFC, Encryption, ADC/DAC, GPIO, Protocols (SPI. I2C, I2S, UART, 2 wire, more!)
  nRF91 - Cellular!!

export default Split

Espruino

Embedded Boards that run JS!

Source: https://www.espruino.com/MDBT42Q
  • MDBT42Q (BLE)
  • Pico (Tiny)
  • Puck (BLE + Housing + Sensors)
  • Pixl (BLE + Screen)
  • Wifi
  • IDE

export default Split

System Architecture


Performance = No Polling


A BLE -> MQTT bridge for Raspberry Pi and other Embedded devices


MQTT

  • Popular IoT transport protocol
  • Bi-directional Publish-Subscribe
  • Optimized for low power, small packets, reliability
  • Channels for status, battery, previous state duration

Code Update


export default FullScreenCode

const SENSOR = D14;
var state = false;
var time = getTime();
var newTime = 0;
var options = {
  name: "Skookum Stall Monitor",
  interval:1000,
  manufacturer:0x0590
};

function setAdvertisingData(doorState, duration) {
  options.manufacturerData = JSON.stringify({
    l: doorState ? 1 : 0,
    d: Math.round(duration)
  });
    
  NRF.setAdvertising({
      0x180F : [Math.round((NRF.getBattery()-2.5)/0.8*100)]
    }, options
  );
}

// Initialization

pinMode(D14, 'input_pulldown');
NRF.setLowPowerConnection(true);
setAdvertisingData(!SENSOR.read(), 0);

// Main

setWatch(function(e) {
  if(state !== e.state) {
    newTime = getTime();

    setAdvertisingData(!e.state, newTime - time);
    
    time = newTime;
  }
  
  state = e.state;
}, SENSOR, { repeat: true, edge: 'both', debounce: 1000 });
NRF.setLowPowerConnection()
setWatch()

NRF.getBattery()

Client Update


export default FullScreenCode

const http = new XMLHttpRequest();
const url = "http://10.1.5.135:3000/stall";

function setBathroomStatus(occupied) {
  document.getElementById('toilet').style.display = 'block';
  document.getElementById('occupied').style.display = occupied ? 'block' : 'none';
  document.getElementById('vacant').style.display = occupied ? 'none' : 'block';
};

function log(msg) {
  document.getElementById('log').textContent = msg;
}
    
// Create a client instance
client = new Paho.MQTT.Client(
  location.hostname||"10.1.5.121",
  parseInt(location.port||1888),
  location.pathname.substr(0,location.pathname.lastIndexOf("/")+1),
  Math.random().toString(36).substring(7)
);

// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
log("MQTT Connecting...");

// connect the client
client.connect({onSuccess:onConnect});

// called when the client connects
function onConnect() {
log("MQTT Connected");
  client.subscribe("#"); // get everything
}

// called when the client loses its connection
function onConnectionLost(responseObject) {
  if (responseObject.errorCode !== 0) {
    document.getElementById('toilet').style.display = 'none';
    log("MQTT connection lost:"+responseObject.errorMessage);
  }
}

// called when a message arrives
function onMessageArrived(message) {
  log(""+message.destinationName+"  ->  "+JSON.stringify(message.payloadString));
  if (message.destinationName.startsWith("/ble/advertise/stall-monitor-men/l")) {
    // console.log(message.destinationName, ": ", message.payloadString);
    setBathroomStatus(message.payloadString === "1");
  }
}

export default Horizontal

3D Case Printing


Fusion 360


export default Horizontal

3D Case Printing


Makerbot Print


Be agile they said,

iterate they said


Final Product



This presentation was built with:

&