[PYTHON] "Amazon Dash Button" a atterri au Japon, mais j'ai osé le faire moi-même

DashButtonCover.jpg

Aperçu

L'autre jour, "Amazon Dash Button" est enfin sorti au Japon. Le fait est que lorsque vous cliquez sur le bouton, le produit cible sera automatiquement commandé par Amazon et livré à votre domicile. Faisons cela nous-mêmes cette fois! C'est un article à cet effet.

Ceux qui le comprennent comprendront, mais pour être exact, ceux qui disent "AWS IoT Button" qui est une version programmable de "Amazon Dash Button" Je pense que c'est proche.

structure globale

L'architecture globale est la suivante:

全体構成.png

  1. Appuyez sur le bouton attaché à Raspberry Pi Zero pour vous connecter à AWS IoT via MQTT.
  2. Le moteur de règles AWS IoT achemine les messages vers AWS Lambda.
  3. La fonction Lambda explore le site Web d'Amazon à partir de Selenium + PhantomJS et achète le produit spécifié.

J'expliquerai en détail à l'arrière du processus (dans l'ordre de 3-> 2-> 1).

1. Créez une fonction Lambda pour un achat automatique sur Amazon

Dans ce chapitre, nous utiliserons Selenium et PhantomJS pour explorer le site Web d'Amazon et créer une fonction Lambda qui achète automatiquement l'article spécifié.

Qu'est-ce qu'AWS Lambda?

http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html Lorsqu'AWS Lambda télécharge du code sur AWS Lambda, le service devient un service informatique qui utilise l'infrastructure AWS pour déléguer l'exécution du code.

Java, Node.js, Python, C # peuvent être sélectionnés pour l'exécution, mais cette fois, nous utiliserons Python.

Configuration du package

Placez le corps de la fonction Lambda et les bibliothèques nécessaires directement sous le répertoire du projet.

$ tree -L 1
.
├── amzorderer.py				#Corps de fonction Lambda
├── phantomjs					#Binaire PhantomJS
├── selenium					#Bibliothèque Selenium pour Python
└── selenium-3.0.2.dist-info

Référence: https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html

Installation de sélénium

Utilisez pip pour installer Selenium directement sous le répertoire du projet.

pip install selenium -t /path/to/project-dir

Installation de PhantomJS

Téléchargez la version Linux 64 bits de tar depuis PhantomJS Officiel et placez phantomjs sous le répertoire bin directement sous le répertoire du projet.

Créer une fonction Lambda

Le code source est également disponible ci-dessous. (Prévu pour être publié plus tard)

amzorderer.py


# -*- coding:utf-8 -*-

__author__ = 'H.Takeda'
__version__ = '1.0.0'

import os
import boto3

from argparse import ArgumentParser
from base64 import b64decode
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

# Amazon top page url.
AMAZON_URL = "https://www.amazon.co.jp"
# Amazon user id (email).
AMAZON_USER = boto3.client('kms').decrypt(
    CiphertextBlob=b64decode(os.environ['user']))['Plaintext']
# Amazon user password.
AMAZON_PASS = boto3.client('kms').decrypt(
    CiphertextBlob=b64decode(os.environ['password']))['Plaintext']
# User agent.
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/53 (KHTML, like Gecko) Chrome/15.0.87"
# Item dictionary.
ITEMS = {
    "01": "1fLhF7q",    # Toilet Paper
    "02": "fhYcbp7"     # Saran Wrap
}


def lambda_handler(event, context):
    # Create web driver for PhantomJS.
    dcap = dict(DesiredCapabilities.PHANTOMJS)
    dcap["phantomjs.page.settings.userAgent"] = USER_AGENT
    driver = webdriver.PhantomJS(desired_capabilities=dcap,
                                 service_log_path=os.path.devnull,
                                 executable_path="/var/task/phantomjs")

    # Get amazon top page.
    driver.get(AMAZON_URL)
    # Transition to sign in page.
    driver.find_element_by_id("nav-link-yourAccount").click()
    # Input user id.
    driver.find_element_by_id("ap_email").send_keys(AMAZON_USER)
    # Input user password.
    driver.find_element_by_id("ap_password").send_keys(AMAZON_PASS)
    # Sign in.
    driver.find_element_by_id("signInSubmit").click()
    # Select item.
    driver.get("http://amzn.asia/" + ITEMS[event["item"]])
    # Add to cart.
    driver.find_element_by_id("add-to-cart-button").click()
    # Proceed to checkout.
    driver.find_element_by_id("hlb-ptc-btn-native").click()
    # Order.
    # driver.find_element_by_name("placeYourOrder1")[0].click()
    driver.save_screenshot("hoge.png ")
    driver.quit()

En gros, je ne fais qu'une simple opération Selenium, mais je vais ramasser les points.

Déploiement des fonctions Lambda

archiver

Compressez le répertoire du projet. Le nom du fichier zip n'a pas d'importance.

$ zip -r upload.zip /path/to/project-dir/*

Paramètres de la fonction Lambda

Définissez la fonction Lambda à partir de la console de gestion AWS. Vous pouvez également télécharger le fichier zip créé ici.

Lambda Management Console.png

Test de fonction Lambda

Définissez l'événement de test (paramètre passé à la fonction Lambda) depuis Actions> Configurer l'événement de test, Appuyez sur le bouton Test pour exécuter la fonction Lambda.

Lambda Management Console2.png

C'est OK si le processus est terminé normalement. Ceci termine la création de la fonction Lambda qui achète automatiquement sur Amazon.

2. Paramètres AWS IoT

Dans ce chapitre, nous utiliserons AWS IoT pour accepter les requêtes MQTT et configurer les paramètres pour appeler la fonction Lambda créée ci-dessus.

Qu'est-ce qu'AWS IoT?

https://aws.amazon.com/jp/iot/how-it-works/ En utilisant AWS IoT, il est possible de connecter divers appareils à divers services AWS, de protéger les données et la communication, et d'effectuer des traitements et des actions sur les données des appareils.

Enregistrement de l'appareil

Enregistrez l'appareil qui se connecte à AWS IoT à partir de l'écran de la console AWS IoT.

  1. Passez à l'écran d'enregistrement à partir de "Premiers pas".

AWS IoT0.png   2. Sélectionnez les informations d'environnement pour le périphérique client. Cette fois, nous nous connecterons à AWS IoT à partir de Raspberry Pi Zero (OS: Raspbian) à l'aide du SDK Python.

AWS IoT4.png   3. Entrez un nom de périphérique arbitraire (raspi0 dans ce cas) et appuyez sur "Étape suivante".

AWS IoT5.png   4. Appuyez sur "Liux / OSX" pour télécharger la clé publique, la clé privée et le certificat client (vous les utiliserez plus tard). Cliquez sur "Étape suivante" pour passer à l'écran suivant.

AWS IoT7.png   5. La procédure de configuration de l'appareil apparaîtra, alors appuyez sur "Terminé" pour terminer.

Enregistrement des règles

Défini pour appeler la fonction Lambda lorsqu'un message est publié sur un sujet particulier.

  1. Passez à l'écran d'enregistrement à partir de "Créer une règle".

AWS IoT R1.png   2. Entrez un nom de règle arbitraire (amzorderer dans ce cas) pour définir la requête de règle. Lorsqu'un message est publié dans la rubrique "amzordere", il extrait la valeur de l'attribut d'élément et exécute l'action.

AWS IoT R2.png   3. Sélectionnez Appeler la fonction Lambda comme Action.

AWS IoT3.png   4. La fonction à appeler est le "amzorderer" créé précédemment.

AWS IoT R4.png   5. Cliquez sur "Créer une règle" pour terminer la création.

AWS IoT R.png

3. Créer une machine cliente

Dans ce chapitre, nous utiliserons Raspberry Pi pour créer un appareil client avec des boutons.

Qu'est-ce que Raspberry Pi Zero?

Inutile de dire que ce sera un petit modèle de Razpai. Avec une horloge CPU de 1 GHz et une mémoire de 512 Mo, le prix est exceptionnellement élevé à environ 5 $. Cette fois, en utilisant ce Raspberry Pi Zero, Je souhaite créer un appareil qui envoie une demande à AWS IoT en appuyant simplement sur un bouton.

Les choses nécessaires

Nous le fabriquerons en utilisant des pièces de travail électroniques de base que l'on trouve dans chaque foyer.

IMG_0307.JPG

Puisqu'il n'y a qu'un seul terminal miniUSB, il est pratique d'avoir un concentrateur USB au moment du réglage initial.

Configuration initiale de Raspberry Pi (installation du système d'exploitation)

Installez Raspbian (Jessie) en vous référant à Around here.

Connexion LAN sans fil

Cette fois, nous connecterons Raspberry Pi Zero au LAN sans fil à l'aide de l'unité esclave sans fil de Buffalo.

Connectez l'unité esclave LAN sans fil à l'USB. Si vous tapez la commande lsusb, vous pouvez voir qu'elle reconnaît l'unité esclave.

$ lsusb
Bus 001 Device 002: ID 0411:01a2 BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM Wireless LAN Adapter [Ralink RT8070]
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Utilisez la commande wpa_passphrase pour générer le SSID et le mot de passe requis pour une connexion LAN sans fil.

$ wpa_passphrase [SSID] [Mot de passe]
network={
        ssid=[SSID]
        #psk=[Mot de passe] <-Vous pouvez supprimer cette ligne
        psk=[Phrase secrète cryptée]
}

Copiez le texte ci-dessus et ajoutez-le à / etc / wpa_supplicant / wpa_supplicant.conf.

/etc/wpa_supplicant/wpa_supplicant.conf


country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid=[SSID]
        psk=[Phrase secrète cryptée]
}

Editez / etc / dhcpcd.conf et faites-en une adresse IP fixe. Définissez l'adresse IP, le routeur et le DNS en fonction de votre environnement.

interface wlan0
static ip_address=192.168.11.30/24
static routers=192.168.11.1
static domain_name_servers=192.168.11.1

Si vous pouvez redémarrer et connecter SSH à partir du vaisseau mère, le réglage est terminé.

$ sudo shutdown -r now

Soudure GPIO

Contrairement à d'autres modèles, lors de l'utilisation de GPIO avec Raspberry Pi Zero, une soudure est nécessaire. Puisque le travail sera plus fin que prévu, il est recommandé d'utiliser un alignement de soudure de φ0,6 mm.

IMG_0309.JPG

Construire un circuit

Honnêtement, le travail électronique est un amateur, mais je vais le construire en me référant aux informations que j'ai recherchées sur le net. La disposition GPIO de Raspberry Pi Zero est la suivante.

Raspberry-Pi-Model-Zero-Mini-PC.jpg

Il prend 3,3 V d'alimentation du n ° 1 et reçoit le commutateur ON / OFF du commutateur tactile GPIO25 sur GPIO9. Insérez une résistance de 10 kohms entre GPIO25 et GND. C'est ce qu'on appelle une résistance pull-down et joue un rôle dans la transmission fiable d'un signal HIGH (3,3V) ou LOW (0V). Je suis désolé que l'image soit difficile à comprendre.

S__2564101.jpg

Créer un programme

Maintenant que le circuit est assemblé, nous allons créer un programme qui reçoit l'entrée du commutateur tactile et publie le message sur AWS IoT.

Durée

Python 2.7 est installé dans Raspbian (Jessie), donc j'écrirai le programme en Python.

$ python -V
Python 2.7.9

Installation des bibliothèques requises

Le SDK Python pour la connexion à AWS IoT est ouvert au public et sera utilisé.

$ sudo pip install AWSIoTPythonSDK

la mise en oeuvre

publisher.py


# -*- coding:utf-8 -*-

__author__ = 'H.Takeda'
__version__ = '1.0.0'


from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
from argparse import ArgumentParser
import json
import logging
import RPi.GPIO as GPIO
import signal
import sys
import time


def configure_logging():
    # Configure logging
    logger = logging.getLogger("AWSIoTPythonSDK.core")
    logger.setLevel(logging.DEBUG)
    streamHandler = logging.StreamHandler()
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    streamHandler.setFormatter(formatter)
    logger.addHandler(streamHandler)


def parse():
    argparser = ArgumentParser()
    argparser.add_argument("-e", "--endpoint", type=str, required=True)
    argparser.add_argument("-r", "--rootCA", type=str, required=True)
    argparser.add_argument("-c", "--cert", type=str, required=True)
    argparser.add_argument("-k", "--key", type=str, required=True)
    args = argparser.parse_args()
    return vars(args)


def careate_client(endpoint, root_ca, cert, private_pey):
    # For certificate based connection.
    client = AWSIoTMQTTClient("raspi0")
    # Configurations
    client.configureEndpoint(endpoint, 8883)
    client.configureCredentials(root_ca, private_pey, cert)
    client.configureOfflinePublishQueueing(1)
    client.configureConnectDisconnectTimeout(10)    # 10 sec
    client.configureMQTTOperationTimeout(5)         # 5 sec
    return client


def handler(signum, frame):
    print "Signal handler called with signal", signum
    client.disconnect()
    GPIO.cleanup()
    sys.exit(0)


if __name__ == '__main__':
    # Parse command-line arguments.
    args = parse()
    # Configure logging
    configure_logging()
    # Create mqtt client.
    client = careate_client(
        args["endpoint"], args["rootCA"], args["cert"], args["key"])
    # Connect.
    client.connect()

    signal.signal(signal.SIGINT, handler)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(9, GPIO.IN)
    before = 0
    while True:
        now = GPIO.input(9)
        if before == 0 and now == 1:
            # Create message.
            message = {"item": "01"}
            # Publish.
            client.publish("amzorderer", json.dumps(message), 0)
            print "message published."
        time.sleep(0.1)
        before = now

Nous publions un message (valeur de classification d'article "01" pour l'achat de papier toilette) sur AWS IoT lorsque GPIO 9 est entré à l'aide de RPi.GPIO.

Contrôle de fonctionnement

Exécutez le script ci-dessus sur Rapsberry Pi Zero et vérifiez l'opération. Spécifiez le point de terminaison AWS IoT, l'autorité de certification racine, le certificat client et le chemin de la clé privée dans les arguments du script. Bien qu'il soit décrit dans le fichier README de AWS IoT SDK, l'autorité de certification racine est ici. Obtenu à partir de /content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem). Qu'est-ce qu'un certificat client? La clé privée est incluse dans le zip téléchargé lorsque vous configurez AWS IoT.

$ python test.py -e <endpoint> -r <rootCA path> -c <certificate path> -k <private key path>
2016-12-11 08:15:31,661 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Paho MQTT Client init.
2016-12-11 08:15:31,664 - AWSIoTPythonSDK.core.protocol.mqttCore - INFO - ClientID: raspi0
2016-12-11 08:15:31,667 - AWSIoTPythonSDK.core.protocol.mqttCore - INFO - Protocol: MQTTv3.1.1
2016-12-11 08:15:31,672 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Register Paho MQTT Client callbacks.
2016-12-11 08:15:31,675 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - mqttCore init.
2016-12-11 08:15:31,680 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Load CAFile from: root-CA.crt
2016-12-11 08:15:31,683 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Load Key from: raspi0.private.key
2016-12-11 08:15:31,687 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Load Cert from: raspi0.cert.pem
2016-12-11 08:15:31,691 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Custom setting for publish queueing: queueSize = 1
2016-12-11 08:15:31,696 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Custom setting for publish queueing: dropBehavior = Drop Newest
2016-12-11 08:15:31,699 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Set maximum connect/disconnect timeout to be 10 second.
2016-12-11 08:15:31,704 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Set maximum MQTT operation timeout to be 5 second
2016-12-11 08:15:31,710 - AWSIoTPythonSDK.core.protocol.mqttCore - INFO - Connection type: TLSv1.2 Mutual Authentication
2016-12-11 08:15:32,384 - AWSIoTPythonSDK.core.protocol.mqttCore - INFO - Connected to AWS IoT.
2016-12-11 08:15:32,386 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Connect time consumption: 70.0ms.

Lorsque j'ai appuyé sur le commutateur tact, un message a été publié sur AWS IoT et l'achat de "papier toilette" a été effectué avec succès sur Amazon.

Ce que je voulais faire

Recommended Posts

"Amazon Dash Button" a atterri au Japon, mais j'ai osé le faire moi-même
Quand j'ai essayé de créer un VPC avec AWS CDK mais que je n'ai pas pu le faire
J'ai fait de mon mieux pour créer une fonction d'optimisation, mais cela n'a pas fonctionné.
J'ai créé un bouton Amazon Web Service Dash
ForeignKey est défini pour CustomUser spécifié dans AUTH_USER_MODEL dans Django, mais il n'est pas référencé.
Je veux faire la transition avec un bouton sur le ballon
Comment utiliser Decorator dans Django et comment le créer
Python: peut être répété en lambda
J'ai introduit le noir dans vscode, mais il n'est pas automatiquement formaté