Skip to content

Instantly share code, notes, and snippets.

@cm-fujii
Created August 4, 2019 13:41
Show Gist options
  • Save cm-fujii/c1a435a907346ea2aa18404c5564be05 to your computer and use it in GitHub Desktop.
Save cm-fujii/c1a435a907346ea2aa18404c5564be05 to your computer and use it in GitHub Desktop.
HomeControl 1st
import * as AWS from 'aws-sdk';
import * as QueryString from 'querystring';
const iot = new AWS.Iot();
export async function handler(event: any) {
const endpoint = await iot.describeEndpoint({
endpointType: 'iot:Data',
}).promise();
const requestParams = parseRequest(event.body);
console.log(requestParams);
const iotdata = new AWS.IotData({
endpoint: endpoint.endpointAddress,
});
await iotdata.publish({
topic: process.env.IOT_TOPIC!,
payload: JSON.stringify(requestParams),
}).promise();
return {
statusCode: 200,
body: '操作を受け付けました。',
}
}
export function parseRequest(body: any): RequestParams {
const query = QueryString.parse(body);
console.log(JSON.stringify(query));
const pattern = /^(\w+) (\w+)$/;
const result = pattern.exec(String(query.text));
if (String(query.command) !== '/control' ) {
throw new Error('Unknown command.');
}
if (result == null) {
throw new Error('Invavlid command params.');
}
return {
token: String(query.token),
team_domain: String(query.team_domain),
command: String(query.command),
target: result[1],
param: result[2],
}
}
export interface RequestParams {
token: string;
team_domain: string;
command: string;
target: string;
param: string;
}
import * as apigateway from '@aws-cdk/aws-apigateway';
import * as iot from '@aws-cdk/aws-iot';
import * as role from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import { ServicePrincipal, ManagedPolicy } from '@aws-cdk/aws-iam';
import { Duration } from '@aws-cdk/core';
import cdk = require('@aws-cdk/core');
export class HomeControlStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
// IoT Things
const raspberryPi = new iot.CfnThing(this, 'Raspberry Pi', {
thingName: 'HomeControl-RaspberryPi',
});
// IoT Topic
const iotTopic = 'HomeControl/RaspberryPi';
// IoT Policy
const raspberryPiPolicy = new iot.CfnPolicy(this, 'raspberry Pi Poliry', {
policyName: 'HomeControl-RaspberryPi-Policy',
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: 'iot:Connect',
Resource: `arn:aws:iot:${this.region}:${this.account}:client/${raspberryPi.ref}`
},
{
Effect: 'Allow',
Action: 'iot:Subscribe',
Resource: `arn:aws:iot:${this.region}:${this.account}:topicfilter/${iotTopic}`
},
]
},
});
// Role
const apiRole = new role.Role(this, 'ApiRole', {
roleName: 'HomeControl-LambdaRole',
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [
ManagedPolicy.fromAwsManagedPolicyName('AWSIoTFullAccess'),
ManagedPolicy.fromAwsManagedPolicyName('AWSIoTDataAccess'),
ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')
],
});
// Lambda
const iotLambda = new lambda.Function(this, 'IoTLambda', {
code: lambda.Code.asset('src/lambda/iot_publish'),
handler: 'app.handler',
runtime: lambda.Runtime.NODEJS_10_X,
timeout: Duration.seconds(3),
role: apiRole,
environment: {
IOT_TOPIC: iotTopic,
},
});
// API Gateway
const api = new apigateway.RestApi(this, 'HomeControlApi', {
restApiName: 'HomeControlApi'
});
const integration = new apigateway.LambdaIntegration(iotLambda, {
proxy: true,
});
const controlResource = api.root.addResource('control');
controlResource.addMethod('POST', integration);
}
}
const app = new cdk.App();
new HomeControlStack(app, 'HomeControlStack');
app.synth();
import os
import configparser
import time
import json
import RPi.GPIO as GPIO
import logging
from logging import getLogger, Formatter, FileHandler
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
# Use PIN 7 (GPIO 4)
PIN_AIRCON_ON = 7
# programme finish trigger file
FINISH_FILE = 'finish.txt'
# logger setting
handler_format = Formatter('[%(asctime)s][%(name)s][%(levelname)s] %(message)s')
file_handler = FileHandler('main.log', 'a')
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(handler_format)
logger = getLogger(__name__)
logger.setLevel(logging.INFO)
logger.addHandler(file_handler)
def main():
logger.info('Start home controller')
init_gpio()
configs = parse_config_file()
logger.info(json.dumps(configs, indent=4))
# https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/sphinx/html/index.html
client = AWSIoTMQTTClient(configs['client_id'])
client.configureEndpoint(configs['endpoint'], configs['port'])
client.configureCredentials(configs['root_ca'], configs['private_key'], configs['certificate'])
client.configureAutoReconnectBackoffTime(1, 32, 20)
client.configureOfflinePublishQueueing(-1)
client.configureDrainingFrequency(2)
client.configureConnectDisconnectTimeout(10)
client.configureMQTTOperationTimeout(5)
client.connect()
client.subscribe(configs['topic'], 1, subscribe_callback)
while True:
time.sleep(5)
if is_finish():
os.remove(FINISH_FILE)
GPIO.cleanup()
logger.info('Finish home controller')
break
def init_gpio():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(PIN_AIRCON_ON, GPIO.OUT, initial=GPIO.HIGH)
def parse_config_file():
config = configparser.ConfigParser()
config.read('config.ini')
return {
'root_ca': config['AWS_IOT_CONNECT']['ROOT_CA'],
'private_key': config['AWS_IOT_CONNECT']['PRIVATE_KEY'],
'certificate': config['AWS_IOT_CONNECT']['CERTIFICATE'],
'client_id': config['AWS_IOT_CORE']['CLIENT_ID'],
'endpoint': config['AWS_IOT_CORE']['ENDPOINT'],
'port': int(config['AWS_IOT_CORE']['PORT']),
'topic': config['AWS_IOT_CORE']['TOPIC']
}
def subscribe_callback(client, userdata, message):
topic = message.topic
payload = json.loads(message.payload)
logger.info(f'from topic: {topic}')
logger.info(f'Received a new message: {json.dumps(payload, indent=4)}')
control(payload)
def control(params):
if is_control(params) == False:
return
if is_aircon_on(params):
logger.info('Execute PIN_AIRCON_ON')
execute(PIN_AIRCON_ON)
def execute(pin_no):
GPIO.output(pin_no, True)
time.sleep(0.5)
GPIO.output(pin_no, False)
time.sleep(0.5)
def is_finish():
if os.path.isfile(FINISH_FILE):
return True
return False
def is_control(params):
if params['command'] == '/control':
return True
return False
def is_aircon_on(params):
if params['target'] == 'aircon' and params['param'] == 'on':
return True
return False
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment