Project tutorial
Smart Message Board

Smart Message Board © Apache-2.0

You can set a message on a dot matrix display by Alexa!

  • 3,985 views
  • 0 comments
  • 14 respects

Components and supplies

Ard yun
Arduino Yun
×1
Ojyc6a5jtrgslqwc5j7gw9ti
Seeed Base Shield V2
×1
Amazon echo dot
Amazon Alexa Echo Dot
×1
Seeed Grove Rotary Angle Sensor
For scroll speed adjustment. optional
×1
Dot Matrix MAX7219 4 in 1 Module
one to eight MAX7219 modules can be controllable by this project.
×1
11026 02
Jumper wires (generic)
×8

Apps and online services

About this project

It is fun to set message by your voice!

My Message Board Demo Video

Setup Flow

  • Arduino YUN AWS IoT SDK setup
  • Arduino Project
  • Wiring
  • Lambda
  • Skill

Arduino YUN AWS IoT SDK setup

Refer to https://github.com/aws/aws-iot-device-sdk-arduino-yun

Everything you need is described. Here is just a summary.

  • First, please configure network connection of Arduino YUN, by either by wired or wireless.
  • Create AWS IoT Credentials, and copy them to local folder.
  • Setup SSH connection to Arduino YUN.
  • Download AWS IoT SDK.
  • Run setup script.

Arduino Project

Download source codes:

  • MyMessageBoard.ino
  • DotMatrixControl.cpp
  • DotMatrixControl.h
  • aws_iot_config.h (Change IoT endpoint url with yours)

Add library from https://github.com/nickgammon/MAX7219_Dot_Matrix/tree/master/src

Place them in the library folder.

Wiring

Wire YUN, Dot Matrix and Rotary Angle Sensor as Circuit Design diagram.

Lambda

  • Go to AWS console, AWS Lambda page.
  • Create a new function of Node.js.
  • Change IoT endpoint url with yours and save it.
  • Setup trigger from Alexa Skill Kit, access to AWS IoT and CloudWatch logs.

Skill

Finally skill

  • Go to Amazon developper console.
  • Go to Alexa Skill Kit page.
  • Add a new skill.
  • Enter Name and Invocation Name
  • In configuration page, you need to enter Lambda ARN endpoint which created above.

Now you can test this project! Enjoy it!

Code

aws_iot_config.hC/C++
Place this code in the same directory of Arduino ino file.
/*
 * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

#ifndef config_usr_h
#define config_usr_h

// Copy and paste your configuration into this file
//===============================================================
#define AWS_IOT_MQTT_HOST "XXXXXXXXXXXX.iot.us-east-1.amazonaws.com"   // your endpoint
#define AWS_IOT_MQTT_PORT 8883                  // your port
#define AWS_IOT_CLIENT_ID "My_ClientID"           // your client ID
#define AWS_IOT_MY_THING_NAME "My_Board"            // your thing name
#define AWS_IOT_ROOT_CA_FILENAME "aws-iot-rootCA.crt"           // your root-CA filename
#define AWS_IOT_CERTIFICATE_FILENAME "cert.pem"                 // your certificate filename
#define AWS_IOT_PRIVATE_KEY_FILENAME "privkey.pem"              // your private key filename
//===============================================================
// SDK config, DO NOT modify it
#define AWS_IOT_PATH_PREFIX "../certs/"
#define AWS_IOT_ROOT_CA_PATH AWS_IOT_PATH_PREFIX AWS_IOT_ROOT_CA_FILENAME			// use this in config call
#define AWS_IOT_CERTIFICATE_PATH AWS_IOT_PATH_PREFIX AWS_IOT_CERTIFICATE_FILENAME	// use this in config call
#define AWS_IOT_PRIVATE_KEY_PATH AWS_IOT_PATH_PREFIX AWS_IOT_PRIVATE_KEY_FILENAME	// use this in config call

#endif
DotMatrixControl.cppC/C++
Place this code in the same directory of Arduino ino file.
#include "DotMatrixControl.h"

DotMatrixControl::DotMatrixControl(int dataPin, int clkPin, int csPin, int _displayCount) {
  DATA_PIN = dataPin;
  CLK_PIN = clkPin;
  CS_PIN = csPin;

  displayCount = _displayCount;

  if (displayCount <= 0) displayCount = 1;
  if (displayCount > MAX_DISPLAY_COUNT) displayCount = MAX_DISPLAY_COUNT;
}

void DotMatrixControl::setup() {
  digitalWrite(CS_PIN, HIGH);

  pinMode(DATA_PIN, OUTPUT);
  pinMode(CLK_PIN, OUTPUT);
  pinMode(CS_PIN, OUTPUT);

  for (int i = 0; i < sizeof(buffer); i++) buffer[i] = 0x00;

  //shutdown all display first
  for (int i = 0; i < displayCount; i++) shutdown(i, true);

  for (int i = 0; i < displayCount; i++) {
    send(i, REG_DISPLAY_TEST, 0);
    send(i, REG_SCAN_LIMIT, 7);
    send(i, REG_DECODE_MODE, 0);
    setIntensity(i, 0);
  }

  clearDisplay();

  //shutdown off
  for (int i = 0; i < displayCount; i++) shutdown(i, false);
}

void DotMatrixControl::shutdown(int index, bool isShutdown) {
  if ((index < 0) || (index >= displayCount)) return;

  send(index, REG_SHUTDOWN, isShutdown ? 0 : 1);
}

//intensity : 0-15
void DotMatrixControl::setIntensity(int intensity) {
  if ((intensity < 0) || (intensity >= 16)) return;
  for (int x = 0; x < displayCount; x++) send(x, REG_INTENSITY, intensity);
}

void DotMatrixControl::setIntensity(int index, int intensity) {
  if ((index < 0) || (index >= displayCount)) return;
  if ((intensity < 0) || (intensity >= 16)) return;

  send(index, REG_INTENSITY, intensity);
}

void DotMatrixControl::clearDisplay() {
  clearBuffer();
  transferAllDots();
}

void DotMatrixControl::clearDisplay(int index) {
  if ((index < 0) || (index >= displayCount)) return;

  clearBuffer(index);
  transferAllDots();
}

void DotMatrixControl::clearBuffer() {
  for (int x = 0; x < displayCount; x++) clearBuffer(x);
}

void DotMatrixControl::clearBuffer(int index) {
  if ((index < 0) || (index >= displayCount)) return;

  for (int i = 0; i < 8; i++) buffer[index * 8 + i] = 0;
}

//(0, 0) is right top corner
void DotMatrixControl::setDot(int x, int y, bool value) {
  int index = x / 8;
  int column = 7 - (x % 8);
  int row = y;

  setDot(index, row, column, value);
}

void DotMatrixControl::setDot(int index, int row, int column, bool value) {
  if ((index < 0) || (index >= displayCount)) return;
  if ((row < 0) || (row > 7)) return;
  if ((column < 0) || (column > 7)) return;

  int offset = index * 8;
  byte val = 1 <<  (7 - column);

  if (value) {
    buffer[offset + row] = buffer[offset + row] | val;
  } else {
    val = ~val;
    buffer[offset + row] = buffer[offset + row] & val;
  }
}

void DotMatrixControl::transferAllDots() {
  for (int i = 0; i < 8; i++) {//each line
    digitalWrite(CS_PIN, LOW);

    for (int x = 0; x < displayCount; x++) {//each device
      int offset = ((displayCount - 1) - x) * 8;
      shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, REG_DIGIT_0 + i);
      shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, buffer[offset + i]);
    }

    digitalWrite(CS_PIN, HIGH);
  }
}

void DotMatrixControl::shiftLeft() {
  for (int i = 0; i < 8; i++) {//each line
    for (int x = 0; x < displayCount; x++) {//each device
      int offset = ((displayCount - 1) - x) * 8;
      int mostBit = buffer[offset + i] >> 7;
      buffer[offset + i] <<= 1;

      if (x > 0) {
        int offsetLeftDevice = ((displayCount - 1) - (x - 1)) * 8;
        buffer[offsetLeftDevice + i] += mostBit;
      }
    }
  }
}

void DotMatrixControl::send(int index, byte reg, byte value) {
  int dataSize = displayCount * 2;
  byte sendData[MAX_DISPLAY_COUNT * 2];

  memset(sendData, 0, sizeof(sendData));

  sendData[index * 2] = reg;
  sendData[index * 2 + 1] = value;

  digitalWrite(CS_PIN, LOW);

  for (int i = 0; i < displayCount; i++) {
    shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, sendData[i * 2]);     //reg
    shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, sendData[i * 2 + 1]); //value
  }

  digitalWrite(CS_PIN, HIGH);
}
DotMatrixControl.hC/C++
Place this code in the same directory of Arduino ino file.
#ifndef DotMatrixControl_h
#define DotMatrixControl_h

#include <avr/pgmspace.h>
#include <Arduino.h>


#define MAX_DISPLAY_COUNT 4

#define REG_NO_OP        0
#define REG_DIGIT_0      1
#define REG_DECODE_MODE  9
#define REG_INTENSITY   10
#define REG_SCAN_LIMIT  11
#define REG_SHUTDOWN    12
#define REG_DISPLAY_TEST 15


class DotMatrixControl {
  private:
    byte buffer[MAX_DISPLAY_COUNT * 8];

    int DATA_PIN;
    int CLK_PIN;
    int CS_PIN;

    int displayCount;

  public:
    DotMatrixControl(int dataPin, int clkPin, int csPin, int _displayCount);
    
    void setup();
    
    void shutdown(int index, bool isShutdown);
    void setIntensity(int intensity);
    void setIntensity(int index, int intensity);

    void clearDisplay();
    void clearDisplay(int index);
    void clearBuffer();
    void clearBuffer(int index);

    void setDot(int x, int y, bool value);
    void setDot(int index, int row, int col, bool value);
    
    void transferAllDots();
    void shiftLeft();

  private:
    void send(int index, byte reg, byte value);
};

#endif	//DotMatrixControl_h
MyMessageBoard.inoArduino
#include <aws_iot_mqtt.h>
#include <aws_iot_version.h>
#include "aws_iot_config.h"

#include "MAX7219_Dot_Matrix_font.h"  //https://github.com/nickgammon/MAX7219_Dot_Matrix/tree/master/src
#include "DotMatrixControl.h"

//Dot Matrix
int displayCount = 4;
DotMatrixControl dmc = DotMatrixControl(12, 11, 10, displayCount);
int delayTime = 0;
int animationStatus = 0;
char currentMessage[100] = "";
int sensorPin = A0;
char skillName[] = "My Message Board";

//AWS IoT
aws_iot_mqtt_client iotClient;
bool isIoTClientReady = false;
char messageReceived[100] = "";
int iotYieldTimerDefault = 1000;//ms
int iotYieldTimer = iotYieldTimerDefault;

//loop
int seqNum = 0;


void cmdCallback(char *message, unsigned int mesLen, Message_status_t messageStatus) {
  Serial.println("cmdCallback");
  if (messageStatus != STATUS_NORMAL) {
    Serial.print("AWS IoT cmdCallback messageStatus : ");
    Serial.println(messageStatus);
    return;
  }

  strncpy(messageReceived, message, sizeof(messageReceived));
  Serial.println(message);
}



void setupAwsIot() {

  //AWS IoT
  Serial.println("AWS IoT setup.") ;

  int progress = 0;
  dmc.setDot(++progress, 0, 1); 
  dmc.transferAllDots();


  if ((iotClient.setup(AWS_IOT_CLIENT_ID)) != 0) {
    Serial.println("AWS IoT setup error!") ;
    dmc.setDot(progress, 1, 1); 
    dmc.transferAllDots();
    return;
  }

  Serial.println("AWS IoT setup ok.") ;
  dmc.setDot(++progress, 0, 1); 
  dmc.transferAllDots();

  if (iotClient.config(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, AWS_IOT_ROOT_CA_PATH, AWS_IOT_PRIVATE_KEY_PATH, AWS_IOT_CERTIFICATE_PATH) != 0) {
    Serial.println("AWS IoT config error!");
    dmc.setDot(progress, 1, 1); 
    dmc.transferAllDots();
    return;
  }

  Serial.println("AWS IoT config ok.");
  dmc.setDot(++progress, 0, 1); 
  dmc.transferAllDots();

  if (iotClient.connect() != 0) {
    Serial.println("AWS IoT connect error!");
    dmc.setDot(progress, 1, 1); 
    dmc.transferAllDots();
    return;
  }

  Serial.println("AWS IoT connect ok.");
  dmc.setDot(++progress, 0, 1); 
  dmc.transferAllDots();


  isIoTClientReady = true;

  char topicName[] = "cmd";
  Serial.print("AWS IoT subscribing to topic:\"");
  Serial.print(topicName);
  Serial.print("\".\n");

  if (iotClient.subscribe(topicName, 1, cmdCallback) != 0) {
    Serial.println("AWS IoT subscribe error!");
    dmc.setDot(progress, 1, 1); 
    dmc.transferAllDots();
    return;
  }

  Serial.println("AWS IoT subscribe ok.");
  dmc.setDot(++progress, 0, 1); 
  dmc.transferAllDots();
}

void setup() {
  Serial.begin(115200) ;
  Serial.println("setup");

  randomSeed(analogRead(0));


  dmc.setup();
  dmc.setIntensity(0);  //0-15

  Serial.println("DotMatrixControl set up ok.");

  dmc.setDot(0, 0, 1);
  dmc.transferAllDots();

  currentMessage[0] = 0;
  messageReceived[0] = 0;
  sprintf(currentMessage, "No message. You can set a message by saying \"Alexa, open %s.\"", skillName);

  setupAwsIot();
}


void transposeCharData(const char *charDataSrc, char *charDataTrg) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      charDataTrg[7 - j] +=  ((charDataSrc[i] >> (7 - j)) & 0x01) << i;
    }
  }
}

void alignLeft(const char *charDataSrc, char *charDataTrg) {
  int pos = 0;

  for (int i = 0; i < 8; i++) {
    if (charDataSrc[i] == 0) continue;

    charDataTrg[pos++] = charDataSrc[i];
  }

  while (pos < 8) charDataTrg[pos++] = 0;
}

int getFontWidth(const char *charDataSrc) {
  for (int i = 0; i < 8; i++) {
    if (charDataSrc[7 - i] != 0) return 7 - i + 1;
  }

  return 0;
}


void loopScrollMessage() {
  int charCount = strlen(currentMessage);

  if (animationStatus == 0) dmc.clearBuffer();

  if (charCount == 0)return;

  if (animationStatus < (8 * charCount)) {
    int charIndex = animationStatus / 8;
    char c = currentMessage[charIndex];
    const byte *charDataSrc = MAX7219_Dot_Matrix_font[c];
    byte bufChars1[] = {0, 0, 0, 0, 0, 0, 0, 0};
    byte bufChars2[] = {0, 0, 0, 0, 0, 0, 0, 0};
    byte bufChars[] = {0, 0, 0, 0, 0, 0, 0, 0};
    int currentCharWidth = 0;

    //copy char data
    for (int i = 0; i < 8; i++) {
      bufChars2[i] = pgm_read_byte(charDataSrc + i);
    }

    alignLeft(bufChars2, bufChars1);  //remove white space of left side
    currentCharWidth = getFontWidth(bufChars1);
    transposeCharData(bufChars1, bufChars);//tranpose


    for (int y = 0; y < 8; y++) {
      int dot = (bufChars[y] >> (animationStatus % 8))  & 0x01;
      dmc.setDot(0, y, dot);
    }

    int width = currentCharWidth;

    if (width < 7) {//skip left side space
      if (width == 0) {
        //space
        if ((animationStatus % 8) == 3) animationStatus += 4;
      } else {
        if ((animationStatus % 8) == width) animationStatus += (8 - width) - 1;
      }
    }
  }

  dmc.transferAllDots();
  dmc.shiftLeft();

  animationStatus++;

  if (animationStatus > (8 * displayCount + (8 * charCount))) {
    animationStatus = 0;  //loop back to start
  }
}


void checkMessageReceive() {
  if (messageReceived[0] == 0) return;

  Serial.println("message received");

  //start new message scroll
  strncpy(currentMessage, messageReceived, sizeof(currentMessage));
  messageReceived[0] = 0;
  animationStatus = 0;
}


void loop() {
  checkMessageReceive();

  if (--iotYieldTimer < 0) {
    if (iotClient.yield() != 0) {
      Serial.println("Yield failed!");
    }

    iotYieldTimer = iotYieldTimerDefault;
  }

  int sensorValue = analogRead(sensorPin);
  int delayValue = 0;

  if (sensorValue < 100) {
    delayValue = sensorValue / 20;
  } else  if (sensorValue < 300) {
    delayValue = 5 + (sensorValue - 100) / 10;
  } else if (sensorValue < 800) {
    delayValue = 5 + 29 + (sensorValue - 300);
  } else {
    //no scroll
    return;
  }

  loopScrollMessage();

  delay(delayValue);

  iotYieldTimer -= delayValue;
}
AWS Lambda index.jsJavaScript
Create AWS Lambda Node.js function and paste and save this code.
'use strict';

/**
 * This sample demonstrates a simple skill built with the Amazon Alexa Skills Kit.
 * The Intent Schema, Custom Slots, and Sample Utterances for this skill, as well as
 * testing instructions are located at http://amzn.to/1LzFrj6
 *
 * For additional samples, visit the Alexa Skills Kit Getting Started guide at
 * http://amzn.to/1LGWsLG
 */

var aws = require('aws-sdk');
var endpoint = 'XXXXXXXXX.iot.us-east-1.amazonaws.com'; //your endpoint
var iotdata = new aws.IotData( { endpoint: endpoint } );




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

function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output,
        },
        card: {
            type: 'Simple',
            title: `${title}`,
            content: `${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 My Message Board. ' +
        'What message do you want to set?';
        
    // 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 = 'What message do you want to set?';
    const shouldEndSession = false;

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

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

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

function createFavoriteColorAttributes(favoriteColor) {
    return {
        favoriteColor,
    };
}

/**
 * Sets the color in the session and prepares the speech to reply to the user.
 */
function setMessage(intent, session, callback) {
    const cardTitle = 'New Massage';//intent.name;
    const message = intent.slots.message;
    let repromptText = '';
    let sessionAttributes = {};
    let  shouldEndSession = false;
    let speechOutput = '';

    if (message) {
        const messageValue = message.value;
        sessionAttributes = createFavoriteColorAttributes(messageValue);
        speechOutput = `This message is set: ${messageValue}.`;
        repromptText = null;
        
            
            
    
        var params = {
          topic: 'cmd', /* required */
          payload: messageValue,
          qos: 1
        };
        
        iotdata.publish(params, function(err, data) {
          if (err) {
              console.log(err, err.stack); // an error occurred
          }
          else{     
              console.log(data);           // successful response
          }
          
          shouldEndSession = true;
            callback(sessionAttributes,
             buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
             
        });        
        
        
    } else {
        speechOutput = "What message do you want to set?";
        repromptText = "What message do you want to set?";

            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 === 'AnyMessage') {
        setMessage(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);
    }
};
MyMessageBoard_IM.jsonJSON
Alexa Skill Kit Skill Builder Code(Interaction Model)
{
    "languageModel": {
        "types": [
                  {
                  "name": "MESSAGE",
                  "values": [
                             {
                             "id": null,
                             "name": {
                             "value": "hello",
                             "synonyms": []
                             }
                             },
                             {
                             "id": null,
                             "name": {
                             "value": "good night",
                             "synonyms": []
                             }
                             },
                             {
                             "id": null,
                             "name": {
                             "value": "Thank you",
                             "synonyms": []
                             }
                             },
                             {
                             "id": null,
                             "name": {
                             "value": "I'll be home at 5pm.",
                             "synonyms": []
                             }
                             }
                             ]
                  }
                  ],
        "intents": [
                    {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                    },
                    {
                    "name": "AMAZON.HelpIntent",
                    "samples": []
                    },
                    {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                    },
                    {
                    "name": "AnyMessage",
                    "samples": [
                                "{message}"
                                ],
                    "slots": [
                              {
                              "name": "message",
                              "type": "MESSAGE"
                              }
                              ]
                    }
                    ],
        "invocationName": "my message board"
    }
}

Schematics

Circuit Design
DATA_PIN = 12; CLK_PIN = 11; CS_PIN = 10;
Rotary Angle Sensor signal = A0;
Circuit i9mexugeqm

Comments

Similar projects you might like

Smart Pool: Alexa Controlled Pool Manager

Project tutorial by Benjamin Winiarski

  • 1,362 views
  • 2 comments
  • 7 respects

Hygge Home - Alexa Smart Bath

Project tutorial by J Howard

  • 5,356 views
  • 2 comments
  • 18 respects

Scent-terrific Smart Candle

Project tutorial by Darian Johnson

  • 2,894 views
  • 0 comments
  • 32 respects

Alexa Based Smart Home Monitoring

Project tutorial by Adithya TG

  • 16,662 views
  • 19 comments
  • 47 respects

Animated Smart Light with Alexa and Arduino

Project tutorial by Bruno Portaluri

  • 3,670 views
  • 9 comments
  • 23 respects

Secure Package Delivery Trunk for Your Front Porch

Project tutorial by Team Castle Locker

  • 3,197 views
  • 1 comment
  • 19 respects
Add projectSign up / Login