• Português
  • English
  • Español
  • Arquitetura Serverless em Cloud para uma aplicação IoT

    Por: em 13 de dezembro de 2017

    O desenvolvimento de soluções na área de Internet das Coisas é extremamente multidisciplinar. Para a implementação de uma boa aplicação, além da stack de software, outras escolhas importantes precisam ser feitas, como o hardware que irá rodar a aplicação, os protocolos de comunicação para troca de dados e arquitetura de nuvem que será utilizada. Essas escolhas devem ser pensadas seguindo critérios de escalabilidade, disponibilidade, baixa latência, proteção e autenticação dentre outros, sempre levando em conta restrições impostas pelo hardware geralmente encontrada nos sistemas embarcados.

    Partindo do ponto de vista de desenvolvimento de MVPs em um ambiente de inovação no melhor estilo move fast and break things, garantir níveis satisfatórios nesses critérios pode tomar um tempo precioso de implementação, sendo a utilização de ferramentas comerciais uma excelente escolha. Neste post traremos um exemplo simples utilizando ferramentas disponibilizadas pela AWS (Amazon Web Services) que facilitam e agilizam o desenvolvimento de soluções em nuvem.

    Nosso projeto será um registro de acesso a ambientes baseado em reconhecimento facial, para isso usaremos do ponto de vista de hardware uma Raspberry Pi3 com o módulo de câmera e do ponto de vista de serviços em nuvem S3, DynamoDB, Lambda e Rekognition da AWS. Como há muita documentação e exemplos de implementações de algoritmos de aquisição de imagens e detecção de faces para Raspberry Pi e nosso foco é a arquitetura em si, daremos atenção à configuração de ambiente e execução do algoritmo em nuvem utilizando uma arquitetura serverless.

    Para o ambiente cloud usaremos todos os serviços baseados na região US East -North Virginia, dada a restrição de disponibilidade do Rekognition na região de São Paulo. A seleção de região pode ser feita na página inicial do AWS Console, conforme a Figura 1.


    Figura 1 – Mudança de Região

    O primeiro serviço que iremos configurar será o DynamoDB­ o serviço de banco de dados No-SQL da AWS. A configuração do serviço é tão simples quanto criar uma tabela, para isso basta procurar pelo nome serviço na página inicial do AWS Console. Na página seguinte clique em Create Table, a seguir preencha o campo Table Name com o nome da sua tabela (no exemplo log-controle-de-entrada) e o campo Primary Key com o nome da chave primária. No nosso exemplo, a chave primária será composta do Timestamp e um identificador único para cada pessoa. Para a criação da chave primária composta basta selecionar a caixa Add Sort Key. O resultado final pode ser visto na Figura 2. Após a criação da tabela aparecerá um dashboard, anote o valor do campo Amazon Resource Name (ARN) ele será necessário posteriormente para o provimento de permissão.



    Figura 2 – Criação de tabela no DynamoDB

    O passo seguinte é a configuração do serviço AWS Lambda, um serviço que permite a execução de código em nuvem sem a necessidade de provisionamento e manutenção de servidores. Na página inicial do serviço clique em Create Function, na tela seguinte marque a opção Author from Scratch. No espaço inferior no campo Name dê um nome para a sua função (log-de-entrada no exemplo), escolha uma das linguagens disponíveis para implementação, no nosso caso python 3.6. A próxima etapa consiste no provimento de acesso do nosso script a outros serviços AWS, para isso, no campo Role selecione Create New Role from Template(s), essa opção abre mais dois campos, dê um nome para o conjunto de permissões em Role Name e em Policy Templates selecione os seguintes campos: Amazon Rekognition read-only permissions, Amazon Rekognition write-only permissions, S3 object read-only permissions. As configurações devem estar semelhantes às encontradas na Figura 3. Clique em Create Function e a função será criada.

     


    Figura 3 – Criação de Role para permissão de acesso a serviços AWS
     

    Nosso script ainda necessita de acesso ao serviço DynamoDB, este tem que ser feito manualmente. Para isso vá na página inicial do AWS Console e procure por IAM. No dashboard do IAM clique em Roles e procure o Role criado na etapa anterior. Na tela clique em Add Inline Policy, selecione Policy Generator e clique em Select, conforme mostrado na Figura 4. Na próxima página selecionaremos o serviço Amazon DynamoDB, em Actions selecione GetItem, ListTables, UpdateItem e PutItem. Finalmente em Amazon Resource Name, use o valor do ARN do DynamoDB criado na seção anterior. Clique em Next Step e posteriormente em Apply Policy. Pronto, todas as permissões necessárias foram garantidas

     


    Figura 4 – Adição de Inline policy no Role criado

    Antes de implementar a função Lambda em si, configuraremos o AWS S3, um serviço de armazenamento remoto. Para isso, vá a página inicial do AWS Console e procure pelo serviço S3, para isso vá até a home do AWS Console e procure pelo serviço S3. Na página inicial do serviço, clique em Create Bucket, escolha um nome para o Bucket (imagens-de-log no nosso exemplo), utilize as configurações padrões até a criação do Bucket. Já temos onde armazenar nossas imagens, mas precisamos criar um Trigger para ativação do nosso script. Para isso clique no Bucket recém criado e vá até a aba Properties, clique em Events e em Add Notification, conforme Figura 5, dê um nome para o evento e escolha Put dentre os Events Listados. No campo Send To, escolha Lambda Function e no campo inferior, escolha a função recém-criada. Clique em Save.



    Figura 5 – Criação de Trigger no Bucket S3

    Quanto ao reconhecimento facial, utilizaremos o serviço Rekognition da AWS. A configuração do serviço é provida através de um console, mas pode ser facilmente realizada através de APIs como o pacote para linguagem python chamado Boto3. O serviço permite a criação de Collections, um conjunto para armazenamento de faces conhecidas. A criação de collections é facilmente realizada utilizando a função create_collection. Igualmente fácil é a inserção de faces conhecidas na Collection, feita pelo comando index_faces.

    Temos todos os serviços já configurados e podemos implementar o script. Abaixo temos um exemplo do script que utilizamos, ele leva em conta a criação existência e configuração de uma Collection no serviço Rekognition.

    Agora basta começar a enviar as imagens diretamente para o Bucket S3 criado (imagens-de-log) e esperar a tabela criada no DynamoDB ser preenchida com os dados das pessoas reconhecidas pela câmera, como demonstrado na Figura 6.


    Figura 6 – Preenchimento da Tabela com a identidade das pessoas reconhecidas pelo sistema

     

    import boto3

    import os

    import sys

    import time

    import logging

     

     

    s3_client = boto3.client('s3')

    client_rek = boto3.client('rekognition')

     

    AUTHORIZED_COLLECTION_ID = 'aws-iot-face-lab-authorized'

     

    DOOR_LOG_DYNAMO_DB = 'log-controle-de-entrada'

     

    def get_table(tablename=DOOR_LOG_DYNAMO_DB):

        dynamodb = get_dynamo_resource()

        return dynamodb.Table(tablename)

     

    def get_dynamo_resource():

        return boto3.resource('dynamodb')

     

    def get_s3_client():

        return boto3.client('s3')

     

    def get_rekognition_client():

        return boto3.client('rekognition')

     

    def get_dynamo_table(tablename=DOOR_LOG_DYNAMO_DB):

        dynamodb = get_dynamo_resource()

        return dynamodb.Table(tablename)

     

    def lambda_handler(event, context):

       

        logger = logging.getLogger()

        logger.setLevel(logging.INFO)

       

        dyn_table = get_table(DOOR_LOG_DYNAMO_DB)

     

        rek_client = get_rekognition_client()

     

        for record in event['Records']:

            bucket = record['s3']['bucket']['name']

            s3_object = record['s3']['object']

            key = record['s3']['object']['key']

            # download_path = '/tmp/{}{}'.format(uuid.uuid4(), key)

            # upload_path = '/tmp/resized-{}'.format(key)

     

            # s3_client.download_file(bucket, key, download_path)

            # resize_image(download_path, upload_path)

            # s3_client.upload_file(upload_path, '{}resized'.format(bucket), key)

            logger.info('got event{}'.format(record))

            aws_rekognition_Id = None

            aws_rekognition_ExternalId = None

            rek_image = {

                'S3Object': {

                'Bucket': bucket,

                'Name': key

                    }

                }

            rek_Search = rek_client.search_faces_by_image(CollectionId=AUTHORIZED_COLLECTION_ID,

                                                      FaceMatchThreshold=60,

                                                      Image=rek_image)

            if rek_Search['FaceMatches']:

                # Selects the face of greather similarity

                aws_rekognition_Id = rek_Search['FaceMatches'][0]['Face']['FaceId']

     

            if rek_Search['FaceMatches'][0]['Face']['ExternalImageId']:

                aws_rekognition_ExternalId = rek_Search['FaceMatches'][0]['Face']['ExternalImageId']

                # logger.info('Face in ' + filename + ' recognized as ' + aws_rekognition_Id + ' rek id')

     

            if aws_rekognition_Id:

                if aws_rekognition_ExternalId:

     

                    response = dyn_table.put_item(Item={

                                            'timestamp':int(time.time()),

                                            'rekognition_Id':str(aws_rekognition_Id),

                                            'external_Id':str(aws_rekognition_ExternalId)

                                            })

    13 de dezembro de 2017

    Filtre por mês

    Filtre por autor