Wednesday, July 13, 2016

De volta após um longo período - Vamos falar de Arduino Nano e como carregar um bootloader


Fala Pessoal,

Estou de volta depois de um longo hiato por aqui. Muitas coisas mudaram acá e depois de participar de um sensacional e inspirador TDC, resolvi remexer as coisas por aqui.

Lá ouvi falar sobre o protocolo Firmata e decidi experimentar com ele e meu Arduino Nano. A ideia é que o protocolo transforme o arduiíno em um slave the uma aplicação que irá contolar seus inputs e outputs além de conter toda a lógica.

De acordo com o palestrante - Marco Diniz Garcia Gomes- uma das vantagens é embarcar o mínimo de software possível e usar todo o poder de processamento de uma máquina desktop. Claro que como desvantagem está o fato de que se houver perda de conexão o dispositivo não funciona.

Isso será tópico de outra conversa. Por enquanto, só quero falar da dor de cabeça que tive para começar a brincadeira. Preparei pra começar, li um pouco sobre o Firmata e na hora de fazer o download do sketch para o Nano, nada de funcionar: eu não conseguia carregar os sketches

Depois de atualizar os drivers FTDI sem sucesso, comecei a desconfiar que meu Nano estava sem Booloader. O Bootloader é um firmware que permite que outros Firmwares sejam carregados usando um programador externo.

A melhor indicação que o meu Nano estava sem Bootloader foi que o Led ligado ao D13 não piscava ao resetar a placa e ao tentar fazer o download para a placa.

Li um pouco sobre o bootloader para tentar não transformar minha placa em peso para papel e decidi seguir em frente.

Acabei descobrindo que o processo para carregar o Bootloader é simples, Tudo o que precisei foi de um outro Arduíno e alguns cabos para conexão

Abaixo os passos que segui:

:


1 - Carregar o sketch ArduinoISP no Arduíno que está funcionando (figura 1)

Figura 1
2 - Conectar o Arduino Nano ao outro Arduíno - no meu caso o UNO (figura 2). Obviamente manter os 2 Arduinos desconectados da USB

PS. Acabei de descobrir que a imagem que usei de referência não era do UNO, mas funcionou do mesmo jeito


Figura 2

3 - Ligar o Arduino que funciona na USB e na IDE do Arduino selecionar Tools ->Programmer -> Arduino as ISP (figura 3)
Figura 3

4 - Aqui foi onde fiquei na dúvida: algumas referências pediram para selecionar o Arduino defeituoso como Board. Outros o Arduino que funciona. Acabei selecionando o que funciona (figura 4)
Figura 4
5 - Selecionar a Porta
6 - Selecionar Burn Bootloader (figura 5)

Figura 5

Pronto! Depois disso,  desconectar os cabos e ligar o Arduíno Nano na USB.  Se tudo deu certo você irá perceber que o LED que mencionei lá no começo irá piscar.

Para testar faça o upload de um código simples (como o Blink) para testar.

O que percebi no meu caso e não sei se foi por causa da minha dúvida no passo 4 é que preciso selecionar Arduino UNO na IDE para fazer o upload. Não consigo fazer quando deixo Nano selecionado. Vamos ver se isso será um problema no futuro!

Como referência para esses passos eu usei os seguintes sites:

Para os passos: http://www.instructables.com/id/How-To-Burn-a-Bootloader-to-Clone-Arduino-Nano-30/

Para as conexões (a imagem está lá em cima) : http://forum.arduino.cc/index.php?topic=88081.15

Era isso Pessoal. Depois eu volto com novidades sobre Firmata no Arduino.

Keep it Up!
Ewerton












Tuesday, January 12, 2016

Pausa na aplicação - Controlando versões de código: conheci o BitBucket!

Fala Pessoal, tudo bem?

Enquanto estou travado no desenvolvimento da minha aplicação por um problema que irei descrever assim que resolvê-lo, quero compartilhar mais uma que aprendi nessa nova empreitada de criar código. :)

Sempre escrevi minhas macros, alguns códigos, etc, mas nunca me preocupei em ser organizado, guardar versões antigas do que eu já tinha feito, etc. Eu ia fazendo, aprendendo, errando e acertando e uma hora o código funcionava e eu ficava satisfeito.

Com o desenvolvimento dessa aplicação estou indo mais a fundo em me organizar como "desenvolvedor". Tenho arrancado os cabelos por alterar um código que funcionava e que depois de algumas alterações parou de funcionar e eu não consigo voltar ao que era antes. Isso até descobrir o BitBucket, que é uma plataforma para controle de revisões de projeto.

Soube do BitBucket por acaso, conversando com uma pessoa lá no SJC Hacker Clube. Estava pedindo umas dicas na minha aplicação e ele pedu para compartilhar o código. Me explicou como funcionava e pronto... Criei uma conta, configurei o repositório e a mágica se fez!!

Claro que para qualquer desenvolvedor que ler isso vai saber disso desde o primeiro dia em que se entitulou desenvolvedor, é arroz com feijão. Mas para desenvolvedores eventuais como eu, esse conceito não é tão intrínseco. Eu sabia do conceito, já tinha interagido com SVN aqui na empresa mas não conhecia uma plataforma free para criar times e não fazer o código 100%  público (como é o GitHub).

Além de manter um histórico das versões, dá pra fazer uma comparação do que mudou, como no exemplo abaixo:


Volto a dizer: não é a descoberta da roda aqui, mas vai ser uma coisa que me ajudará muito. A plataforma é free até certo ponto e fácil de usar.

Agora posso alterar o código à vontade.. Estou protegido!

Era isso.. só queria compartilhar.

Cheers.. Keep it up!
Ewerton


Tuesday, January 5, 2016

Alterando uma extensão do ThingWorx - Update I

Fala Pessoal,

Continuo minha luta para fazer uma extensão para o ThingWorx. Tem sido uma experiência bacana: quanto mais eu penso em adicionar funcionalidades, as dificuldades vão aparecendo e eu vou descobrindo melhor como o mecanismo de extensões funciona.

Meu último post antes de falar de autenticação foi sobre a alteração do código de runtime para que a extensão funcionasse. E funcionou só que com um porém: não consegui fazer com que a atualização fosse dinâmica, ou seja, a possibilidade de escolher campos diferentes a serem plotados no mapa.

Minha versão anterior dependia de que o a propriedade fosse definida na criação do Mashup e não em tempo de execução.

Bom, depois de uma pergunta aqui e outra ali e alguns fios de cabelo a menos cheguei em uma versão de código que faz o que quero.

A API (se é que posso chamá-la assim) possui um método chamado updatePropertyInfo.Esse método captura as mudanças de valor na propriedade. Eu já tinha usado antes sem saber para que serve (resultado de CRTL+C, CTRL+V), mas aos poucos vou entendendo.

Também tive que declarar algumas variáveis como globais, fora do bloco if, ou seja, se uma variável não estiver declarada no bloco abaixo ela foi declarada globalmente.

O código ficou assim.

if (updatePropertyInfo.TargetProperty === 'CustomLayerDataField'){
    customLayerDataField = updatePropertyInfo.ActualDataRows;
    return;
}
if (updatePropertyInfo.TargetProperty === 'CustomLayerData'){
    customLayerDataRows = updatePropertyInfo.ActualDataRows;
    var nRows = customLayerDataRows.length;
    var heatmapData=[];
    for (var rowNumber = 0; rowNumber < nRows; rowNumber++) {
        var row = customLayerDataRows[rowNumber];
        heatmapData[rowNumber] = 
{location: new google.maps.LatLng(parseFloat(row[this.getProperty('CustomLayerLocationField')].latitude) , parseFloat(row[this.getProperty('CustomLayerLocationField')].longitude)), weight: parseFloat(row[customLayerDataField[0].SelectedValue])};
    }  
    var heatMapDissipating = this.getProperty('heatMapDissipating');
    var heatMapGradient = this.getProperty('heatMapGradient');
    var heatMapOpacity= this.getProperty('heatMapOpacity')
    var heatMapRadius=this.getProperty('heatMapRadius')
    var heatmap = new google.maps.visualization.HeatmapLayer({
            data: heatmapData,
            dissipating: heatMapDissipating,
            opacity: heatMapOpacity,
            radius: heatMapRadius
        });
    heatmap.setMap(this.map); 
    return;
}

E o resultado:
Mapa para Temperatura
Mapa para Chuvas
 Ainda são apenas testes preliminares e não a aplicação final mas vou atualizando vocês conforme eu evoluir!

Keep it Up!
Ewerton




Wednesday, December 30, 2015

Alterando uma extensão do ThingWorx - Faltou falar de autenticação!

Autenticando!

Pessoal, anteriormente (leiam os posts Como Escolher, Hello World, IDE e Runtime) falei sobre o uso da API HeatMaps do Google mas acabei me esquecendo de um ponto importante: a autenticação!

Como mencionei no primeiro post, o uso da API Heatmaps tem uma cota diária e para tal é necessário fazer a autenticação utilizando-se uma Chave de Autenticação criada para liberar a API e controlar o uso.

Para isso é necessário entrar no Console de Desenvolvedores do Google e criar uma credencial que será associada à API e depois utilizada na aplicação. No help do console há algumas dicas de como fazê-lo.

No meu caso eu criei uma Browser Key (ainda não entendi bem a diferença entre Browser/Server keys),  e como o ThingWorx usa widgets, há um arquivo XML chamado metadata que possui algumas configurações, e uma delas é a chamada da API. Tudo o que tive que fazer foi adicionar a autenticação:

<Widget name="googlemap">
<UIResources>
<!-- Studio ONLY -->
<FileResource type="CSS" file="googlemap.ide.css" description="" isDevelopment="true" isRuntime="false" />
<FileResource type="JS" file="googlemap.ide.js" description="" isDevelopment="true" isRuntime="false" />
<!-- Runtime/Squeal ONLY -->
<FileResource type="CSS" file="googlemap.runtime.css" description="" isDevelopment="false" isRuntime="true" />
<FileResource type="JS" file="googlemap.runtime.js" description="" isDevelopment="false" isRuntime="true" />
<!--FileResource type="JS" url="https://maps.google.com/maps/api/js?sensor=false" description="" isDevelopment="false" isRuntime="true" /-->
<FileResource type="JS" url="https://maps.googleapis.com/maps/api/js?key=SUA_CHAVE_DE_AUTENTICAÇÃO_AQUI&amp;libraries=visualization" description="" isDevelopment="false" isRuntime="true"  />
</UIResources>
</Widget>

Só consegui fazer funcionar para uma instância na nuvem, pois coloco a URL como autorizada. Não consegui autorizar o meu localhost.

No meu próximo post eu falo sobre a criação da aplicação, a configuração do Widget e como fica tudo isso!

PS: Pensando sobre esse approach acabei descobrindo uma falha de segurança: como coloco a chave de autenticação aí, no momento de runtime dá pra capturar essa chave usando o console do browser e usar para outra coisa. Na verdade, na configuração da chave eu digo quais são as URLs autorizadas, reduzindo o risco de uso indevido, mas me incomoda o fato de a chave estar exposta publicamente:





Cheers
Ewerton

Alterando uma extensão do ThingWorx - Criando funções em Runtime e fazendo as chamadas da API HeatmapLayer

Criando a função para a execução (Runtime)

Fala galera, em meu post anterior eu descrevi como criei as propriedades que serão consumidas nas chamadas da API em Runtime. Agora vou descrever como ficou a função que chama a API e alguns detalhes e dificuldades que tive. Fiquei surpreso em ver o tamanho do código depois que fiz uma limpeza: sofri tanto para deixar funcionando que nem parece que foi só isso que fiz. :)

Antes...

Também decidi deixar o código mais flexível e para isso criei mais duas propriedades: CustomLayerDataField, CustomLayerLocationField. Isso permitirá escolher qual o campo irá ser usado para os dados e para a localização, sem depender de um Datashape específico. Também criei outras propriedades para a chamada da API, mas isso é mais para configurações de raio, opacidade, etc.

Aqui como ficaram as propriedades:

'CustomLayerDataField': {
'description' : 'Field which will provide data for Custom Layer',
'isBindingTarget': true,
'isVisible': true,
'isEditable': true,
'defaultValue': 'Reading',
'sourcePropertyName': 'CustomLayerData',
'baseTypeRestriction': 'NUMBER',
'baseType': 'FIELDNAME'
},
'CustomLayerLocationField': {
'description' : 'Field which will provide data for Custom Layer',
'isBindingTarget': true,
'isVisible': true,
'isEditable': true,
'defaultValue': 'location',
'sourcePropertyName': 'CustomLayerData',
'baseTypeRestriction': 'LOCATION',
'baseType': 'FIELDNAME'
},

Vejam que há outras características importantes:
sourcePropertyName - relaciona a outra propriedade e define a lista de propriedades que serão exibidas;
baseTypeRestriction - restringe o tipo que será mostrado na lista.

Em outras palavras, ao relacionar-se os dados ao campo CustomLayerData, as propriedades desse campo estão disponíveis para seleção, mas apenas as propriedades do tipo selecionado.






Agora sim, a função para Runtime 

Ficou assim:

if (updatePropertyInfo.TargetProperty === 'CustomLayerData') {
var customLayerDataRows = updatePropertyInfo.ActualDataRows;
var nRows = customLayerDataRows.length;
var heatmapData=[];
for (var rowNumber = 0; rowNumber < nRows; rowNumber++) {
var row = customLayerDataRows[rowNumber];
heatmapData[rowNumber] = 
{location: new google.maps.LatLng(parseFloat(row[this.getProperty('CustomLayerLocationField')].latitude) , parseFloat(row[this.getProperty('CustomLayerLocationField')].longitude)), weight: parseFloat(row[this.getProperty('CustomLayerDataField')])};
}  
var heatMapDissipating = this.getProperty('heatMapDissipating');
var heatMapGradient = this.getProperty('heatMapGradient');
var heatMapOpacity= this.getProperty('heatMapOpacity')
var heatMapRadius=this.getProperty('heatMapRadius')
var heatmap = new google.maps.visualization.HeatmapLayer({
data: heatmapData,
dissipating: heatMapDissipating,
opacity: heatMapOpacity,
radius: heatMapRadius
});
heatmap.setMap(this.map); 
return;
}

Algumas considerações:

  • Para usar o valor de uma propriedade, usei o método getProperty, como em: this.getProperty('CustomLayerLocationField')
    • Nesse caso específico irei pegar o nome da coluna definida nesse campo para que seja usada como location no mapa.
  • No caso acima, o Google Maps necessita dos valores de lat e long separados, por isso ao consumir esses dados foi usado: this.getProperty('CustomLayerLocationField')].latitude
  • O bloco for está iterando todos os dados associados ao Widget e criando um vetor (heatmapData) para que esse seja passado na chamada da API. Esse vetor possui um Object LatLong do GoogleMaps
    • Na tag location, estão sendo passados os valores de lat e long, como mencionei antes.
    • Na tag weight está sendo passado o valor dos pontos que serão plotados, com seu devido peso. Quanto maior, mais "vermelho" é o mapa.
O resultado no Thingworx ficou assim:

Tive várias dificuldades, muitas delas em como acessar os dados de uma matriz (pegar a lat e long do campo location, por exemplo) e outras com sintaxe de chamadas.

Vou continuar trabalhando nessa alteração, mas acho que isso já dá pra começar! Espero que ajude!

Cheers!
Ewerton

PS.. Faltou falar de Autenticação, que cobri no meu próximo post



Tuesday, December 29, 2015

Alterando uma extensão do ThingWorx - Criando propriedades para o Widget

Criando  propriedades para o Widget do Google Maps

Como mencionei em meu post anterior, o ThingWorx possibilita o uso de elementos de interface pré criados, chamados Widgets, na criação das telas de interface, chamadas de Mashups.

Esses Widgets possuem propriedades e eventos que podem ser utilizados na criação da aplicação utilizando-se drag n' drop no momento da criação do Mashup.

No caso da extensão do Google Maps, o widget foi criado em Javascript e possui 2 arquivos principais. Iremos falar de um deles agora, o googlemap.ide e como alterar para adicionar os parâmetros necessários para a funcionalidade de Heatmaps.

Na sessão de propriedades do Widget, irei criar algumas das propriedades que penso em usar:

  1. Liga/Desliga o Layer de Heatmap - propriedade Boolean apenas para acionar a funcionalidade.
  2. Tipo de Layer: penso em fazer com que a alteração seja flexível, então irei adicionar opções para se encolher entre criar-se um layer KML, um layer usando a API HeatMap ou uma FusionTable
  3. Dados de Entrada: é uma matriz com os dados que irão popular o mapa caso utilize-se a API
Vou focar nessas 3 propriedades pois meu desenvolvimento agora será utilizando a API. Quando for desenvolver para Layer KML ou FusionTable precisarei de propriedades para passar esse tipo de dado.

Código para adicionar-se as propriedades:

this.widgetProperties = function () {
return {
'ShowCustomLayer': {
'description': 'Select if custom layer is used',
  'isBindingTarget': true,
'defaultValue': false,
'baseType': 'BOOLEAN'
},
'CustomLayerType': {
  'isBindingTarget': true,
  'description' : 'Select type of custom layer: Google HeatMap or Fusion Tables',
  'baseType': 'STRING',
  'defaultValue': 'HeatMap',
  'selectOptions': [
    { value: 'HeatMap', text: 'HeatMap' },
    { value: 'FusionTables', text: 'Fusion Tables' }
    ]
  },
'CustomLayerData': {
  'description' : 'Data to populate Custom Layer',
  'isBindingTarget': true,
  'isVisible': true,
  'baseType': 'INFOTABLE'
},
}

Claro que  o cabeçalho já existe devido à declaração das outras variáveis. Coloquei ele no código acima apenas para nos localizarmos onde fazer a alteração no código existente.

Nesse código há algumas definições interessantes:
O nome da propriedade está definido entre aspas simples no começo de cada bloco
isBindingTarget - define se a propriedade pode ser associada a alguma variável na IDE
defaultValue - qual será o valor default para a propriedade
baseType -  tipo da propriedade. Isso definirá qual tipo de variável poderá ser associado na IDE. Note que para uma matriz de valores o ThingWorx usa o tipo INFOTABLE
selectOptions - define quais as opções disponíveis para seleção na IDE. Os valores devem ser passados no formato JSON

Depois que o arquivo é alterado e atualizado no Thingworx, as propriedades do Widget Google ficam conforme a figura ao lado.
Dá pra notar que a variável Boolean ficou como um checkBox, a INFOTABLE ficou com o ícone de uma tabela e a variável String que dependia de uma lista ficou com as opções disponíveis para serem selecionadas.

Agora, com as propriedades já definidas no Widget, e como a propriedade isBindingTarget for definida como True,  é possível associar valores ou um conjunto de valores a elas. No exemplo abaixo, o resultado do serviço QueryDataTableEntries está sendo associado à propriedade CustomLayerData. Esses dados serão utilizados posteriormente quando em Runtime, para que o mapa de calor seja populado.


É isso pessoal, a parte de alteração do Widget para a IDE e configuração da aplicação está OK. Agora falta a parte de Runtime, que irei descrever no próximo post

Cheers
Ewerton




Usando a API do Google Maps para criar um Mapa de Calor: Usando a Função HeatMap (HelloWorld)

Fala Pessoal, tudo bem?

Como mencionei no post anterior eu decidi usar a função Heatmaps layers do Google Maps para servir como base para a criação de dashboards para o projeto SmartCitzen do Hacker Clube de São José dos Campos.

Minha maior preocupação na verdade é um problema bom para se resolver: como a API tem uma cota diária, se a aplicação foi muito utilizada há uma chance de exceder-se a cota. Não vou me preocupar com isso por enquanto.

Exemplo de uso da função HeatMaps Layer

No exemplo que peguei no Google, os dados são 'hardcoded'. Funcionou bem, mas como disse em meu post anterior, a intenção é que os dados sejam dinâmicos, portanto preciso de uma rotina para atualizá-los:

var heatmapData = [
{location: new google.maps.LatLng(37.782, -122.447), weight: 0.5},
new google.maps.LatLng(37.782, -122.445),
new google.maps.LatLng(37.752986, -122.403112),
new google.maps.LatLng(37.751266, -122.403355),
{location: new google.maps.LatLng(37.782, -122.443), weight: 2},
new google.maps.LatLng(37.782, -122.437),
{location: new google.maps.LatLng(37.782, -122.435), weight: 0.5},
{location: new google.maps.LatLng(37.785, -122.447), weight: 3},
{location: new google.maps.LatLng(37.785, -122.435), weight: 3}
];

var heatMapDissipating = this.getProperty('heatMapDissipating');
var heatmap = new google.maps.visualization.HeatmapLayer({


var heatMapGradient = this.getProperty('heatMapGradient');
var heatMapOpacity= this.getProperty('heatMapOpacity')
var heatMapRadius=this.getProperty('heatMapRadius')

data: heatmapData,
dissipating: heatMapDissipating,
opacity: heatMapOpacity,
radius: heatMapRadius
});
heatmap.setMap(this.map);  

O primeiro bloco são dos dados que serão plotados no mapa, o segundo são opções para configurar o mapa e o terceiro é a chamada propriamente dita. Para fazer os dados serem dinâmicos preciso fazer com que a variável heatmapData seja alimentada por dados dinâmicos.

Trabalhando com Widgets:

A plataforma que estou usando, o Thingworx, usa o conceito de Widgets: existe uma interface RAD (Rapid Application Development) que possui elementos pré criados para que possamos criar as interfaces de usuário usando pouco código e o  conceito de drag n' drop (olhem esse video para ter uma ideia)

O Thingworx já possui uma extensão para o Google Maps, porém essa extensão não usa a API do HeatMaps. Decidi usar essa extensão como base e adicionar a funcionalidade. Para fazer isso é necessário alterar 2 arquivos da extensão:

  1. googlemap.ide - possui as características do Widget, propriedades, etc - Será necessário alterá-lo para que a IDE no Thinworx possua as propriedades relacionadas à nova funcionalidade
  2. googlemap.runtime - define as funções e chamadas quando a aplicação está em execução - É nesse arquivo que criaremos as funções JavaScript para tratar chamar a função HeatmapLayer

Estou tentando fazer posts pequenos para que não sejam cansativos, então chega por aqui. Nos próximos post irei mostrar como alterei o arquivo de ide e o de runtime

Cheers
Ewerton