Smarthome

Meu interesse por IoT não é recente. Desde muito tempo atrás, eu já planejava fazer de minha casa uma Smarthome. Mas, nesta época, logo quando comecei a pesquisar sobre o assunto, tínhamos poucas opções no Brasil. Não lembro se o Arduino já existia na época, acredito que não. Muito menos Raspberry, ESP8266 e por aí vai. Existiam poucas opções no Brasil. Lá fora, entretanto, a história era diferente. O mercado já estava aquecido e lembro de ter visto diversos padrões emergindo. Só que importar para o Brasil tudo isso não era uma opção viável, devido ao alto custo. Daí, larguei meu sonho de lado.

Agora, voltemos ao ano de 2016. Tenho tudo em minhas mãos para começar a botar em prática tudo isso. Só me faltava, agora, aprender um pouco sobre Arduino, Raspberry, eletrônica, eletricidade, etc. E 2016 serviu para isso. Agora, em 2017, chegou a hora de colocar tudo em prática. Tenho várias ideias para minha casa e já comecei a implementar algumas.

Tentarei compartilhar, aqui no blog, todos esses projetos à medida que vou projetando-os e colocando-os em “produção”. Aqui, começo com uma lista das ideias que tenho em mente. Curtiu as ideias? Tem alguma ideia pra me dar? Sugestões? Deixa aí nos comentários e vamos trocar ideias. Vamos lá:

Fitas LED RGB Quintal

A questão é simples: tenho fitas de LED em RGB e, atualmente, as deixo ligadas 24 horas. Para mudar a cor das fitas, preciso de um controle remoto e uma ação deliberada minha de ir lá e mudar a cor. Chato. Aqui entra meu primeiro projeto, talvez o mais simples de todos: controlar o acendimento e a cor das fitas conforme variáveis externas, como temperatura, dia da semana ou qualquer outro evento de meu interesse.

Este projeto, na verdade, já está em 90%. Atualmente, as luzes acendem e apagam no horário marcado e a cor depende apenas do dia da semana. Para ficar mais incrementado, precisa ainda se integrar com o restante das informações da casa (temperatura, por exemplo). Vou demonstrar como fiz isso em um post futuro, logo logo.

Relés para Luzes e Equipamentos Eletrônicos

Basicamente, quero controlar toda a parte elétrica da casa através de relés Wifi, cada um comandado por um ESP8266 conectado ao meu broker MQTT. No momento, faço o controle de algumas partes, como a fonte luminosa, que antes ficava ligada 24 horas e agora liga às 9 da manhã e desliga às 21h. A ideia é super simples e deveria ser a mais fácil de ser implantada. Mas não é tão simples assim quando você mora em uma casa que foi construída em 1964, que tem 386m2 e a instalação elétrica é antiga, com fios rígidos e caixas e tubos de metal. 🙁

Inicialmente, preciso refazer toda essa parte elétrica, mas o custo é altíssimo e não dá para ser feito agora, ainda mais com a pequena Valentina com apenas 3 meses de idade. Ou seja, no momento, vou controlar alguns pontos específicos da casa, mas aproveitarei a reforma da parte elétrica para deixar os relés em seus devido lugares! 🙂

Controle Automático de Portas e Janelas

Esse pode parecer um projeto que farei só para “tirar onda”, mas lembre-se do que escrevi acima: a casa tem 386m2. Tenho muitas portas e janelas aqui e abrir todas pela manhã para ventilar os cômodos e depois sair fechando tudo a cada noite é um trabalho chato para um preguiçoso assumido como eu. Então, vou sim controlar todas portas e janelas remotamente! 🙂

Bom, mas aqui tenho um problema, amigão! Minhas portas são antigas, de madeira maciça. Os projetos que vemos na internet usam motor de vidro de carro e tal. A ideia é boa, mas não vai funcionar pra mim, pois as portas são pesadas. Fora isso, existe a questão da segurança da casa, pois não é meramente abrir e fechar, mas também travar as portas. O que pode me ajudar, aqui, são os atuadores lineares (pistão elétrico). O único porém é o preço! Já fiz umas cotações e para fechar uma das portas, preciso de um atuador que custa 530 reais. Vai doer no bolso, mas vou fazer! kkk!

Já para as janelas, a história é diferente, pois tenho muito mais janela que portas e, embora os atuadores sejam a melhor solução de forma geral, o custo é proibitivo. Então, neste caso, eu vou de motor de vidro elétrico de carro mesmo, pois elas não são pesadas e dá para bolar um mecanismo de travamento mais simples.

Nível de Água nos Tanques

Este é um projeto que talvez não faça muito sentido caso você more em um apartamento, mas faz muito sentido para quem mora em uma casa. Tenho dois tanques e, nesta época em que há muita falta de água e a Embasa as vezes corta a distribuição de água sem muito aviso prévio, as vezes fico todo ensaboado debaixo de um chuveiro que só cai um pingo de água a cada 1 segundo. Mas minha ideia não é apenas saber o nível de água nos tanques, mas também a vazão da água que está chegando na casa.

Não sei por qual motivo, mas minha conta de água de tempo em tempo vem um murro de soqueira no queixo. A Embasa diz que é problema dentro de minha casa. E deve ser mesmo, só que não sei qual é. Esse controle vai me ajudar a identificar esses problemas e tomar uma ação preventiva ao invés de reativa. Aliás, é meu projeto atual e que também vou detalhar em posts futuros!

Agora imagine a situação: a água do tanque atinge um nível crítico e eu recebo push notification, SMS, email, as luzes RGB começam a piscar na cor vermelha… kkk, vai ser uma papagaiada só, espie!

Notificação de Campainha

Visualize a seguinte situação: você está no trabalho, chegam os Correios na sua casa, a campainha toca e… não tem ninguém lá para receber sua encomenda. Raios! Mas, e se eu tivesse uma campainha que me avisasse que tem gente lá, me enviasse uma foto ou até um link para meu circuito de Cftv (nem tenho ainda, mas terei) para eu ver quem está lá. Para fechar com chave de ouro, porque não um alto falante pra eu mandar um recado de voz pro cara que está lá remotamente? “Amigão, entrega essa encomenda aí na casa do vizinho, que é a casa de meu pai” (e é mesmo, viu!). Sucesso!

Porta de Entrada

Esse projeto aqui é, vou admitir, só pra tirar a maior onda mesmo. Mas quero fazer, pois envolve desafios de segurança. Minha ideia é que a porta de entrada para a casa também possa ser controlada remotamente, além de permitir a entrada por biometria ou outras formas, como NFC. A questão de segurança aqui é o que mais me preocupa, pois não dá para ter uma falha nesse aspecto, ou então a casa fica exposta para os meliantes. Mas vai rolar, sim. Vai ser tenso, mas vou fazer. 🙂

Com esse projeto, posso aposentar as chaves de entrada, autorizar o acesso temporário de pessoas pela digital e por aí vai. Vai ficar lindo!

Consumo de Energia

Minha ideia aqui é controlar o consumo de energia on the fly. Quero saber os horários de maior consumo, ser notificado quando ocorrerem picos, ter uma “prévia” do consumo até um determinado momento e por aí vai. Claro, no momento, estou esbarrando na minha instalação elétrica da época de Judas, mas já dá para implementar uma fase inicial.

Circuito Cftv

Bom, esse aqui não é bem um projeto que envolve Arduino, NodeMCU e tal, mas que vai fazer parte do todo. Quero colocar um circuito de Cftv na casa já faz um tempo. Nem é tanto por questão de segurança, pois moro nesta rua há mais de 30 anos e nunca sofremos tentativas de assalto por lá. A questão é que tem uma negada má intencionada que joga veneno para os animais das casas. Com uma criança pequena em uma casa, também é importante ter um monitoramento como esse. Sem contar a questão da segurança mesmo, nunca se sabe quando e onde um meliante pode resolver assaltar. A questão também é que o circuito de Cftv vai fazer parte do todo, pois provê insumos para a rede inteira.

Irrigação de Plantas

Eu sou preguiçoso, lembra? Então, pronto. Já comecei me justificando, porque minha ideia é irrigar a horta de forma automática, com sensor de umidade de solo e os escambau. Pronto, nem vou me alongar mais aqui. 😛

Mini Estação Meteorológica

A ideia aqui não é ter uma estação meteorológica avançada, mas sim uma pequena estação que vai fornecer insumos para outras ações dentro da casa. Ainda não sei direto como fazer, onde vai ficar e tal. Estudarei sobre isso futuramente.

E chegamos ao final! Minha ideia é implementar TODOS esses projetos por conta própria. Então, caros amigos que trabalham com isso e querem vender seus produtos prontos: não tenho interesse, tá? 🙂

Futuramente, não tão distante assim, começo os posts sobre cada um desses projetos, conforme eu for fazendo-os! Curtiu? Deixa seu comentário aí com ideias!

D-Link Powerline

Recentemente, comprei um D-Link Powerline para distribuir minha internet pela casa usando a rede elétrica. O bicho é fácil de instalar e praticamente basta conectar o adaptador (no meu caso, o modelo DHP-W208AV) ao roteador de sua operadora (que tem a internet) e coloca-lo em uma tomada. Depois disso, é só ligar o extensor, no meu caso o DHP-W220AV, em uma outra tomada onde você quer que a internet seja distribuída tanto por WiFi como por cabos.

No geral, gostei do produto. Até aqui, está funcionando muito bem. Quando conecto o computador por cabo, diretamente no extensor, a velocidade é praticamente a máxima (tenho Vivo Fibra 50mb). Quando conecto via WiFi, temos uma perda natural deste meio e consigo cerca de 30mb de taxa de download e 15mb de taxa de upload.

Um problema que reparei foi a minha instalação elétrica. Tenho uma instalação antiga, com fios rígidos, bem antigos. Já fiz um upgrade nessa instalação, mas não deu para substituir todos os fios. Notei que a internet fica muito lenta quando conecto o extensor em uma tomada com os fios antigos. Já nas tomadas com a fiação nova, a internet fica ótima.

Outro problema que me deparei foi a configuração do extensor. Ele vem com as configurações de fábrica e caso você queira trocar o SSID ou a senha do WiFi, por exemplo, terá uma boa dor de cabeça, pois o manual é muito ruim neste aspecto. Basicamente, o manual informa que você deve conectar na rede sem fio do extensor e digitar o endereço 192.168.0.50 para acessar a área de administração do extensor. Nada feito. Não funciona desse jeito.

Para resolver este problema, você deve configurar o IP de sua máquina MANUALMENTE e colocar um IP na faixa de IPs 192.168.0.*. Provavelmente, sua máquina vem configurada por padrão para obter IPs através de DHCP. Desta forma, quem vai atribuir um IP para sua máquina será seu roteador central (provavelmente, o roteador que a operadora te deu). Por exemplo, eu coloquei minha máquina com o IP 192.168.0.51. Após isto, você perderá acesso à internet, mas conseguirá acessar a área de administração do extensor. Após configurá-lo, lembre-se de voltar a configuração para obter IPs através de DHCP.

Desabafo

O objetivo desta postagem é puramente desabafar. Só isso. Alguns chamam isso de #mimimi. Então, é isso. Vou #mimimizar. A questão é que a cada dia fico mais impressionado com a diferença de tratamento que existe entre empresas com base no Brasil e empresas que não atuam diretamente no nosso mercado. Sendo mais específico, estou impressionado pela diferença que existe quando ocorre algum um problema com o produto que compramos. Para você entender melhor, vamos a alguns exemplos que aconteceram comigo.

Caso 1: Mochila da Case Logic

Este caso ocorreu há alguns anos atrás, quando comprei uma mochila da Case Logic na loja Papel & Cia. Com apenas uma semana de uso, a mochila apresentou pontos onde a costura estava se desfazendo. Não tentei levar para a loja para realizar a troca, ao invés disso, achei que deveria avisar isso diretamente para a fabricante. Assim, enviei um email para a representante da Case Logic no Brasil, informando o problema e enviando fotos do produto danificado, assim como a nota fiscal de compra.

Após 1 semana, não obtive qualquer resposta. Resolvi, então, enviar um email para a Case Logic americana. Obtive uma resposta no mesmo dia. Eles apenas me pediram para enviar fotos do produto, incluindo uma foto de um código de barras que fica escondido, dentro da mochila (provavelmente para verificar se não era produto falsificado). Após fazer isso, recebi uma resposta no dia seguinte com o código de rastreamento da nova mochila que eles me enviaram, de lá dos Estados Unidos.

Uma semana após, a mochila zerada, novinha em folha, chegava em minhas mãos. Eles enviaram com frete prioritário, tudo pago. Coincidentemente, no mesmo dia, o representante da Case Logic no Brasil respondeu meu email. Abaixo está a resposta deles. É sério mesmo. Isso aí é um Copy & Paste da resposta deles (removi qualquer referência a pessoas ou endereços da empresa).

Bom dia Marlon.
O seu produto deve ser enviado via PAC ou SEDEX para: … (removido)

A/C SETOR DE QUALIDADE E SAC

Favor redigir carta a punho (escrever manualmente) e nos enviar (Original), contendo:

– Descrição problema;
– Histórico do produto;
– Onde foi adquirido;
– Quando foi adquirido;
– Cópia do cupom/nota fiscal de compra;
– Nome completo;
– RG e CPF;
– Seu endereço (destino para troca).
– Nº de telefone celular, residencial e e-mail .

Obs: Nos casos em que o conserto não é possível, sua carta será usada para ser escriturada no setor fiscal, liberando crédito para pedido de troca em garantia a ser realizado pelo setor comercial.
Informamos ainda, que os prazos para as realizações dos consertos continuam os mesmos: 30 dias e a devolução será feita via PAC para o endereço de preferência do cliente. Caso a(s) peça(s) para conserto não esteja(m) disponível (is) em estoque, este prazo será postergado até o recebimento da respectiva(s) por processo de importação.

O departamento de Qualidade terá até 5 dias úteis para entrar em contato após o recebimento do seu produto e a sua  carta.

Isso aí mesmo. Eu teria que arcar com os custos de frete para enviar o produto para eles. Após isso, deveria aguardar aproximadamente 35 dias para eles me darem uma resposta se seria possível consertar o produto. Exatamente. Eles não me enviariam um novo. No máximo, um reembolso. E olhe lá!

Caso 2: Nerd Factory e TFury

Quando o dólar não era tão caro, eu comprava várias camisas da loja TFury. Eles tem um esquema bem legal, onde cada dia tem uma camisa com estampa diferente e o valor era de meros 9 dólares. A camisa é de excelente qualidade. Em uma dessas compras, o produto ficou preso na alfândega e nunca chegou em minha casa.

Entrei em contato com a TFury informando o problema e eu juro que esperava uma resposta do tipo: Senhor, não podemos fazer nada, pois isso é um problema da alfândega do seu país. Eu acho essa resposta até justa e caso essa fosse a resposta, eu não reclamaria. Mas, nada disso. A resposta deles foi rápida e já contendo o código de rastreamento da nova camisa que eles tinham acabado de enviar. Assim, rápido e sem perguntas.

Agora, vamos ao caso da Nerd Factory. Recentemente, comprei várias camisas com eles, mas uma estava errada, no tamanho errado. Enviei um email relatando e a resposta deles foi que eu deveria enviar a camisa de volta para eles e só então eles iriam verificar se realmente havia algum problema e então me enviariam uma nova. Burocracia ma veia, negão! Não enviei e dei a camisa para minha esposa. Ponto final.

Caso 3: Amazon

Meu pai comprou um Kindle logo quando ele foi lançado. Era um daqueles grandões, que tinha um stick pra você movimentar as páginas e navegar nos menus. Após 1 ano de uso, esse stick quebrou. Meu pai enviou um email para eles e, como ele não sabe inglês, usou o Google Translator. A resposta veio rápida e eles pediram que entrasse em contato por telefone, através de um número gratuito. Fizemos isso e a Amazon perguntou apenas poucos detalhes sobre o produto e logo em seguida informou que um novo Kindle seria enviado o mais rápido possível. O novo Kindle, zerado, chegou pouco tempo depois.

Esse novo Kindle voltou a apresentar o mesmo problema, com um ano de uso, mas dessa vez não relatamos o problema, já que meu pai já tinha adquirido um Kindle mais recente e bem melhor que o trambolho inicial. Uma burocracia super simples. Só ligar para eles para eles fazerem perguntas básicas. O inglês poderia ter sido um problema, mas estão desculpados, já que a Amazon, nesta época, ainda não havia chegado ao Brasil.

Caso *: Vários outros

Já tive problemas com várias empresas. Com os Correios? Nem preciso comentar, né? Através de minhas redes sociais vocês já viram o quanto reclamo dessa porcaria de empresa. Já tive problemas parecidos com: Submarino, Americanas, e dezenas de lojas online.

Conclusão

Eu poderia relatar outros problemas, já que enfrentei vários, mas vou parar por aqui. A conclusão que tenho é que nossas empresas assumem que estamos mentindo. Sempre. Para eles, o consumidor nunca tem razão e com 99% de chances, só quer fuder com eles. Em contraste, as empresas gringas não ligam se você quer sacanear eles ou não. Eles assumem esse risco. Obviamente, existirão aqueles que querem sacanear mesmo, mas eles assumem esse prejuízo considerando que é o preço que devem pagar para terem clientes honestos, fiéis e satisfeitos. Enfim, é questão cultural. Está enraizado em nós. 

Tradução: Docker Salvador

Ainda não havia comentado aqui no blog, mas agora também sou organizer da comunidade Docker Salvador. Quem me acompanha nas redes sociais já sabe o quanto venho comentando sobre essa ferramenta e o quanto a venho estudando. A oportunidade de me tornar membro ativo dessa comunidade surgiu há pouco tempo, quando Mario Jorge recebeu um convite e me convidou também para fazer parte dessa comunidade. Claro que eu aceitei e bati um papo legal com Michelle Antebi, a Manager de comunidades na Docker, que selou minha participação no grupo.

Bom, deixando de muita conversa, esse post é, na verdade, uma chamada para a comunidade que também gosta de Docker para nos ajudar a adicionar legendas para alguns dos vídeos da DockerCon 2016. Quase todas as palestras (senão todas) estão disponíveis no Youtube e sugiro que assistam! Bom, mas nem todos tem fluência na língua inglesa para entender um nativo falando, certo? É aí que nós entramos, tentando traduzir esses vídeos para vocês.

Mas, se você já fala inglês e pode nos ajudar nessa empreitada, não se sinta acanhado! Venha nos ajudar! 🙂 O primeiro vídeo está nesse link aqui e no título desse post. Escolhi primeiro a palestra Docker for Developers por pura conveniência, já que sou desenvolvedor. Mas a ideia é ir traduzindo outros vídeos também. Este vídeo está aberto para adição e edição de legendas, então é só entrar lá e editar alguma tradução que eu possa ter feito de forma errada. Já temos cerca de 11 minutos traduzidos. Aliás, o cara é francês e as vezes é difícil entender o “inglês” dele. hehehe.

Para editar, clique no botão de configurações, conforme a imagem abaixo:

1

Depois, clique em Legendas/CC e você verá a tela abaixo. Agora, clique em Adicionar Legendas.

2

Por enquanto, este vídeo encontra-se em minha conta, mas em breve vou criar uma página do Docker Salvador no G+ e colocar esses vídeos com as traduções nessa conta. Outro detalhe é que entrei em contato com o pessoal de comunidades da Docker solicitando autorização para fazer essas traduções e publicação em outras contas no Youtube. A resposta foi um SIM grande. Ou seja, não se preocupem com copyright e afins.

Ah! Em breve, faremos vários eventos nas faculdades aqui de Salvador, fiquem ligados! 🙂

 

Dispenser de MMs – Parte 1

Demorei mas, enfim, iniciei no mundo Arduino e Raspberry Pi. Na verdade, comecei pelo último, já que ainda sequer liguei o Arduino. Elegi como meu primeiro projeto uma ideia que tinha visto no DevFest São Paulo de 2015: um dispenser de MMs feito pelo Luis Leão. Achei a ideia bem bacana, divertida e, principalmente, didática. Minha ideia é levar esse projeto para os próximos eventos do GDG Salvador como uma forma de estimular os estudantes a entrarem nesse mundo também, afinal de contas, se um zé ruela como eu que nunca mexeu com eletrônica conseguiu, por que não eles também?

Nesse post, não vou dar detalhes muito técnicos. Vou passar mais pelos problemas e as soluções que encontrei. Caso você não queira ler tanto blá blá blá, sugiro visitar o post mais técnico (Parte 2), onde vou direto ao ponto, mostrando como montei as partes, as peças, as conexões com o Raspberry e por aí vai. Digamos que esse post aqui é mais filosófico. 😛

A Ideia

Vamos começar explicando a ideia. Meu objetivo era ter um dispenser que checaria por tweets e procuraria por uma determinada hashtag (configurável). Quando encontrasse essa hashtag, o dispenser liberaria MMs em um copo. No projeto do Luis Leão, ele usou um dispenser que já continha um sensor e um mecanismo de abertura que libera os doces (figura abaixo). Nesse caso, ele conectou o Raspberry a esse mecanismo, de forma que o sensor estivesse ativo apenas caso ele encontrasse os tweets. Caso não encontrasse os tweets, ele desligava o sensor, então, não adiantava encostar as mãos, pois ele estaria desativado.

229862204589c

Minha ideia inicial era usar o mesmo dispenser, mas… não o encontrei aqui no Brasil. Tem aos montes no exterior, como no eBay, Amazon e AliExpress, mas o custo total, com taxas de importação, daria uns 200 reais ou mais. Totalmente inviável. Mas não me dei por vencido e tentei encontrar algum outro dispenser que servisse aos meus propósitos. Infelizmente, não encontrei nenhum com sensor ou abertura automática. Foi então que me dei conta que eu precisava fazer tudo, desde o sensor de proximidade até a abertura do reservatório. Dessa forma, pesquisando no Mercado Livre, cheguei ao dispenser da imagem abaixo e pude começar minhas brincadeiras.

dispenser-porta-cereal-prata-zevro

Desafios

Os desafios que eu tinha com esse dispenser se resumiam a:

  • Como vou girar as pás de forma a liberar os MMs?
  • Qual sensor uso para checar se tem uma mão ou um copo próximo?
  • Como vou conectar tudo isso no dispenser?
  • Boto um LCD?
  • Como faço tudo isso de forma que o resultado final não fique uma bagunça?

Alguns destes desafios se mostraram até fáceis demais, vamos a eles.

Girar as Pás

Esse foi o primeiro problema que resolvi encarar, afinal, se eu não conseguisse girar as pás, de nada adiantaria ver os demais desafios. Logo de cara, assim como você também deve ter pensado, pensei em solucionar o problema com um servo motor. Usei um que veio no kit que comprei da RoboCore. Trata-se de um Servo Turnigy TG9e 9g. Comecei retirando a manopla que veio na frente do dispenser (aquela ali da frente, pra girar manualmente as pás) e encaixando o servo motor na haste interna que é usada para girar as pás internas.

103_1_M

Fiz essa fixação, inicialmente, com cola e durex mesmo, já que queria só testar minha hipótese. E que acabou falhando. Falhou porque o servo motor não tinha torque suficiente para mexer as pás quando o dispenser estava muito carregado. Meus primeiros testes contavam apenas com “MMs de papel”, e aí funcionava bem. Quando testei com MMs de verdade, colocando quase 1kg deles no dispenser, o servo não conseguia girar as pás. A solução, então, foi comprar um servo mais potente e, dessa vez, escolhi o SM-S4303R, que tem um bom torque e é de rotação contínua.

427_1_M

Pronto! Agora tudo beleza! O servo tinha força de sobra para girar as pás. Meus testes foram com até 1kg de MMs, o que acho suficiente. O primeiro aprendizado aqui é que servos de rotação contínua operam de forma diferente dos servos com rotação limitada (180 graus). Ao usar os servos de rotação contínua, você determina a velocidade de rotação deles, enquanto com os servos limitados a 180 graus você define a posição para a qual ele deve se deslocar.

Sensor

Logo que comecei com essa brincadeira, nunca tinha imaginado como seria o funcionamento de um sensor de proximidade. No mundo lindo que eu tinha na minha cabeça, o sensor já me daria como dado bruto a distância em si. Mera ilusão. Na verdade, seria necessário usar algum sensor com o qual eu pudesse checar a proximidade de um objeto. Por exemplo, um sensor de luminosidade. Caso um objeto esteja muito próximo, a luz diminui. Mas não serviria muito bem para os meus propósitos, pois seria necessário aproximar demais as mãos.

Foi então que vi que eu tinha um sensor ultrassônico, que se encaixou perfeitamente. Com esse sensor, eu posso calcular a distância de um objeto para o sensor. A ideia é simples: ele emite um som que vai bater em objeto e voltar. Assim, eu tenho todas as informações que preciso pra saber a distância: o tempo que o som levou para ir e voltar e também a velocidade do som. Lindo. Agora eu já tenho como saber se tem um objeto próximo o suficiente. Ah! Para meu caso, usei o sensor HC-SR04.

620_1_M

LCD

Para o negócio ficar ainda mais bonito, resolvi botar uma tela de LCD de 16×2 com o objetivo de mostrar o nome da pessoa que ganhou os MMs. E essa foi a parte que mais me deu trabalho. Primeiro, porque o LCD precisa de fio pra cacete. Segundo, porque o idiota aqui conectou errado na primeira vez. Terceiro, porque eu sou idiota mesmo. 😛

79_1_M

Mas, acabou que funcionou lindamente, embora tenha poluído o projeto com uns 12 fios passando de um lado pro outro. O LCD que usei foi o LCD 16×2 com fonte preta e fundo verde, vendido na Robocore.

Assembly

Uma vez que eu tinha os componentes e já os tinha testado, agora restava colocá-los no dispenser de uma forma bacana, sem que ficassem muito expostos. Foi aí que entrou meu lado Maker. E como esse lado Maker me surpreendeu. Eu diria que foi até muita sorte, porque eu consegui fazer os cortes até bem demais. Só o do LCD que não ficou muito gatinho, mas está valendo.

Primeiro, tirei o “girador” manual da frente e coloquei o servo motor na parte de trás, para que ficasse escondido e bem apoiado. Caso eu o colocasse na parte frontal, teria como problema sua fixação, já que necessitaria de algo para apoiá-lo bem, sem que girasse em seu próprio eixo toda vez que fosse acionado. Depois, precisei fazer os cortes do LCD e do sensor ultrassônico, pois sem esses cortes, os fios atrapalhariam bastante, sem contar que ficariam demasiadamente expostos.

Para esses cortes, usei um estilete aquecido e um niple de inox que uso na minha panela de brassagem. Funcionou belezura demais! Acabou que eu tinha tudo o que precisava em minha casa mesmo!

Software

Para falar a verdade, o software foi a parte mais fácil. E não poderia ser de outra forma, né! Só precisei relembrar um pouco de Python e brigar um pouco com a GPIO até entendê-la direito. Superados esses problemas, foi piece of cake! Aliás, todo o código está no Github, caso esteja interessado.

Cadê os detalhes?

Calma! Este foi só o primeiro post! Um mais filosófico! Já estou escrevendo o post que mostrará todos os detalhes técnicos, com as conexões, uso do GPIO, código Python e fotos!

Os 7 Hábitos das Pessoas Altamente Eficazes – Parte 1

Por incrível que pareça, eu ainda não havia lido esse livro, embora já tenha lido muitos outros nessa área.  Ele foi lançado há cerca de 20 anos atrás por Stephen Covey mas foi apenas nos últimos dias que eu decidi lê-lo. E agora que o estou lendo, percebi o quanto eu deveria ter lido este livro antes! Antes de começar a escrever minhas impressões sobre a primeira parte do livro, sugiro assistir o vídeo que inicia esta postagem. Ele foi feito pelo Brian Johnson, que é assíduo leitor de livros nesta área e sempre cria vídeos com resumos sobre eles. Todos seus vídeos são extremamente indicados!

Parte 1

There is no real excellence in all this world which can be separated from right living – David Starr Jordan

 

Nesta primeira parte, o Covey foca bastante no que ele chama de Personality Ethic e Character Ethic. No primeiro, o sucesso é obtido através de técnicas, comportamentos e da preocupação com sua imagem pública. Neste caso, você não se importa muito com o que você é de fato mas sim como você é visto pelas pessoas. Por exemplo, você quer parecer uma pessoa confiável aos olhos das outras e, ao invés de se tornar de fato uma pessoa confiável, você usa técnicas que visam confundir ou manipular as pessoas de tal forma que elas acreditem que você é uma pessoa confiável e, desta forma, você consiga vantagens.

Já o Character Ethic baseia-se  na ideia de que o sucesso só é duradouro caso você tenha como base o seu caráter. Importa mais você de fato ser uma pessoa confiável do que apenas fingir ser uma. Covey tenta nos mostrar como essa estratégia não nos leva a um sucesso duradouro. Para o autor, se você apenas usa técnicas para tentar dissuadir as pessoas, um dia irá quebrar a cara. 

 

In the last analysis, what we are communicates far more eloquently than anything we say or do – Stephen Covey

 

E, para não quebrarmos a cara, Covey fala sobre o poder da quebra, ou mudança, de um paradigma: devemos mudar totalmente a forma como vemos o mundo. Entretanto, ele próprio salienta o quanto esta quebra é difícil, uma vez que nós estamos tão imersos em hábitos destrutivos que não notamos que estamos nos levando ao fracasso regularmente. Como você não os nota, as técnicas que lhe fazem concluir suas tarefas de forma mais rápida, entretanto, só fazem você chegar mais rápido ao lugar errado.

A leitura desta primeira parte me lembrou de alguns vídeos e também de livros que li nesta área. Por exemplo, há o vídeo da Amy Cuddy, sobre como você pode passar a ser aquilo que você finge ser. Saliento que a palavra “fingir” não é empregada, neste texto, no sentido pejorativo. Afinal, em português essa palavra sempre vem carregada com um sentimento de egoísmo e mentira. Na verdade, a ideia dela é que de tanto você fingir, ou imitar um comportamento específico, você se incorpora esse comportamento dentro de você próprio, mudando quem você é. Não tem um pouco de contraste entre o que ambos falam? 

Talvez, não. Talvez os dois se complementem. Entendo que para Covey, o errado é usar desse fingimento para ter vantagem sobre outras pessoas sem usar isso para melhorar a si próprio. Já Cuddy acredita que você pode mudar a si próprio apenas moldando o que pessoas de sucesso fazem. Isto é diferente, pois você não tem como objetivo tirar vantagem de ninguém. Isto também me lembra bastante o que já li na literatura sobre Programação Neurolinguística, onde podemos moldar pessoas de sucesso, copiando suas formas de pensar e agir. Enfim, gostei bastante desta primeira parte do livro. Em breve mais textos sobre o livro.

Ah! Para quem nunca ouviu falar de PNL, existem diversos livros interessantes e também vídeos no Youtube. Abaixo está um vídeo do Richard Bandler, um dos criados da PNL, com legendas em português.

Darter: RESTful APIs em Dart

Lembram da última publicação que escrevi falando sobre as ferramentas disponíveis em Dart para criar APIs RESTful? Eu reclamei de algumas características que essas ferramentas não tinham, certo? E como resolver isso? Uma forma seria contribuir para o Redstone, por exemplo. Só que, infelizmente, não dá para modificar o Redstone para permitir o controle de versionamento de APIs, conforme você pode ver nessa issue que abri lá. Outra forma seria trabalhar em cima do RPC da Google. Só que nesse eu não abri issues e nada. hehe. Resolvi logo partir para a violência: criar uma biblioteca própria, considerando não cometer as mesmas falhas que encontrei nessas duas.

O meu guia de referência para essa biblioteca foi o Grape, para Ruby. Em minha opinião, é o framework, para desenvolver APIs RESTful, mais completo e simples de ser usado, independente de linguagem. Uso ele para todas as minhas APIs. Entretanto, é óbvio que não pude criar uma DSL em Dart, já que essa linguagem não dá facilidades para fazer isso da mesma forma como Ruby. Precisei usar a maneira Dart de codificar. Acho que o resultado ficou bom!

Darter

Apresento-lhes o Darter! Meu primeiro projeto open-source para Dart. Ele está servindo para muitos propósitos: estou aprendendo a fundo a linguagem, estou me divertindo pacas e estou contribuindo! O Darter ainda não está em versão final. Precisa de melhorias e correções. Como ainda estou na fase de codificação para provar meu conceito, ainda não escrevi os testes. E, por favor, deixa de #mimimi se isso é certo ou errado, preferi primeiro validar minha ideia para depois partir para tornar a ferramenta mais madura, com testes, exemplos e etc.

Mas, já é possível usá-lo? É sim, companheiro. O Darter já está no Github mas ainda não publicado no Pub. Inclusive, estou escrevendo todo um projeto em cima dele e que também está no Github aqui. Trata-se do meu “projeto-prova-de-conceito”. Ele está totalmente funcional! Agora, vamos ver como funciona o Darter?

 

Exemplo de Uso

O primeiro passo é criar uma classe e anotá-la com @API, assim como fizemos no exemplo abaixo. Observe que esta anotação precisa do argumento path. No caso abaixo, teremos uma rota da seguinte forma: http://localhost/categories.

import 'package:darter/darter.dart';
@API(path: 'categories') 
class MyDarterAPI { }

Depois disso, você já pode iniciar a criação de seus métodos que irão tratar as diversas requisições. Para isso, precisamos usar as anotações @GET@POST@PUT@DELETE e @PATCH. Vamos incrementar a classe acima para refletir isso!

import 'package:darter/darter.dart';

@API(path: 'categories')
class MyDarterAPI {

    @GET()
    List<MyModel> list() {
    }

    @GET(path: ':id')
    MyModel get(Map pathParams) {
    }

    @PUT(path: ':id')
    MyModel put(PathParams params, MyModel myModel) {
    }

    @POST()
    MyModel post(MyModel myModel) {
    }

    @DELETE(path: 'id')
    void delete(Map pathParams) {
    }
}

Observe que omiti o corpo dos métodos, pois meu objetivo é só exemplificar o Darter. Como era de se esperar, com essa classe aí, teremos as rotas:

  • GET http://localhost/categories
  • POST http://localhost/categories
  • PUT http://localhost/categories/<id>
  • GET http://localhost/categories/<id>
  • DELETE http://localhost/categories/<id>

Parâmetros

No exemplo que vimos na seção anterior, note que recebemos como parâmetro um objeto MyModel em alguns casos, enquanto em outros, recebemos um Map. No primeiro caso, o Darter tenta transformar os parâmetros encontrados em uma classe de negócio da sua aplicação. Por exemplo, suponha que você envia uma String JSON para o Darter e seu método tem como parâmetro um objeto de negócio. O Darter vai criar esse objeto e preencher seus atributos com os valores obtidos do JSON.

Mas, é claro, isso não abrange todos os cenários, certo? Claro que não. Existem os Path parameters e Query parameters. E como ter acesso a eles? Através de uma convenção bem simples: crie um parâmetro do tipo Map e dê o nome de pathParams ou queryParams. Você pode me perguntar porque não fiz igual ao JAX-RS (Java), que tem anotações @PathParam e @QueryParam. Simplesmente porque eu acho essa solução feia, medonha. Polui seu código.

Em minha humilde opinião, é muito mais simples e clean você receber um Map contendo os dados. Rápido, caceteiro, simples e eficiente.

Versionamento

Opa! Você não reclamou tanto de versionamento nas outras ferramentas? Sim! E fiz isso de forma mais flexível no Darter! Vamos melhorar a classe anterior (vou omitir agora os métodos só para exemplificar o versionamento).

@API(path: 'categories')
@Version(version: 'v1', vendor: 'company', format: Format.JSON, using: Using.HEADER)
class MyDarterAPI { }

O Darter permite usar dois tipos de estratégias de versionamento: por path e por header. No caso do header, exemplificado acima, você precisa usar a anotação @Version e informar quatro argumentos obrigatórios. Por que? Porque o Darter vai procurar por isso no cabeçalho Accept. Como? Ele espera que esteja no formato application/vnd.<vendor>.<version>+<format>. Entendeu agora o motivo dos argumentos extra? No caso acima, ele espera o cabeçalho formatado assim application/vnd.company.v1+json.

E caso você queira o versionamento no path? Eu não aconselho essa estratégia, mas ela existe e eu não poderia deixar ela de fora. Neste caso, basta modificar a anotação e esquecer os parâmetros extras.

@API(path: 'categories')
@Version(version: 'v1', using: Using.PATH)
class MyDarterAPI { }

Nesta estratégia, você terá a URL http://localhost/v1/categories.

Error Handlers

Suponha que seu método recebe um ID e você vai buscar esse ID na base de dados. Seu mecanismo de busca não encontra e lança uma exceção chamada ObjectNotFoundException. O que sua API deve fazer com essa exceção? O correto é pegar essa exceção e retornar na API um status 404 e uma mensagem de erro! O Darter facilita isso? Claro!

@API(path: 'categories')
@Version(version: 'v1', using: Using.PATH)
class MyDarterAPI { 
    
    @ErrorHandler
    Response handleObjectNotFound(ObjectNotFoundException ex) {
    }

}

A partir deste método, você pode retornar um objeto Response ou qualquer outro objeto, inclusive seus models. Observe que o parâmetro do método deve ser exatamente o tipo da exceção que você quer tratar. E caso você tenha mais de um handler com o mesmo parâmetro? O Darter pega o primeiro e ignora os outros, então, tome cuidado.

Interceptors

Agora, imagine outra situação: você precisa validar antes se o usuário tem permissão de acesso à sua API! Como fazer isso? Com interceptors, meu caro. Um interceptor, como o próprio nome já diz, intercepta uma requisição para que você possa tratar ela. Essa interceptação pode ocorrer antes ou depois que seu método seja chamado. Ah! E você também pode definir a ordem de execução dos interceptors! Vamos deixar de blá blá blá e ver um exemplo?

@Interceptor(when:Interceptor.BEFORE, priority: 1)
class Authentication {

    void intercept(Chain chain) {
        String token = chain.request.headers["X-Token"];
        if (token != "Test") {
          chain.abort(new Response()
            ..body = "{\"error\":\"Permission Denied\"}"
            ..statusCode = 401);
        }
    }
}

Você deve primeiro criar uma classe e anotá-la com @Interceptor, fornecendo dois parâmetros: quando ele será executado e sua prioridade. Em seguida, e isso é uma convenção, crie um método chamado intercept que recebe o parâmetro Chain. O objeto chain lhe dá acesso apenas ao Request, quando é um interceptor BEFORE, e acesso ao Request e Response quando é um interceptor AFTER.

Iniciando

Para fechar o exemplo, só precisamos iniciar o servidor, né? E isso é fácil! Basta criar uma instância de DarterServer, adicionar suas APIs e interceptors e mandar bala com start().

main() {
  new DarterServer()
    ..addApi(new MyDarterAPI())
    ..addInterceptor(new Authentication())
    ..start();
}

Vai me perguntar porque não fiz reflexão para encontrar as classes anotadas? Achei o mecanismo de mirrors do Dart muito massa, mas um pouco complicado de escanear o classpath de sua própria aplicação em busca das classes. Achei oneroso e propenso a erros. Até mesmo o RPC, do próprio Google, não faz isso. Então, resolvi ir na mesma onda deles! 🙂

Conclusão

Gostou? Achou a ideia interessante? Agora vem a parte mais legal: o projeto ainda está em estágios iniciais e, portanto, sua ajuda não é só permitida, é altamente desejada. Não precisa ser necessariamente com código, mas com sugestões de melhorias, testes e etc. Vamos lá? Manda suas dicas nos comentários!

Ah! Por último, porque o nome Darter? Em primeiro lugar, é óbvio, é pelo trocadilho com o nome da linguagem. Mas só isso não bastaria, eu também quis salientar a leveza e liberdade de um pássaro para voar da forma como quiser. Dois princípios que pretendo manter na biblioteca! O pássaro é esse da foto do post!

Dart: Syntax Sugar!

Que Dart é bacana, isso todo mundo sabe, certo? Mas, por que Dart é bacana mesmo? Um dos motivos é o que chamamos de syntax sugar. O que é isso? São facilitadores que a linguagem traz para que você faça tarefas muito comuns de forma mais fácil, com menos linhas de código. Algumas pessoas acham que syntax sugar é para os fracos. Outros dizem que é pura frescura. Ah vai, para! Se uma linguagem me dá uma forma de fazer uma coisa com menos trabalho, é claro, óbvio, cristalino, inteligente e outros mil bons adjetivos que eu quero usar isso!

Então, vamos começar falando sobre os syntax sugar que o Dart fornece para…

Construtores

Imagine, por exemplo, que você queira criar um construtor que recebe dois parâmetros e que atribui esses dois parâmetros para dois atributos que tem o mesmo nome. Trata-se de uma tarefa bem comum, certo? Então, porque não facilitar? Dart facilita. Vejamos como:

class Pessoa { 
   String nome; 
   String endereco; 

   Pessoa(this.nome, this.endereco); 
}

Pessoa marlon = new Pessoa("Marlon", "Rua dos Dartisans");

Lindo, não é? Observe que sua classe em Dart tem dois atributos e apenas um construtor, que recebe como parâmetro o nome e o endereço e já atribui o valor destes dois parâmetros para os atributos. Outro detalhe importante: essa atribuição ocorre antes de o corpo do construtor ser executado! Mas, peraí, e se eu precisar colocar um código no corpo desse construtor? Sem problemas.

class Pessoa { 
   String nome; 
   String endereco; 

   Pessoa(this.nome, this.endereco) {
      if(this.nome == "Marlon") {
         this.nome = "Marlon S. Carvalho";
      }
   }
}

Pessoa marlon = new Pessoa("Marlon", "Rua dos Dartisans");

Agora, e se sua classe herda de uma classe-pai e você precisa chamar o construtor do pai? Muito simples, meu caro, pois basta colocar um logo depois do construtor e chamar o construtor do pai. Observe também que você pode continuar usando a atribuição que vimos no exemplo anterior. Olha esse exemplo:

class Pessoa { 
   String nome; 
   String endereco; 

   Pessoa(this.nome, this.endereco);
}

class PessoaInteligente extends Pessoa {
    double qi;

    PessoaInteligente(nome, endereco, this.qi): super(nome,endereco) {
    }
}

Operador em Cascata

O operador em cascata é outro syntax sugar bem bacana. Quem nunca se deparou com a situação em que você precisa chamar diversos métodos de um objeto em sequência? Isso sempre acontece, né não? Principalmente quando você está inicializando um model ou entity e atribuindo aos seus atributos valores oriundos de um formulário HTML.

Pessoa pessoa = new Pessoa();
pessoa
    ..nome = "Marlon"
    ..endereco = "Rua dos Dartisans"
    ..save();

Métodos Assíncronos

Esta é bem recente e eu o considero como um syntax sugar também. Para você entender bem esse syntax sugar, lembre-se de como você trata requisições assíncronas com Javascript. Lembrou? Horrível, certo? Em Javascript temos o conhecido callback hell. Você precisa encadear um monte de funções de callback para atender a duas ou três chamadas assíncronas. Algo assim:

funcao_assincrona("param1", function(resultado) {
    funcao_assincrona2(resultado, function(resultado2) {
        funcao_assincrona3(resultado2, function(resultado3) {
            // Enfim, podemos fazer algo!
        });
    });
});

Meu amigo, esse código aí é feio demais! Nas primeiras versões do Dart, você também precisava fazer algo parecido com isso. A única diferença é que nós tínhamos a classe Future, mas a ideia era a mesma. E como o Dart resolveu isso? Com a biblioteca dart:async. Olha como as coisas agora ficaram lindas!

var resultado1 = await funcao_assincrona("param1");
var resultado2 = await funcao_assincrona2(resultado1);
var resultado3 = await funcao_assincrona3(resultado2);

Muito melhor, não? Com await, você programa quase como se estivesse programando um código síncrono. Quer saber mais sobre isso? Clica aqui.

Finalizando

Você acha que esqueci de citar alguma outra syntax sugar bacana do Dart? Então deixa um comentário! Eu adicionarei sua sugestão no artigo e com a devida citação para o autor.

RESTful APIs com Dart

Já ouviu falar de Dart? É uma linguagem bem bacana, embora ainda ache ela um pouco “verbose”, criada pelo Google. A linguagem lembra um pouco Java, mas adiciona features que são extremamente interessantes e que facilitam substancialmente nossa vida. Alguns desenvolvedores torcem o nariz para Dart por sua semelhança com Java e Javascript, outros a adoram, exatamente por ter essa semelhança mas incluir features que o Java carece.

Qual meu lado? Eu acho Dart massa! Principalmente por eu ter programado em Java por tantos anos. Entretanto, Ruby ainda é minha linguagem favorita! Imbatível! 🙂 Mas, eu não vim aqui para exaltar nem Java, nem Ruby e nem Dart. Eu estou escrevendo esse post para tratar sobre três frameworks escritos em Dart que podem facilitar a vida de quem deseja criar uma API RESTful usando essa linguagem.

Algumas das vantagens de criar uma API com Dart é que a nuvem do Google está preparada para o Dart e a linguagem inclui features bem interessantes para isso. Até o momento, encontrei três ferramentas para essa tarefa: Redstone.dart, RPC (do Google) e Shelf Rest. São três boas ferramentas, mas, como veremos a seguir, carecem de algumas funcionalidades interessantes que encontramos em frameworks como o Grape, para Ruby.

Alerto que eu não fiz um estudo exaustivo sobre essas ferramentas. Fiz pequenos exemplos e tentei implementar algumas features que sempre busco em ferramentas como essas. É capaz de existirem outros problemas mas com os quais eu não me deparei. Isto pode ter acontecido porque meus exemplos eram simples, bem básicos e quando eu encontrava dois ou três problemas que, na minha humilde opinião, são falhas graves para a construção de APIs, eu parava de fuçar.

Antes de começarmos a falar sobre essas ferramentas, eu sugiro assistir o vídeo acima. Eu descobri essas ferramentas através desse vídeo. É extremamente indicado para quem quer começar a desenvolver APIs em Dart!

Redstone.dart

O Redstone.dart foi escrito por um brasileiro chamado Luiz Mineo. O Luiz esteve à frente do Redstone até a versão 0.5 mas não pôde continuar seu desenvolvimento e agora o Redstone está nas mãos de abnegados desenvolvedores que já estão trabalhando em melhorias e reformulações profundas. A nova versão, 0.6, já está em Beta e aparentemente, próxima de ser lançada.

A principal questão é que o Redstone não foi feito especificamente para criar APIs RESTful. Com ele você pode criar rotas e tratar essas rotas usando os principais métodos HTTP de forma muito, mas muito fácil mesmo! Eu criei uma API simples nele em 10 minutos! Mas, então, o que falta nele? Vamos enumerar:

  1. Não permite alterar dinamicamente o status code. Desta forma, você não consegue mudar de 200 para 201 em um PUT que cria um recurso. Eu já relatei uma issue no Issue Tracking deles e um dos desenvolvedores considerou a feature necessária. Ou seja, é provável que eles implementem isso no futuro. Embora eu esteja avaliando a possibilidade de mandar um Pull Request! 😛
  2. O Redstone não tem uma forma fácil de tratar a versão da sua API. Para APIs, isto é importantíssimo, pois APIs sempre evoluem e não dá para jogar a versão anterior fora e colocar uma nova de supetão.
  3. Respostas Parciais. Também não tem nenhum mecanismo que facilite construir respostas parciais. Isto teria que ser implementado “na mão”.
  4. Não retorna os status “padrão” para cada método HTTP. Por exemplo, é esperado que o método POST retorne o status 201 CREATED. O Redstone não retorna automaticamente o 201, no lugar, ele retorna 200. 

RPC

RPC, diferente do Redstone, foi feito para criar APIs RESTful. Esse era o objetivo quando criaram ele. O RPC foi criado pelo Google e foi a escolhida pelo cara do vídeo que postei no início do post. Mas, infelizmente, tem uma coisa que me irritou nela. O RPC inclui a versão da API na URI. Não encontrei outra forma. Eu prefiro, e acho mais elegante, tratar a versão no cabeçalho ACCEPT. Eu uso a URI apenas para endereçar recursos. Somente!

Sendo uma biblioteca feita essencialmente para construir APIs RESTful, eu esperava encontrar maior flexibilidade com relação a isso. Outro problema que encontrei foi a impossibilidade de alterar o status code dinamicamente. Procurei na documentação como fazer isso, mas não encontrei. Dei uma leve fuçada no código, mas também não encontrei.

Shelf RPC

Como o nome sugere, o Shelf Rest é um adendo ao Shelf para criar serviços RESTful. Esta foi a única ferramenta que eu não testei profundamente. Só dei uma fuçada na documentação, então, peço desculpas caso eu esteja falando merda aqui! 😛 Do que pude observar, ele carece de todos os problemas que citei para o RPC e o Redstone adicionado de mais um: não encontrei como criar rotas usando o método PATCH. Estranho, hein?

Outra coisa que achei bem estranha: eles definem anotações para os métodos HTTP: @Get, @Post, @Put e @Delete. Só que inventaram uma anotação @AddAll que está na mesma categoria das outras. Oi? Semanticamente, não faz o mínimo sentido, embora a funcionalidade pareça interessante.

Conclusão

Você deve estar se perguntando: maluco, você indicaria algum desses frameworks? Eu sou meio xiita nesse negócio de APIs REST, então, tenderia a dizer não. Mas, eu acredito que é possível sim criar boas APIs RESTful usando o Redstone. Pareceu a biblioteca mais promissora e com maior flexibilidade. Eles tem um mecanismo de plugin que achei interessante, pois dá para, por exemplo, criar um mecanismo para retornar Partial Responses.

Ou seja, até aqui eu indicaria o Redstone. A outra pergunta que me fariam é: você acha que Dart está pronto para construir APIs RESTful? Minha resposta é que a linguagem está sim. Ainda não temos um framework tão interessante como é o Grape em Ruby. Uma coisa não invalida a outra. Dart é sim interessante para essa tarefa, mas ainda precisamos de ferramentas mais adaptadas para isto. Então, vamos construir uma? Vamos ajudar o pessoal do Redstone? Ou criar um plugin lá?

Eu vou! 😛

APIs RESTful com Grape – Parte 3

Este é mais um post da série APIs RESTful com Grape, o terceiro da série. No primeiro post, mostramos como montar seu ambiente e como estruturar seu projeto. Além disso, montamos uma API simples cujo o objetivo é prover dados sobre cervejas. Até aqui, temos apenas uma API funcional e provendo uma lista de tipos de cervejas. Adiante, já no segundo post, vimos como usar o gem grape-entity para evitar expor nossos Models através da API.

Continuando essa série, vamos agora implementar os métodos POST, PUT, DELETE e GET(id) para criar, atualizar, remover e obter uma cerveja e um tipo de cerveja específico. Por debaixo dos panos, também estaremos usando o DataMapper para realizar a persistência dos dados. Relembrando, pela terceira vez, este projeto está no Github. Sugiro que você baixe-o e utilize esta série de posts apenas como guia para entender o código fonte que está no projeto.

DataMapper

Conhece o DataMapper? Trata-se simplesmente de um framework para persistência de dados. Só isso mesmo. Caso não goste de frameworks deste tipo, você pode fazer tudo na unha, é problema seu. Ou, caso não goste do DataMapper, você também pode usar o ActiveRecord. Por fim, caso você não queira usar bancos de dados relacionais, você pode dar uma olhada no MongoMapper. Só aviso que nosso objetivo aqui não é detalhar como funcionam estas ferramentas. Talvez em um post futuro, mas não nesse! Neste caso, vamos fazer apenas o básico do básico para colocar o DataMapper funcionando neste projeto.

Instalando

Rápido e caceteiro! Digite gem install datamapper para instalar o DataMapper globalmente. Em seguida, atualize seu arquivo Gemfile, adicionando a linha gem ‘data_mapper’. Finalizando, execute bundle install para instalar os gems necessários para o projeto. Fim!

Alterando os Models

Agora, precisamos alterar nossos models para que eles tenham persistência de dados. Mas não se assuste, é coisa bem simples, como você pode ver na listagem de código abaixo.

require 'data_mapper'

module Models

  # Cervejas.
   class Cerveja
     include DataMapper::Resource

     property :id, Serial
     property :nome, String
     belongs_to :tipo
   end

  # Tipos de Cervejas
   class Tipo
     include DataMapper::Resource

     property :id, Serial
     property :nome, String
     has n, :cervejas
   end

end

O que nós fizemos? Primeiro, precisamos fazer um “require” do DataMapper logo no início do arquivo models.rb. Segundo, precisamos alterar nossas classes para incluir o DataMapper::Resource e definir as propriedades, que virarão colunas nas tabelas que representarão cada classe. Para definir as propriedades, usamos o método property, que recebe dois parâmetros: um Symbol que representa o nome da propriedade e o tipo da propriedade.  Observe que neste exemplo em específico, ainda precisamos fazer um relacionamento de “um-para-muitos” entre tipo e cerveja. Na classe Cerveja, informamos isto através da linha belongs_to :tipo, enquanto na classe Tipo, fizemos has n, :cervejas. Simplificando: um Tipo tem muitas cervejas e uma Cerveja tem apenas um Tipo.

Finalizando

Para colocar o DataMapper rodando, agora só precisamos definir o Adapter de banco de dados a ser usado e avisar a ele para criar automaticamente toda a estrutura do banco de dados. Como fazemos isso? Do modo mais simples possível: alterando nosso arquivo config.ru. Mas, antes disso, você precisará instalar e configurar um banco de dados de sua preferência. Para este artigo, usarei o MariaDB, herdeiro do MySQL. Por que? Porque sim e pronto.

Comece instalando o gem ‘dm-mysql-adapter‘ e não se esqueça de incluí-lo também no Gemfile, viu? Agora altere seu arquivo config.ru para ficar parecido com a listagem abaixo. Observe que adicionamos apenas quatro linhas. Primeiro, o require para o DataMapper. Segundo, informamos o banco de dados através do método setup, em seguida, chamamos o método auto_migrate! para criar a estrutura das tabelas automaticamente e finalizamos chamando finalize! Pronto! Cabô essa seção, ufa! Muito chata!

$:.unshift "./app"

require 'rack/cors'

require 'rubygems'
require 'grape'
require 'rack'
require 'grape-entity'
require 'data_mapper'
require 'api/base.rb'

DataMapper.setup(:default, 'mysql://seulogin:suasenha@localhost/bebumapi')
DataMapper::auto_migrate!
DataMapper::finalize

use Rack::Cors do
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :post, :put, :delete, :options, :patch]
  end
end

run API::Base

API de Tipos e Cervejas

Agora, que tal fecharmos toda a API de Tipos? Vamos lá. Vamos implementar mais 3 métodos nela. O primeiro método será responsável por obter um Tipo de cerveja a partir de um ID e está definido na linha que tem get ‘:id’ do. Observe que a String ‘:id’ informa que teremos uma rota /tipos/algoaqui. Ou seja, sempre que alguém tentar acessar http://localhost:9292/tipos/*, cairá neste método. E como podemos obter esse valor :id? Simples, usando o Hash chamado params. Simples demais! Agora só chamamos o DataMapper pedindo o Model que representa esse recurso.

Vamos ver o método POST? Observe que não passamos uma String igual a como fizemos com o get. Exatamente porque não precisa, já que queremos uma rota POST na URL http://localhost:9292/tipos. Quando alguém fizer um post nessa rota, também deve passar algumas coisas como parâmetro. Neste caso, o nome do Tipo da cerveja. A partir daí, fica tudo mais fácil! Só criamos um objeto Models::Tipo e mandamos o DataMapper salvar. De lambuja, retornamos a entidade criada.

module API

  module V1

    class Tipos < Grape::API

      resources :tipos do

        get do
          present Models::Tipo.all, :with => Entities::Tipo
        end

        get ':id' do
          present Models::Tipo.get!(params[:id]), :with => Entities::Tipo
        end

        post do
          tipo = Models::Tipo.new
          tipo.nome = params[:nome]
          tipo.save

          status 201
          header 'Location', "/tipos/#{tipo.id}"
          present tipo, :with => Entities::Tipo
        end

        put ':id' do
          tipo = Models::Tipo.get params[:id]

          if tipo.nil?
            status 201
            header 'Location', "/tipos/#{tipo.id}"
            tipo = Models::Tipo.new
          else
            status 200
          end

          tipo.nome = params[:nome]
          tipo.save

          present tipo, :with => Entities::Tipo
        end

        delete ':id' do
          status 204
          Models::Tipo.get!(params[:id]).destroy!
        end

      end

    end

  end

end

Mas, opa! Lembra que eu falei que iríamos fazer uma API seguindo os princípios REST? Então, é prudente que a gente também retorne o cabeçalho Location informando a URI do recurso que acabamos de criar. E o Grape nos ajuda substancialmente para fazer isso! Basta usar header ‘Location’, “/tipos/#{tipo.id}”. De brinde, embora não seja necessário, pois o Grape já faz isso em todo método POST, informamos que queremos retornar um status 201 CREATED na linha status 201. Diga se não é lindo isso!

E o DELETE? Moleza, companheiro! Basta criar o bloco DELETE parecendo com o GET anterior e remover a entidade. Ah! Só não se esqueça de definir o status como 204 NO CONTENT, viu? Vamos finalizar com o PUT? Ele é só um pouco mais chato. Mas nada demais. Lembre que o PUT deve verificar se o ID informado se refere a um recurso existente. Caso não se refira, devemos criar esse recurso.

No código, a única diferença é que checamos se o objeto é nil. Caso seja, mudamos o status para 201 CREATED e também retornamos o cabeçalho Location. Caso contrário, botamos o status para 200 OK. O resto do código é similar ao que fizemos para o método POST.

E como fica a API de Cerveja? Rapaz, idêntica a essa. Claro, temos que tratar algumas coisas específicas, como o relacionamento entre Cerveja e Tipo. Mas não é nada de outro mundo, como você pode ver na listagem abaixo e que eu não vou explicar porque você é inteligente e já entendeu tudo! 😛

Pronto! Cabô mais um artigo! Quer saber sobre o que escreverei no próximo? Vamos ver como tratar erros genéricos, como, por exemplo, quando um recurso não existe ou quando o usuário da API esqueceu de enviar um parâmetro. Não perdaum!