0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

赤外線リモコンを自作する - その4サーバサイド編

Last updated at Posted at 2022-09-05

目次

  1. 赤外線リモコンを自作する - その1データ解析編
  2. 赤外線リモコンを自作する - その2データ送信編
  3. 赤外線リモコンを自作する - その3温度/湿度センサー編
  4. 赤外線リモコンを自作する - その4サーバサイド編
  5. 赤外線リモコンを自作する - その5クライアント編

赤外線リモコンを自作する - その4サーバサイド編

今回は、赤外線リモコンであるArduinoに対して外部から命令を出すためのサーバサイドプログラムについて説明します。

開発環境

サーバサイドプログラムはAWS上にServerless Frameworkを使ってデプロイします。

  • AWS (API GW, Lambda, DynamoDB, SQS)
  • Serverless Framework
sls -v
Running "serverless" from node_modules
Framework Core: 3.19.0
Plugin: 6.2.2
SDK: 4.3.2

全体の流れ

予めその1データ解析編で取得した赤外線信号を、DynamoDBに保存します。
利用者は、タスク(赤外線信号の送信命令)をサーバに登録します。
Arduinoは定期的にセンサ値(温度、湿度)をサーバにアップロードする。この際、タスクが存在する場合には、サーバは返り値として赤外線信号を返します。
赤外線信号を受信した場合には、Arduinoが赤外線信号を送信し、機器を操作します。

サーバサイドプログラム

package.json

{
  "dependencies": {
    "aws-sdk": "^2.1158.0"
  }
}

serverless.yml

service: homeir
frameworkVersion: '3'

provider:
  name: aws
  runtime: nodejs12.x
  stage: v1
  region: ap-northeast-1
  profile: default
  logRetentionInDays: 7
  environment:
    DB_TABLE_COMMANDS: ${self:service}-commands
    DB_TABLE_SENSOR_VALUES: ${self:service}-sensor-values
    SQS_TASK_URL: { Ref: TaskQueue }
  iam:
    role:
      statements:
        - Effect: Allow
          Action: # 必要に応じて制限してください
            - dynamodb:*
            - s3:*
            - sqs:*
          Resource: "*"

package:
    patterns:
        - '!**'
        - handler.js

functions:
  send:
    handler: handler.send
    events:
      - http:
          method: post
          path: /send
          cors:
            origins:
              - '*'
  saveCommand:
    handler: handler.saveCommand
  createTask:
    handler: handler.createTask
    events:
      - http:
          method: post
          path: /tasks
          cors:
            origins:
              - '*'

resources:
 Resources:
  DbTableCommands:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${self:provider.environment.DB_TABLE_COMMANDS}
      AttributeDefinitions:
        - AttributeName: key
          AttributeType: S
      KeySchema:
        - AttributeName: key
          KeyType: HASH
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1
  DbTableSensorValues:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${self:provider.environment.DB_TABLE_SENSOR_VALUES}
      AttributeDefinitions:
        - AttributeName: timestamp
          AttributeType: N
      KeySchema:
        - AttributeName: timestamp
          KeyType: HASH
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1
  TaskQueue:
    Type: "AWS::SQS::Queue"
    Properties:
      QueueName: ${self:service}-task
      MessageRetentionPeriod: 7200 # メッセージ保持秒数

handler.js

'use strict';

const aws = require('aws-sdk');
const dynamoDB = new aws.DynamoDB.DocumentClient();
const sqs = new aws.SQS({apiVersion: '2012-11-05'});

module.exports.saveCommand = async (event) => {
  await dynamoDB.put({
    TableName: process.env.DB_TABLE_COMMANDS,
    Item: {
      key: process.env.key,
      command: process.env.command
    }
  }).promise();
  return "OK";
}

module.exports.createTask = async (event) => {
  console.log(event.body);
  const json = JSON.parse(event.body);

  // 送信すべき赤外線データを取得
  const commandItem = await dynamoDB.get({
    TableName: process.env.DB_TABLE_COMMANDS,
    Key: {
      key: json.key
    }
  }).promise();
  if (!commandItem) {
    return {
      statusCode: 404,
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ 'success': false }),
    };
  }

  const commandStr = commandItem.Item.command;
  const length = (commandStr.match(/\,/g) || []).length + 1
  await sqs.sendMessage({
    MessageBody: JSON.stringify({
      command: commandStr,
      length: length,
      ceratedAt: Date.now()
    }),
    QueueUrl: process.env.SQS_TASK_URL
  }).promise();

  return {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ 'success': true }),
  };
}

module.exports.send = async (event) => {
  console.log(event.body);
  const json = JSON.parse(event.body);
  // センサデータの保存
  await dynamoDB.put({
    TableName: process.env.DB_TABLE_SENSOR_VALUES,
    Item: {
      timestamp: Date.now(),
      humidity: json.humidity,
      temperature: json.temperature
    }
  }).promise();
  // SQSより赤外線情報を取得
  const sqsMessage = await sqs.receiveMessage({
    QueueUrl: process.env.SQS_TASK_URL,
    MaxNumberOfMessages: 1
  }).promise();
  console.log(sqsMessage);
  var response = {'command': '', 'length': 0};
  if (sqsMessage.Messages) {
    const message = sqsMessage.Messages[0];
    const json = JSON.parse(message.Body)
    response['command'] = json.command;
    response['length'] = json.length;
    await sqs.deleteMessage({
      QueueUrl: process.env.SQS_TASK_URL,
      ReceiptHandle: message.ReceiptHandle
    }).promise()
  }
  console.log(response);

  return {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(response),
  };
};

関数説明

saveCommand

saveCommand関数を使って、赤外線信号をDBに保存します。keyに信号名、commandに赤外線信号を設定し、直接Lambdaを呼び出すことでDynamoDBに保存します。

sls invoke -f saveCommand --env key=workplace_light_off --env command=3502,1732,44...

createTask

利用者が、タスク(赤外線信号の送信命令)をサーバに登録するためのものです。SlackやLINE APIを経由して操作できる想定なので、POSTメソッドにより外部から呼び出せます。
タスクを受け取った場合には、タスク名から赤外線信号を取得し、SQSに命令を登録します。
BodyとしてsaveCommandで登録した信号名を指定します。

{
  "key": "workplace_ac_off"
}

send

Arduinoがセンサ値(温度、湿度)をアップロードするためのエンドポイントです。
アップロードの際、タスクが存在する場合には、サーバは返り値として赤外線信号を返します。

次回

次回、クライアントであるArduino側のプログラムを解説します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?