Created
August 4, 2019 13:41
-
-
Save cm-fujii/c1a435a907346ea2aa18404c5564be05 to your computer and use it in GitHub Desktop.
HomeControl 1st
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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