Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Stephanie Ko
Published © MIT

Smart Button Baby Monitor

Monitor your baby proactively with, Breathing, Rollover, Crying in a smart button.

IntermediateFull instructions provided3 hours2,416

Things used in this project

Hardware components

STEVAL-STLKT01V1
STMicroelectronics STEVAL-STLKT01V1
×1

Software apps and online services

Watson
IBM Watson
Xcode
Apple Xcode
SMS Messaging API
Twilio SMS Messaging API
Alexa Skills Kit
Amazon Alexa Alexa Skills Kit

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Code

Node-Red JSON

JSON
[
    {
        "id": "94cfccb8.475e5",
        "type": "change",
        "z": "9a3b30e7.e7d3a",
        "name": "Extract Temperature",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.d.Temperature",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 545,
        "y": 150,
        "wires": [
            [
                "e5778a32.5b3d38"
            ]
        ]
    },
    {
        "id": "891ffcf0.7d87d",
        "type": "change",
        "z": "9a3b30e7.e7d3a",
        "name": "Extract Accelerometer X",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.d.X",
                "tot": "msg"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "X",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 555,
        "y": 210,
        "wires": [
            [
                "1ef3873b.1bb189"
            ]
        ]
    },
    {
        "id": "e96e920b.36bad",
        "type": "change",
        "z": "9a3b30e7.e7d3a",
        "name": "Extract Accelerometer Y",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.d.Y",
                "tot": "msg"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "Y",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 555,
        "y": 250,
        "wires": [
            [
                "1ef3873b.1bb189"
            ]
        ]
    },
    {
        "id": "48f968e3.d4d798",
        "type": "change",
        "z": "9a3b30e7.e7d3a",
        "name": "Extract Accelerometer Z",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.d.Z",
                "tot": "msg"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "Z",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 555,
        "y": 290,
        "wires": [
            [
                "1ef3873b.1bb189",
                "5558fb4d.8798a4",
                "8f91cae8.861868"
            ]
        ]
    },
    {
        "id": "4466822e.f8a0ec",
        "type": "switch",
        "z": "9a3b30e7.e7d3a",
        "name": "SensorTile Event Types",
        "property": "eventType",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "Temperature",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "Accelerometer",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "Mic Level",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "outputs": 3,
        "x": 255,
        "y": 250,
        "wires": [
            [
                "94cfccb8.475e5"
            ],
            [
                "891ffcf0.7d87d",
                "e96e920b.36bad",
                "48f968e3.d4d798"
            ],
            [
                "8b7c86dc.a54cd8"
            ]
        ]
    },
    {
        "id": "8b7c86dc.a54cd8",
        "type": "change",
        "z": "9a3b30e7.e7d3a",
        "name": "Extract Microphone level",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.d.Mic",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 555,
        "y": 350,
        "wires": [
            [
                "a5e994.ee09967",
                "a74e167f.401388"
            ]
        ]
    },
    {
        "id": "809bf588.62fbc8",
        "type": "ibmiot in",
        "z": "9a3b30e7.e7d3a",
        "authentication": "boundService",
        "apiKey": "",
        "inputType": "evt",
        "deviceId": "C07A2E305C4D",
        "applicationId": "",
        "deviceType": "+",
        "eventType": "+",
        "commandType": "",
        "format": "json",
        "name": "IBM IoT",
        "service": "registered",
        "allDevices": true,
        "allApplications": "",
        "allDeviceTypes": true,
        "allEvents": true,
        "allCommands": "",
        "allFormats": "",
        "qos": 0,
        "x": 55,
        "y": 167,
        "wires": [
            [
                "f383f7f1.72c348",
                "f3f6c29b.a57de"
            ]
        ]
    },
    {
        "id": "3e63e37d.0d0e3c",
        "type": "comment",
        "z": "9a3b30e7.e7d3a",
        "name": "WIoTP via API keys",
        "info": "Registered Device",
        "x": 101,
        "y": 119,
        "wires": []
    },
    {
        "id": "c03bb406.03f968",
        "type": "debug",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "active": false,
        "console": "false",
        "complete": "true",
        "x": 353.75000381469727,
        "y": 168.25000190734863,
        "wires": []
    },
    {
        "id": "98eac4d1.ae06d8",
        "type": "debug",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "false",
        "x": 686.5277824401855,
        "y": 499.0278081893921,
        "wires": []
    },
    {
        "id": "f383f7f1.72c348",
        "type": "delay",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "pauseType": "rate",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": true,
        "x": 212.5,
        "y": 169.50000381469727,
        "wires": [
            [
                "4466822e.f8a0ec",
                "c03bb406.03f968"
            ]
        ]
    },
    {
        "id": "e5778a32.5b3d38",
        "type": "ui_chart",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "group": "a879ac54.d2c46",
        "order": 3,
        "width": 0,
        "height": 0,
        "label": "Temperature",
        "chartType": "line",
        "legend": "false",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "",
        "dot": false,
        "ymin": "",
        "ymax": "",
        "removeOlder": "10",
        "removeOlderPoints": "",
        "removeOlderUnit": "60",
        "cutout": 0,
        "colors": [
            "#1f77b4",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "useOldStyle": true,
        "x": 775,
        "y": 150,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "1ef3873b.1bb189",
        "type": "ui_chart",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "group": "a879ac54.d2c46",
        "order": 4,
        "width": 0,
        "height": 0,
        "label": "Accelerometer",
        "chartType": "line",
        "legend": "false",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "",
        "dot": false,
        "ymin": "",
        "ymax": "",
        "removeOlder": "10",
        "removeOlderPoints": "",
        "removeOlderUnit": "60",
        "cutout": 0,
        "colors": [
            "#1f77b4",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "useOldStyle": true,
        "x": 837.5000152587891,
        "y": 213.75000190734863,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "a5e994.ee09967",
        "type": "ui_chart",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "group": "a879ac54.d2c46",
        "order": 5,
        "width": 0,
        "height": 0,
        "label": "Microphone",
        "chartType": "line",
        "legend": "false",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "",
        "dot": false,
        "ymin": "",
        "ymax": "",
        "removeOlder": "10",
        "removeOlderPoints": "",
        "removeOlderUnit": "60",
        "cutout": 0,
        "colors": [
            "#1f77b4",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "useOldStyle": true,
        "x": 775,
        "y": 350,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "a74e167f.401388",
        "type": "switch",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "gte",
                "v": "50",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "outputs": 1,
        "x": 758.2500076293945,
        "y": 385.0000057220459,
        "wires": [
            []
        ]
    },
    {
        "id": "39aec6e9.2e010a",
        "type": "switch",
        "z": "9a3b30e7.e7d3a",
        "name": "Shake",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "Shake",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "outputs": 1,
        "x": 668.3333549499512,
        "y": 451.4444227218628,
        "wires": [
            [
                "bb96af4.e54825"
            ]
        ]
    },
    {
        "id": "bb96af4.e54825",
        "type": "function",
        "z": "9a3b30e7.e7d3a",
        "name": "Send SMS",
        "func": "msg.url = 'https://rest.nexmo.com/sms/json';\nmsg.headers = {\n    'content-type': 'application/json',\n};\n\nvar data = {\"api_key\":\"_\",\n\"api_secret\":\"_\",\n\"to\":\"T Number\",\n\"from\":\"From Number\",\n\"text\":\"I am okay\"}; \nmsg.payload = JSON.stringify(data);\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 803.8888549804688,
        "y": 449.2221984863281,
        "wires": [
            [
                "f3ad53c0.7db21"
            ]
        ]
    },
    {
        "id": "f3ad53c0.7db21",
        "type": "http request",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "method": "POST",
        "ret": "obj",
        "url": "",
        "tls": "",
        "x": 961.2499542236328,
        "y": 449.4999752044678,
        "wires": [
            []
        ]
    },
    {
        "id": "d1f77a2d.d12df8",
        "type": "function",
        "z": "9a3b30e7.e7d3a",
        "name": "Extract Activity",
        "func": "switch(msg.payload.d.Activity) {\n    case 0:\n        msg.payload = \"NoActivity\";\n        break;\n    case 1:\n        msg.payload = \"Standing\";\n        break;\n    case 2:\n        msg.payload = \"Walking\";\n        break;\n    case 3:\n        msg.payload = \"FastWalking\";\n        break;\n    case 4:\n        msg.payload = \"Jogging\";\n        break;\n    case 5:\n        msg.payload = \"Biking\";\n        break;\n    case 6:\n        msg.payload = \"Drivin\";\n        break;\n    default:\n        msg.payload = \"Unkown\";\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 508.12500762939453,
        "y": 578.2500076293945,
        "wires": [
            [
                "f7083456.1763b8"
            ]
        ]
    },
    {
        "id": "df7e29f3.924768",
        "type": "function",
        "z": "9a3b30e7.e7d3a",
        "name": "Extract Position",
        "func": "switch(msg.payload.d[\"Carry Position\"]) {\n    case 0:\n        msg.payload = \"Unkown\";\n        break;\n    case 1:\n        msg.payload = \"OnDesk\";\n        break;\n    case 2:\n        msg.payload = \"InHand\";\n        break;\n    case 3:\n        msg.payload = \"NearHead\";\n        break;\n    case 4:\n        msg.payload = \"ShirtPocket\";\n        break;\n    case 5:\n        msg.payload = \"TrousersPocket\";\n        break;\n    case 6:\n        msg.payload = \"ArmSwing\";\n        break;\n    default:\n        msg.payload = \"Unkown\";\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 506.87500762939453,
        "y": 637.0000085830688,
        "wires": [
            [
                "31ea8505.6e16aa"
            ]
        ]
    },
    {
        "id": "280aaa43.c2b086",
        "type": "function",
        "z": "9a3b30e7.e7d3a",
        "name": "Extract Gesture",
        "func": "if (msg.payload.d[\"Mems Gesture\"] == 3){\n    msg.payload = \"Shake\";\n}\nreturn msg;\n\n",
        "outputs": 1,
        "noerr": 0,
        "x": 505,
        "y": 477,
        "wires": [
            [
                "39aec6e9.2e010a",
                "98eac4d1.ae06d8"
            ]
        ]
    },
    {
        "id": "f7083456.1763b8",
        "type": "ui_text",
        "z": "9a3b30e7.e7d3a",
        "group": "a879ac54.d2c46",
        "order": 1,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "Activity",
        "format": "{{msg.payload}}",
        "layout": "row-spread",
        "x": 683.1250114440918,
        "y": 578.2500076293945,
        "wires": []
    },
    {
        "id": "31ea8505.6e16aa",
        "type": "ui_text",
        "z": "9a3b30e7.e7d3a",
        "group": "a879ac54.d2c46",
        "order": 2,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "Carry Position",
        "format": "{{msg.payload}}",
        "layout": "row-spread",
        "x": 701.8750076293945,
        "y": 634.5000085830688,
        "wires": []
    },
    {
        "id": "42fae9c3.56d378",
        "type": "function",
        "z": "9a3b30e7.e7d3a",
        "name": "Send Emergency SMS",
        "func": "msg.url = 'https://rest.nexmo.com/sms/json';\nmsg.headers = {\n    'content-type': 'application/json',\n};\n\nvar data = {\"api_key\":\"_\",\n\"api_secret\":\"_\",\n\"to\":\"T Number\",\n\"from\":\"From Number\",\n\"text\":\"Emergency : Falling down\"}; \nmsg.payload = JSON.stringify(data);\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 985.0000152587891,
        "y": 277.00000286102295,
        "wires": [
            [
                "54ba7306.1d536c"
            ]
        ]
    },
    {
        "id": "54ba7306.1d536c",
        "type": "http request",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "method": "POST",
        "ret": "obj",
        "url": "",
        "tls": "",
        "x": 949.8610992431641,
        "y": 333.527774810791,
        "wires": [
            []
        ]
    },
    {
        "id": "5558fb4d.8798a4",
        "type": "switch",
        "z": "9a3b30e7.e7d3a",
        "name": "Fall Detection",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "gte",
                "v": "1500",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "outputs": 1,
        "x": 780.0000152587891,
        "y": 278.25000286102295,
        "wires": [
            [
                "42fae9c3.56d378"
            ]
        ]
    },
    {
        "id": "8f91cae8.861868",
        "type": "debug",
        "z": "9a3b30e7.e7d3a",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "false",
        "x": 893.1250114440918,
        "y": 240.75000190734863,
        "wires": []
    },
    {
        "id": "f3f6c29b.a57de",
        "type": "switch",
        "z": "9a3b30e7.e7d3a",
        "name": "SensorTile Event Types",
        "property": "eventType",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "Mems Gesture",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "Activity",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "Carry Position",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "outputs": 3,
        "x": 248.75,
        "y": 440.7500057220459,
        "wires": [
            [
                "280aaa43.c2b086"
            ],
            [
                "d1f77a2d.d12df8"
            ],
            [
                "df7e29f3.924768"
            ]
        ]
    },
    {
        "id": "a879ac54.d2c46",
        "type": "ui_group",
        "z": "",
        "name": "Elderly Monitor",
        "tab": "64da1951.2dc478",
        "disp": true,
        "width": "6"
    },
    {
        "id": "64da1951.2dc478",
        "type": "ui_tab",
        "z": "",
        "name": "Home",
        "icon": "dashboard",
        "order": 1
    }
]

Alexa Skill Kit Lamda Code

JavaScript
'use strict';

var https = require('https');
// https is a default part of Node.JS.  Read the developer doc:  https://nodejs.org/api/https.html
// try other APIs such as the current bitcoin price : https://btc-e.com/api/2/btc_usd/ticker  returns ticker.last

function httpsGet(callback) {


    // Update these options with the details of the web service you would like to call
    var options = {
        host: 'sensorelderly.mybluemix.net',
        path: '/status',
        method: 'GET',

        // if x509 certs are required:
        // key: fs.readFileSync('certs/my-key.pem'),
        // cert: fs.readFileSync('certs/my-cert.pem')
    };

    var req = https.request(options, res => {
        res.setEncoding('utf8');
        var returnData = "";

        res.on('data', chunk => {
            returnData = returnData + chunk;
        });

        res.on('end', () => {
            // we have now received the raw return data in the returnData variable.
            // We can see it in the log output via:
            console.log(JSON.stringify(returnData));
            // we may need to parse through it to extract the needed data

            var status = JSON.parse(returnData);

            callback(status);  // this will execute whatever function the caller defined, with one argument

        });

    });
    req.end();

}


// --------------- Helpers that build all of the responses -----------------------

function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output,
        },
        card: {
            type: 'Simple',
            title: `SessionSpeechlet - ${title}`,
            content: `SessionSpeechlet - ${output}`,
        },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText,
            },
        },
        shouldEndSession,
    };
}

function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: '1.0',
        sessionAttributes,
        response: speechletResponse,
    };
}


// --------------- Functions that control the skill's behavior -----------------------

function getWelcomeResponse(callback) {
    // If we wanted to initialize the session to have some attributes we could add those here.
    const sessionAttributes = {};
    const cardTitle = 'Welcome';
    const speechOutput = 'Welcome to baby button.';
    // If the user either does not reply to the welcome message or says something that is not
    // understood, they will be prompted again with this text.
    const repromptText = 'You can ask me the status of the baby';
    const shouldEndSession = false;

    callback(sessionAttributes,
        buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
}

function handleSessionEndRequest(callback) {
    const cardTitle = 'Session Ended';
    const speechOutput = 'Thank you for checking baby status';
    // Setting this to true ends the session and exits the skill.
    const shouldEndSession = true;

    callback({}, buildSpeechletResponse(cardTitle, speechOutput, null, shouldEndSession));
}


function getStatus(intent, session, callback) {
    const cardTitle = intent.name;
    let repromptText = '';
    let sessionAttributes = {};
    const shouldEndSession = true;
    let speechOutput = '';
    
    httpsGet((myResult) => {
        console.log("received : " + myResult);
        let crying = myResult.crying;
        let rollover = myResult.rollover;
        if(crying == "yes"){
            speechOutput = 'The baby is crying. And rollover status is ' + rollover;
        }else{
            speechOutput = 'The baby is not crying. And rollover status is ' + rollover;
        }
        
        callback(sessionAttributes,
            buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));

        }
    );
}



// --------------- Events -----------------------

/**
 * Called when the session starts.
 */
function onSessionStarted(sessionStartedRequest, session) {
    console.log(`onSessionStarted requestId=${sessionStartedRequest.requestId}, sessionId=${session.sessionId}`);
}

/**
 * Called when the user launches the skill without specifying what they want.
 */
function onLaunch(launchRequest, session, callback) {
    console.log(`onLaunch requestId=${launchRequest.requestId}, sessionId=${session.sessionId}`);

    // Dispatch to your skill's launch.
    getWelcomeResponse(callback);
}

/**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log(`onIntent requestId=${intentRequest.requestId}, sessionId=${session.sessionId}`);

    const intent = intentRequest.intent;
    const intentName = intentRequest.intent.name;

    // Dispatch to your skill's intent handlers
    if (intentName === 'Status') {
        getStatus(intent, session, callback);
    } else if (intentName === 'AMAZON.HelpIntent') {
        getWelcomeResponse(callback);
    } else if (intentName === 'AMAZON.StopIntent' || intentName === 'AMAZON.CancelIntent') {
        handleSessionEndRequest(callback);
    } else {
        throw new Error('Invalid intent');
    }
}

/**
 * Called when the user ends the session.
 * Is not called when the skill returns shouldEndSession=true.
 */
function onSessionEnded(sessionEndedRequest, session) {
    console.log(`onSessionEnded requestId=${sessionEndedRequest.requestId}, sessionId=${session.sessionId}`);
    // Add cleanup logic here
}


// --------------- Main handler -----------------------

// Route the incoming request based on type (LaunchRequest, IntentRequest,
// etc.) The JSON body of the request is provided in the event parameter.
exports.handler = (event, context, callback) => {
    try {
        console.log(`event.session.application.applicationId=${event.session.application.applicationId}`);

        /**
         * Uncomment this if statement and populate with your skill's application ID to
         * prevent someone else from configuring a skill that sends requests to this function.
         */
        /*
        if (event.session.application.applicationId !== 'amzn1.echo-sdk-ams.app.[unique-value-here]') {
             callback('Invalid Application ID');
        }
        */

        if (event.session.new) {
            onSessionStarted({ requestId: event.request.requestId }, event.session);
        }

        if (event.request.type === 'LaunchRequest') {
            onLaunch(event.request,
                event.session,
                (sessionAttributes, speechletResponse) => {
                    callback(null, buildResponse(sessionAttributes, speechletResponse));
                });
        } else if (event.request.type === 'IntentRequest') {
            onIntent(event.request,
                event.session,
                (sessionAttributes, speechletResponse) => {
                    callback(null, buildResponse(sessionAttributes, speechletResponse));
                });
        } else if (event.request.type === 'SessionEndedRequest') {
            onSessionEnded(event.request, event.session);
            callback();
        }
    } catch (err) {
        callback(err);
    }
};

Credits

Stephanie Ko
2 projects • 10 followers
Mobile & IOT developer

Comments