Things used in this project

Hardware components:
Odroid C1
×1
Adafruit PN532 NFC/RFID controller breakout board
×1
Adafruit 13.56MHz RFID/NFC Bracelet
×2
Adafruit TSL2561 Digital Luminosity/Lux/Light Sensor Breakout
×1
13285 01
PIR Motion Sensor (generic)
×1
SparkFun Sound Detector
×1
Pressure Mat PM1
×1
Software apps and online services:
Ha 2up iot
Amazon Web Services AWS IoT
Screen%20shot%202015 07 20%20at%206.11.48%20pm
Amazon Web Services AWS DynamoDB
Screen%20shot%202015 07 20%20at%206.10.26%20pm
Amazon Web Services AWS Lambda
Iam logo
Amazon Web Services AWS IAM
Rm web services amazon s3
Amazon Web Services AWS S3

Schematics

Baby NAP fritzing Schematic
Updated - babynap.fzz
Baby NAP fritzing Schematic - Image

No document.

Code

Python Script to Upload Sensor DataPython
#!/usr/bin/python
import paho.mqtt.client  as mqtt
import paho.mqtt.publish as publish
import time,json,ssl
import wiringpi2 as wpi
from tentacle_pi.TSL2561 import TSL2561
import nfc, sys, threading

def on_connect(mqttc, obj, flags, rc):
    if rc == 0:
        print "Connected to the AWS IoT service!"
    else :
        print("Error connecting to AWS IoT service! (Error code " + str(rc) + ": " + RESULT_CODES[rc] + ")")
        client.disconnect()

#Connect to AWS IoT
client = mqtt.Client(client_id="odroid-c1", protocol=mqtt.MQTTv311)
client.on_connect = on_connect
client.tls_set("certs/root-CA.crt", certfile="certs/certificate.pem.crt", keyfile="certs/private.pem.key", tls_version=ssl.PROTOCOL_SSLv23, ciphers=None)
client.tls_insecure_set(True)
client.connect("A32L40P6IYKK8W.iot.us-east-1.amazonaws.com", 8883, 60)
client.loop_start()

# GPIO pin setup
wpi.wiringPiSetup()
wpi.pinMode(2, 0) # PIR sensor on wpi GPIO2
wpi.pinMode(3, 0) # mat pressure sensor on wpi GPIO3
wpi.pinMode(21, 0) # sound sensor GATE on wpi GPIO21

# I2C TSL2561 setup
tsl = TSL2561(0x39,"/dev/i2c-1")
tsl.enable_autogain()
tsl.set_time(0x00)

# nfc functions
def connected(tag):
    global nfcid
    nfcid = str(tag)[12:]
    print "read successful"
    time.sleep(3)
    return False

def reader():
    while True:
        # we do a read every 5s
        timeout = lambda: time.time() - started > 5
        started = time.time()
        device = nfc.ContactlessFrontend('tty:S2:pn532')
        device.connect(rdwr={'on-connect': connected}, terminate=timeout)
        device.close()
        

nfcid = 0
thread = threading.Thread(target=reader)
thread.start()
# end nfc setup

count = 0
mlux = mpir = mmat = msound = mvolume = 0

while True:
    time.sleep(3)
    # read sensor data
    ts = int(time.time())
    lux = tsl.lux()
    pir = wpi.digitalRead(2)
    mat = wpi.digitalRead(3)
    sound = wpi.digitalRead(21)
    volume = wpi.analogRead(0)*255/2047 # 0-10=quiet, 10-30=moderate, 30-127=loud

    mom = 0
    dad = 0
    if mat == 0:
        if nfcid == 'F10B330F':
            mom = 1
        elif nfcid == '833BC4A2':
            dad = 1

    if lux > mlux:
        mlux = lux
    if pir > mpir:
        mpir = pir
    if mat < mmat:
        mmat = mat
    if sound > msound:
        msound = sound
    if volume > mvolume:
        mvolume = volume

    # send data to AWS
    if count == 0:
        msg = {'ts': ts, 'lux': mlux, 'pir': mpir, 'mat': mmat, 'sound': msound, 'volume': mvolume, 'mom': mom, 'dad': dad}
        print json.dumps(msg)
        client.publish('sensors', json.dumps(msg))
        mlux = mpir = mmat = msound = mvolume = 0
        if mmat == 1:
            nfcid = 0
thread = threading.Thread(target=reader)
thread.start()
# end nfc setup

count = 0
mlux = mpir = mmat = msound = mvolume = 0

while True:
    time.sleep(3)
    # read sensor data
    ts = int(time.time())
    lux = tsl.lux()
    pir = wpi.digitalRead(2)
    mat = wpi.digitalRead(3)
    sound = wpi.digitalRead(21)
    volume = wpi.analogRead(0)*255/2047 # 0-10=quiet, 10-30=moderate, 30-127=loud

    mom = 0
    dad = 0
    if mat == 0:
        if nfcid == 'F10B330F':
            mom = 1
        elif nfcid == '833BC4A2':
            dad = 1

    if lux > mlux:
        mlux = lux
    if pir > mpir:
        mpir = pir
    if mat < mmat:
        mmat = mat
    if sound > msound:
        msound = sound
    if volume > mvolume:
        mvolume = volume

    # send data to AWS
    if count == 0:
        msg = {'ts': ts, 'lux': mlux, 'pir': mpir, 'mat': mmat, 'sound': msound, 'volume': mvolume, 'mom': mom, 'dad': dad}
        print json.dumps(msg)
        client.publish('sensors', json.dumps(msg))
        mlux = mpir = mmat = msound = mvolume = 0
        if mmat == 1:
            nfcid = 0
    count = (count + 1) % 20
index.html to build chartsHTML
<!DOCTYPE html>
<html>

<head>
  <title>Baby Night Activity Monitor</title>
  <link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
  <script src="https://code.highcharts.com/stock/highstock.js"></script>
  <script src="https://sdk.amazonaws.com/js/aws-sdk-2.2.33.min.js"></script>
</head>

<body style="font-family: 'Lato', sans-serif;">
<center>
  
  <br/>
  <h1>Baby Night Activity Monitor</h1>
  <br/>
  <!-- initial screen with login -->
  <div id="splash">
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Child_in_crib_being_supervised_clip_art.svg/253px-Child_in_crib_being_supervised_clip_art.svg.png" width="253" height="240"></img>
    <br/><br/><br/>
    <div style="display:flex; align-items:center; justify-content: center;">
      You need to &nbsp;
      <a href="#" id="login">
        <img border="0" alt="Login with Amazon" src="https://images-na.ssl-images-amazon.com/images/G/01/lwa/btnLWA_drkgry_156x32.png" width="156" height="32" />
      </a>
      &nbsp; to access this application.
    </div>
    <br/><br/>
  </div>

  <!-- amazon login element -->
  <div id="amazon-root"></div>

  <!-- containers for charts -->
  <div id="main" style="display: none;">
    <div id="sound1" style="height: 398px; min-width: 600px; max-width: 960px;"></div><br/>
    <div id="mat1" style="height: 300px; min-width: 600px; max-width: 960px;"></div><br/>
    <div id="light1" style="height: 300px; min-width: 600px; max-width:   960px;"></div><br/>
    <div id="pir1" style="height: 300px; min-width: 600px; max-width: 960px;"></div><br/>
 </div>
  <!-- Javascript application -->
  <script type="text/javascript">
    // AWS credentials
    var clientId = 'amzn1.application-oa2-client.7b4ede4c6f32478d8dced3fa29ba7c30';
    var roleArn = 'arn:aws:iam::906035442422:role/aws_web_dynamoDB';
  
    // Highcharts theme defaults
    var chartTheme = {
      global: { useUTC: true },
      credits: { enabled: false },
      tooltip: { useHTML: true },
      chart: { zoomType: null, panning: false, alignTicks: true, backgroundColor: 'white', plotBackgroundColor: 'white', ignoreHiddenSeries: true, borderRadius: 0, borderWidth: 1, borderColor: 'black', spacingRight: 20, plotBorderWidth: 1, plotBorderColor: 'grey' },
      title: { style: { color: 'black', font: 'bold 14px "Trebuchet MS", Verdana, sans-serif', textTransform: 'capitalize'}, floating: false },
      xAxis: { title: { style: { color: '#333', font: '12px "Trebuchet MS", Verdana, sans-serif'} }, lineWidth: 0, lineColor: 'grey', gridLineWidth: 1, gridLineColor: '#ffb2b2', gridLineDashStyle: 'ShortDot', ordinal: false, labels: { overflow: 'justify' }, startOnTick: false, endOnTick: false
      },
      yAxis: { title: { style: { color: '#333', font: '12px "Trebuchet MS", Verdana, sans-serif'} }, lineWidth: 0, lineColor: 'grey', tickPixelInterval: 36, minorTickPixelInterval: 36, gridLineColor: '#ffb2b2', gridLineDashStyle: 'ShortDot', labels: { overflow: 'justify' }, startOnTick: true, endOnTick: true },
      legend: { enabled: true, backgroundColor: 'white', borderRadius: 0, borderColor: 'grey', itemStyle: { color: '#333', font: '12px "Trebuchet MS", Verdana, sans-serif'} }
    };

    // global database variable; 
    var db;
    // global chart variables
    var light1, mat1, pir1, sound1;

    // function to sort highcharts data array of arrays by timestamp (x)
    var bySeriesTimestamp = function(a, b){
      var ats = a[0];
      var bts = b[0]; 
      return ((ats < bts) ? -1 : ((ats > bts) ? 1 : 0));
    }

    // function that requests live data from AWS DynamoDB
    function requestData() {
      if (!db) return;
      // get current max timestamp from chart
      var ts_current = light1 && light1.xAxis && light1.xAxis[0].getExtremes().max ? light1.xAxis[0].getExtremes() : {max: 0};
      // request chart data from AWS, with timestamp > ts_current
      db.scan({TableName: 'sensors', FilterExpression: '#ts > :ts_current', ExpressionAttributeNames: {'#ts': 'device_ts'}, ExpressionAttributeValues: {':ts_current': {'S': String(ts_current.max)}}}, function(err, data) {
        if (err) {
          console.log(err, err.stack);
          return;
        } else {
          var light1data = []; //chart ? chart.series[0].data : [];
          var mat1data = []; //chart ? chart.series[0].data : [];
          var sound1data = []; //chart ? chart.series[0].data : [];
          var sound2data = []; //chart ? chart.series[0].data : [];
          var pir1data = []; //chart ? chart.series[0].data : [];
          console.log("update charts with " + data.Items.length + " items");
          _.each(data.Items, function(item) {
            payload = item.payload.M;
            point = [];
            point.push(Number(payload.ts.N)*1000);
            point.push(Number(payload.lux.N));
            light1data.push(point);
            point = [];
            point.push(Number(payload.ts.N)*1000);
            point.push(Number(payload.mat.N));
            mat1data.push(point);
            point = [];
            point.push(Number(payload.ts.N)*1000);
            point.push(Number(payload.sound.N));
            sound1data.push(point);
            point = [];
            point.push(Number(payload.ts.N)*1000);
            point.push(Number(payload.volume.N));
            sound2data.push(point);
            point = [];
            point.push(Number(payload.ts.N)*1000);
            point.push(Number(payload.pir.N));
            pir1data.push(point);
          });
          // highcharts required data to be sorted
          light1data.sort(bySeriesTimestamp);
          mat1data.sort(bySeriesTimestamp);
          sound1data.sort(bySeriesTimestamp);
          sound2data.sort(bySeriesTimestamp);
          pir1data.sort(bySeriesTimestamp);

          light1.hideLoading();
          mat1.hideLoading();
          sound1.hideLoading();
          pir1.hideLoading();

          var i = 0;
          for (i; i < light1data.length; i++) {
            // add data points in series, no redraw
            light1.series[0].addPoint(light1data[i], false);
            mat1.series[0].addPoint(mat1data[i], false);
            sound1.series[0].addPoint(sound1data[i], false);
            sound1.series[1].addPoint(sound2data[i], false);
            pir1.series[0].addPoint(pir1data[i], false);
          }
          // redraw chart
          light1.redraw();
          mat1.redraw();
          sound1.redraw();
          pir1.redraw();
          // run function again in 1 minute to request for newer data
          setTimeout(requestData, 60000); 
        }
      });
    }
  
    // main function, perform login and populate charts
    window.onAmazonLoginReady = function() {
      amazon.Login.setClientId(clientId);
      // callback function that populates charts after login
      document.getElementById('login').onclick = function() {
        amazon.Login.authorize({scope: 'profile'}, function(response) {
          if (!response.error) { // logged in
            AWS.config.credentials = new AWS.WebIdentityCredentials({
              RoleArn: roleArn,
              ProviderId: 'www.amazon.com',
              WebIdentityToken: response.access_token
            });
          
            // you are now logged in
            $("#splash").remove();
            $("#main").show();
            Highcharts.setOptions(chartTheme);
            
            // start using amazon services
            AWS.config.region = 'us-east-1';
            db = new AWS.DynamoDB();
            
            sound1el = $('#sound1').highcharts('StockChart', {
              chart: {
                zoomType: 'x'
              },
              title: {
                text: 'Sound Sensor'
              },
              xAxis: {
                title: { text: 'Date/Time Navigator (select range in all charts)', margin: 15 },
                events: {
                    afterSetExtremes: function (e) {
                      if (e.trigger == 'navigator' || e.trigger == 'zoom') {
                        light1.xAxis[0].setExtremes(e.min, e.max);
                        mat1.xAxis[0].setExtremes(e.min, e.max);
                        pir1.xAxis[0].setExtremes(e.min, e.max);
                      }
                    }
                }
              },
              yAxis: [{
                opposite: false,
                title: { text: 'Sound detected' }
              }, {
                opposite: true,
                title: {text: 'Sound volume'},
                plotBands: [{
                  from: 10,
                  to: 40,
                  color: '#fbe2a5'
                }, {
                  from: 40,
                  to: 127,
                  color: '#fbb7a5'
                }]
              }],
              rangeSelector: {
                  enabled: false
              },
              navigator: {
                enabled: true,
                baseSeries: -1,
                height: 30,
                margin: 10
              },
              series : [{
                type: 'area',
                color: '#f75c63',
                name : 'Sound',
                data : [],
                step: true
              }, {
                type: 'line',
                name : 'Volume',
                data : [],
                step: true,
                yAxis: 1
              }]
            });
            sound1 = sound1el.highcharts();
            sound1.showLoading();

            light1el = $('#light1').highcharts('StockChart', {
              chart: {
                defaultSeriesType: 'line'
              },
              title: {
                text: 'Light Sensor'
              },
              yAxis: {
                type: 'logarithmic',
                opposite: false,
                title: { text: 'Luminosity (lux)' },
                plotBands: [{
                  from: 0,
                  to: 40,
                  color: '#e3e3e3'
                }, {
                  from: 2000,
                  to: 100000,
                  color: '#fbe2a5'
                }]
              },
              rangeSelector: {
                  enabled: false
              },
              navigator: {
                enabled: false
              },
              scrollbar: {
                enabled: false
              },
              series : [{
                name : 'Luminosity',
                data : [],
                step: true
              }]
            });
            light1 = light1el.highcharts();
            light1.showLoading();

            mat1el = $('#mat1').highcharts('StockChart', {
              chart: {
                defaultSeriesType: 'line'
              },
              title: {
                text: 'Pressure Switch (Mat)'
              },
              yAxis: {
                opposite: false,
                title: { text: 'Baby in crib' }
              },
              rangeSelector: {
                  enabled: false
              },
              navigator: {
                enabled: false
              },
              scrollbar: {
                enabled: false
              },
              series : [{
                type: 'area',
                color: '#4f4f55',
                name : 'Pressure',
                data : [],
                step: true
              }]
            });
            mat1 = mat1el.highcharts();
            mat1.showLoading();

            pir1el = $('#pir1').highcharts('StockChart', {
              chart: {
                defaultSeriesType: 'line',
                events: {
                  load: requestData
                }
              },
              title: {
                text: 'Motion Sensor'
              },
              yAxis: {
                opposite: false,
                title: { text: 'Motion detected' }
              },
              rangeSelector: {
                  enabled: false
              },
              navigator: {
                enabled: false
              },
              scrollbar: {
                enabled: false
              },
              series : [{
                name : 'Motion',
                type: 'area',
                color: '#b6f3aa',
                data : [],
                step: true
              }]
            });
            pir1 = pir1el.highcharts();
            pir1.showLoading();


          } else {
            // error logging in to amazon
            console.log('There was a problem logging you in.');
          }
        });
      };
    };

    (function(d) {
      var a = d.createElement('script'); a.type = 'text/javascript';
      a.async = true; a.id = 'amazon-login-sdk';
      a.src = 'https://api-cdn.amazon.com/sdk/login1.js';
      d.getElementById('amazon-root').appendChild(a);
    })(document);
  </script>
</center>
</body>
</html>

Credits

Be4b2f8132e159da7a3f6fab1db12ad7
Marian Mihailescu
1 project • 12 followers
Contact

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Sign up / LoginProjectsPlatformsTopicsContestsLiveAppsBetaBlog