Mostrando postagens com marcador Raspberry Pi. Mostrar todas as postagens
Mostrando postagens com marcador Raspberry Pi. Mostrar todas as postagens

quarta-feira, 20 de fevereiro de 2019

Medição de Poluição em Porto Alegre

A prefeitura de Porto Alegre não mede a poluição do ar desde 2010 e tenho percebido alguns estabelecimentos comerciais usando geradores a diesel. Minha conta de luz subiu, nos últimos dois anos, de R$0,59/KWh a R$0,84/KWh. São 42% de aumento e talvez aí esteja o incentivo necessário para o aparecimento dos geradores. Tampouco percebo fiscalização da poluição dos caminhões e dos ônibus. É possível atravessar a cidade deixando um rastro de fumaça negra sem ser interpelado pela autoridade de trânsito.

Por isso, resolvi fazer um pequeno experimento. Comprei um medidor de partículas, o SDS011. Ele mede apenas partículas de 10 micrômetros e de 2,5 micrômetros. O índice de qualidade do ar (AQI) inclui também gases.

Esse pequeno sensor comunica-se via uma porta serial e o pacote inclui também um adaptador USB e o respectivo cabo. Entretanto, nenhum software é oferecido. Felizmente, o protocolo é simples e envolve apenas enviar uma mensagem de 19bytes (a maior parte é de zeros) e receber uma resposta de 12 bytes). O manual descreve todas as interações.

O equipamento tem uma vida útil de 8 mil horas (um pouco menos de um ano de uso contínuo) e pode fazer medições continuamente, mas, neste caso, eu o coloco em estado de hibernação e o acordo para fazer a medição. Assim, ele irá durar vários anos. Entretanto, é preciso esperar 30s depois de acordá-lo para fazer uma medição.

Escrevi um pequeno programa para fazer a leitura uma vez por hora e deixei-o rodando durante uma semana conectado a um Raspberry Pi 3 B.

Alguns poréns devem ser apontados: o aparelho ficou o tempo todo dentro de casa e bem acima do nível da rua na zona norte de Porto Alegre (que, apesar de ser poluída, tem bastante vento).

Em geral, os resultados foram bons (poucas medições passaram de 10μm/m3, sendo 50μm/m3 o limiar do ar bom). Entretanto, houve um pico de 200μm/m3 de PM10 e 49,9μm/m3 de PM2,5. Essa medição já cai na categoria Inadequado. Talvez algum caminhão tenha passado deixando seu rastro.



Se é que posso tirar alguma conclusão deste meu pequeno experimento, é a de que o ar dentro de minha casa está bom. Um estudo mais abrangente e feito por alguém mais capacitado encontrou que o ar de Porto Alegre não é tão bom assim.

Os próximos passos serão:

  • Medir em outras regiões (o centro e a região sul);
  • Medir ao nível da rua;
  • Medir durante um ano inteiro.



domingo, 18 de novembro de 2018

Configuração de PPTP no Raspbian

Um Raspberry Pi Zero não funciona como uma máquina de trabalho remoto, mas pode ser usada para pequenas tarefas, como monitorar a infraestrutura ou mostrar um painel de monitoração.

A conexão à VPN via PPTP inicia pela instalação do pacote PPTP:

sudo apt-get install pptp-linux 

Depois, verifique que as seguintes opções estejam habilitadas no arquivo /etc/ppp/options.pptp:

lock noauth nobsdcomp nodeflate

Verifique, também, se o options.pptp desabilita alguma opção de protocolo que sua rede requer (PAP, EAP, CHAP, MSCHAP). Inicialmente, só a MSCHAPv2 não é recusada.

O próximo passo é indicar um usuário e uma senha no arquivo /etc/ppp/chap-secrets:

$DOMAIN\\$USERNAME PPTP $PASSWORD *

Basta separar os ítens com um espaço.

Crie, então, um arquivo com a informação da conexão em /etc/ppp/peers/$TUNNEL:

pty "pptp minha.rede.com.br --nolaunchpppd"
name $DOMAIN\\$USERNAME
usepeerdns
remotename PPTP
require-mppe-128
file /etc/ppp/options.pptp
ipparam $TUNNEL
persist

A diretiva usepeerdns provoca a importação da configuração de DNS do servidor. O arquivo /etc/ppp/resolv.conf aparecerá magicamente com os ips dos servidores de DNS remotos. A diretiva persist garante que o túnel será reiniciado se falhar.

Adicione o tunel ao arquivo /etc/network/interfaces:

auto tunnel
iface tunnel inet ppp
  provider $TUNNEL

Agora, para iniciar ou encerrar a conexão, bastam os comandos pon e poff:

pon $TUNNEL
poff $TUNNEL

O ifconfig confirmará que o túnel foi criado, se mostrar algo parecido com isto:

ppp0: flags=4305  mtu 1396
        inet 172.16.15.5  netmask 255.255.255.255  destination 172.16.15.1
        ppp  txqueuelen 3  (Protocolo Ponto-a-Ponto)
        RX packets 25  bytes 1529 (1.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 19  bytes 814 (814.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

terça-feira, 1 de novembro de 2016

Porta-Retratos Digital Caseiro III (A Mágica)

O CPAN nunca decepciona: há um módulo para rotacionar as imagens conforme os metadados do JPEG. As máquinas fotográficas mais modernas gravam nos arquivos JPEG a orientação das fotos e o módulo Imager::ExifOrientation permite carregar a imagem já virada no sentido correto para exibir na tela.

use Imager::ExifOrientation;

sub next_photo {
  my $index=int(rand($#file_list));
  my $filename=$file_list[$index];
  
  my $image = Imager::ExifOrientation->rotate(path => $filename);
  scale($photo_width, $photo_height, $image);
  $photo->configure(-file=>'tmp.jpg');
  
  $filename=$file_list[($index+1)%($#file_list+1)];
  
  $image = Imager::ExifOrientation->rotate(path => $filename);
  scale($thumb_width, $thumb_height, $image);
  $thumb->configure(-file=>'tmp.jpg');
  
  $main->update();
}
A mágica tem seus limites: se o arquivo não contiver a informação de orientação, a imagem será carregada assim como está no arquivo.

segunda-feira, 31 de outubro de 2016

Porta-Retratos Digital Caseiro II (O Bug)

O porta-retratos digital funcionou bem por cerca de 8 horas e então parou com um erro de malloc(). Após algumas simulações e pesquisa dos bugs do Tk, descobri que o defeito está na classe Tk::Photo. Quando a imagem é carregada pela memória (com -data), os bits ficam guardados para sempre. Quando são lidos do disco, os dados não persistem além da próxima leitura.

Então, reescrevi alguns trechos e o código ficou um pouco menor. A função scale() não retorna mais os dados; agora ela escreve um arquivo.

sub scale {
  my ($width, $height, $image)=@_;
  my $scaled=$image->scale(xpixels=>$width,ypixels=>$height,type=>'min');
  $scaled->write(file=>'tmp.jpg', type=>'jpeg');  
}

Por sua vez, a função next_photo() lê este arquivo:

sub next_photo {
  my $index=int(rand($#file_list));
  my $filename=$file_list[$index];
  
  $image->open(file=>$filename);
  scale($photo_width, $photo_height, $image);
  $photo->configure(-file=>'tmp.jpg');
  
  $filename=$file_list[($index+1)%($#file_list+1)];
  
  $image->open(file=>$filename);
  scale($thumb_width, $thumb_height, $image);
  $thumb->configure(-file=>'tmp.jpg');
  
  $main->update();
}

Evidentemente, não quero escrever este arquivo no cartão de memória para não apressar o seu fim. Então, a solução é criar um disco em RAM e escrever lá. Ele não precisa ser muito grande, os JPEGs temporários não passam de 100KB (por isso, o script original demorou a ocupar toda a memória).

quinta-feira, 27 de outubro de 2016

Porta-Retratos Digital Caseiro

Os preços dos porta-retratos digitais estão começando a ficar interessantes, mas construir o próprio é mais divertido.

Usei um Raspberry Pi A+ (256MB de RAM e um ARM11 de 700MHz) com a última versão do Raspbian Jessie. Eu queria mesmo era usar um Raspberry Pi Zero (que custa apenas US$5), mas são muito procurados e ainda não apareceram na minha loja preferida.

Comecei muito otimista (como sempre) e tentei montar uma solução com HTML, Javascript, jQuery, transições, etc. Ela resultou ser muito pesada. Então, tentei em Tcl/Tk, mas manipular os tamanhos das imagens resultou ser muito trabalhoso (possível, mas trabalhoso).

Então, só me restou usar Perl. Foi preciso instalar dois pacotes: Tk e Imager.


sudo apt-get install perl-tk
sudo apt-get install libjpeg-devel
sudo cpanm Imager
sudo cpanm Imager::File::JPEG
sudo cpanm Tk::HideCursor 


A interface é muito simples. Há um quadro grande com uma foto qualquer e uma foto pequena com a foto seguinte. A foto grande é escolhida aleatoriamente, mas a pequena é sempre a que segue (para haver uma relação entre elas). Além disso, exibo as horas e a data.

O script recebe um único parâmetro que indica o diretório onde as fotos são armazenadas. Ctrl+C suavemente encerra o programa.

Futuramente, espero exibir algo mais interessante no quadro das horas (a previsão do tempo ou as notícias).

#!/usr/bin/perl
use Tk;
use Tk::JPEG;
use Tk::Photo;
use Tk::HideCursor;
use Imager;
use File::Find;
use MIME::Base64;
use POSIX 'strftime';
use strict;

my @file_list;

find(\&wanted, $ARGV[0]);

sub wanted {
    return unless -f;
    return unless /\.jpe?g$/i;
    push @file_list, $File::Find::name;
}

my $main = MainWindow->new (
  -title => 'PiFrame',
  -background => 'black'
);

my $w=$main->screenwidth();
my $h=$main->screenheight();
$main->overrideredirect(1);
$main->MoveToplevelWindow(0,0);
$main->geometry(join('x',$w,$h));
$main->hideCursor();

my $photo_width=int($w*3/4);
my $photo_height=$h;
my $thumb_width=$w-$photo_width;
my $thumb_height=int($h/3);

my $canvas=$main->Canvas(
  -width=>$photo_width,
  -height=>$h,
  -background=>'black',
  -highlightthickness => 0);
$canvas->pack(-side=>'left');

my $small_canvas=$main->Canvas(
  -width=>$thumb_width,
  -height=>$thumb_height,
  -background=>'black',
  -highlightthickness => 0);
$small_canvas->pack(-side=>'bottom');

my $time;

my $clock=$main->Label(
  -textvariable=>\$time,
  -width=>100,
  -height=>100,
  -background=>'black',
  -foreground=>'white',
  -highlightthickness => 0,
  -font=>'courier 40 bold');
$clock->pack(-side=>'top');

my $photo=$canvas->Photo();
$canvas->createImage(0,0,-image=>$photo,-anchor=>'nw');
my $thumb=$small_canvas->Photo();
$small_canvas->createImage(0,0,-image=>$thumb,-anchor=>'nw');

sub scale {
  my ($width, $height, $image)=@_;
  my $scaled=$image->scale(xpixels=>$width,ypixels=>$height,type=>'min');
  my $data;
  $scaled->write(data=>\$data, type=>'jpeg');
  return encode_base64($data)
}

my $image=Imager->new();

sub next_photo {
  my $index=int(rand($#file_list));
  my $filename=$file_list[$index];
  
  $image->open(file=>$filename);
  $photo->configure(-data=>scale($photo_width, $photo_height, $image));
  
  $filename=$file_list[($index+1)%($#file_list+1)];
  $image->open(file=>$filename);
  $thumb->configure(-data=>scale($thumb_width, $thumb_height, $image));
  
  $main->update();
}

$canvas->repeat(60000, sub {eval {next_photo()}});
$canvas->repeat(1000, sub {$time=strftime("%H:%M\n%A\n%d/%m", localtime)});

next_photo();

MainLoop;

O sistema operacional que usei para este projeto é o Raspbian com Pixel. As fotos estão armazenadas na pasta /data01/fotos. Então, adicionei a seguinte linha ao arquivo  /home/pi/.config/lxsession/LXDE-pi/autostart para que o sistema inicie automaticamente:

@perl /home/pi/piframe.pl /data01/fotos/

Para evitar que o gerenciamento de energia apague a tela por falta de movimentação, é preciso editar o arquivo /etc/lightdm/lightdm.conf. A linha original e a nova são, respectivamente:

#xserver-command=X
xserver-command=X -s 0 dpms


O gasto de memória oscila entre 25MB e 50MB, o que cabe confortavelmente no espaço que o A+ oferece. Um Pi 3 talvez possa executar isso ao mesmo tempo que ofereça o serviço do Amazon Echo.

quarta-feira, 14 de setembro de 2016

Recuperando um roteador WR1043ND com um Raspberry Pi

Um amigo apresentou-me um desafio: recuperar um roteador cuja atualização do firmware dera errado. O roteador, um TP-Link WR1043ND, não funcionava mais. Esse equipamento tem uma interface serial na placa. É uma interface de 3,3V que é compatível com a interface serial do Raspberry Pi.

Infelizmente, não basta abrir a caixa: a interface serial não tem os pinos instalados. Comprei os pinos, um pouco de fio e conectores para construir um cabinho. Depois comecei a perceber que cabinhos com os conectores adequados estão por toda parte: os mouse Genius antigos os tem, assim como os cabos de som dos drives antigos de CD. Até mesmo o cabo de um drive de disquetes ou de HD IDE serviria com algumas modificações. Também aprendi que montar um cabo sem um crimpador é difícil.

No Raspberry Pi, os pinos 6, 8, e 10 servem a porta serial, sendo, respectivamente, o terra (G), a transmissão (Tx) e a recepção (Rx). Eles são vizinhos de dois pinos com 5V (o 2 e o 4), então é preciso ter cuidado. No roteador, para minha sorte, Rx e Tx estão trocados. Percebi isso apenas depois de ter montado o cabo com pinagem idêntica nas duas pontas. Sorte de principiante.

Como os pinos são muito pequenos e não tenho nenhuma prática com soldagem, pedi ajuda à esposa amada, que, embora também não soubesse soldar, tem mais habilidade. O resultado ficou além do esperado.



Do outro lado, os pinos:


São quatro pinos, porque não havia um conector de três disponível. O quarto pino é de energia (3,3V) e é desnecessário para este projeto.

As instruções para atualizar o firmware via a interface serial estão disponíveis na wiki do OpenWRT. Para esse modelo, há duas opções para carregar o arquivo: via tftp e via a própria interface serial. Como eu estava longe do roteador e usando um Raspberry Pi que não tem uma porta ethernet, resolvi executar tudo pela interface serial.

O primeiro passo é instalar o kermit (para enviar o arquivo) e o minicom (para interagir com o roteador):

sudo apt-get install kermit minicom

A porta serial aparece como o device /dev/serial0 (que é apenas um link para /dev/ttyAMA0). Então, para iniciar a comunicação, o comando é:

minicom -b 115200 -o -D /dev/serial0

E só depois liguei o roteador. Ele não dá muito tempo para interromper a sequência de boot. Assim que aparecer o texto "Autobooting in 3 seconds" é preciso digitar tpl para interromer o processo normal. Pode ser preciso desligar e religar o roteador várias vezes.

Pelo minicom, digitei um comando para limpar um bloco de memória e outro para carregar o arquivo novo:

erase 0xbf020000 +7c0000 
loadb 0x81000000

Depois, noutro terminal, iniciei o kermit sem parâmetros e digitei os seguintes comandos:

set line /dev/serial0
set speed 115200
set carrier-watch off
set handshake none
set flow-control none
robust
set file type bin
set file name lit
set rec pack 1000
set send pack 1000
set window 5
send wr1043nd.bin 

Isso deveria durar uns 20 minutos, mas houve muitos erros na transmissão e o envio levou duas horas. Os erros atribuo à qualidade do meu cabo.


Terminado o envio, dois comandos terminam o processo, copiando o arquivo para o flash e reiniciando o roteador:

cp.b 0x81000000 0xbf020000 0x7c0000
bootm 0xbf020000

Eu entendo que a interface serial esteja escondida, porque seria fácil usar uma interface de 5V (ou 12V) e queimar o equipamento, mas acho que foi economia demais não colocar os pinos (que custam centavos). De qualquer forma, o experimento foi um sucesso e várias habilidades novas foram adquiridas.

sábado, 13 de fevereiro de 2016

Solução caseira para segurança doméstica

As soluções de segurança que tenho visto são caras, então resolvi desenvolver uma solução caseira. Decidi que com um Raspberry Pi, uma câmera barata e um pouco de código, poderia fazer algo tão bom quanto sistemas dez vezes mais caros.

O mais importante é que o sistema deveria enviar notificações para o celular. O Whatsapp não permite robôs, então recorri ao Telegram.

Desenvolvi usando um Raspberry Pi B, mas o sistema final roda num Raspberry Pi A+ (que é ainda menor e mais barato). Acredito que funcionaria igualmente bem num Raspberry Pi Zero (que custa apenas US$5).

A ideia do projeto é bastante simples: a câmera, quando ativada por movimento, copia imagens para o Raspberry Pi e este, por sua vez, as encaminha para uma conta do Telegram. O Telegram entrega as fotos para o meu celular.

Se o código da câmera fosse aberto, ou ela oferecesse alguma API, seria possível que ela falasse diretamente com o Telegram. Ponto negativo para o código fechado.

Ingredientes
  • Um Raspberry Pi B (512MB de RAM, 700MHz de CPU e custa ~US$25);
  • Uma câmera D-Link 930LB (custa menos de R$200,00);
  • Uma conta no Telegram (Whatsapp não aceita robôs);
  • Um cartão de memória SDHC de 16GB (um de 8GB já resolveria);
  • Um pouco de Perl.
Passos

1. Gravar Raspbian no cartão.

2. Instalar um servidor de ftp (sudo apt-get install vsftpd).

3. Configurar o servidor de ftp (/etc/vsftpd.conf).

É preciso habilitar a possibilidade de escrever e de fazer login com contas locais:


local_enable=YES
write_enable=YES


4. Configurar um ramdisk (para não desgastar o cartão de memória, se o número de escritas fugir ao controle e porque é mais rápido).

É preciso adicionar esta linha ao arquivo /etc/fstab:


tmpfs  /home/pi/tmp  tmpfs  nodev,nosuid,size=1M 0 0


Esse comando cria um espaço de 1MB que fica montado no diretório tmp/ dentro do home do usuário pi, mas poderia ser qualquer outro lugar. Os arquivos não passam de 50KB, então essa área poderia ser muito menor.

5. Configurar a câmera.

Configurei a câmera para fazer o ftp da imagem quando for detectado um movimento (usei sensibilidade de 30%, porque ela envia muitas imagens com mais que isso).

O nome do arquivo indiquei como DCS-930LB e isso acaba resultando num arquivo JPEG chamado DCS-930LB.jpg.

6. Criar uma conta no Telegram.

É preciso procurar a conta @BotFather e conversar. Ele dá todas as instruções.

7. Programar em Perl (essa é a melhor parte).

É preciso instalar algumas bibliotecas, o curl, o cpanm e o módulo WWW::Telegram::BotAPI:

sudo apt-get install libnet-ssleay-perl libio-socket-ssl-perl --fix-missing
sudo apt-get install curl
sudo curl -L http://cpanmin.us | perl - --sudo App::cpanminus
sudo cpanm WWW::Telegram::BotAPI

Usei um modelo de robô e fiz algumas adaptações.

Em primeiro lugar, criei ums lista das contas autorizadas (para que estranhos não brinquem com meu robô):


my %chat_ids=(
  123456789=>'forinti',
  987654321=>'derpina'
);


Depois, mudei o loop principal para descansar 5s a cada iteração, verificar se a imagem mudou (pela hora de criação), e enviar a imagem se algo novo surgiu.


my $paused=0;
my $last_update=get_last_update();
while(1) {
  sleep(5);
  my $update=get_last_update();
  if(!$paused && $update>$last_update) {
    for my $id (keys %chat_ids) {
      $api->sendPhoto({
         chat_id=>$id, 
         photo=>{file=>'/home/pi/tmp/DCS-930LB.jpg'}
      });
    } 
    $last_update=$update;
  }
  ...


Finalmente, criei comandos para recuperar a última imagem (/li), parar o envio (/pause) e reiniciar o envio (/go).

sub get_last_update {
  return (stat('/home/pi/tmp/DCS-930LB.jpg'))[9];
}

sub get_last_image {
  return {
    method=>'sendPhoto',
    photo=>{ file=> '/home/pi/tmp/DCS-930LB.jpg' }
  };
}

sub pause {
  $paused=1;
  return 'Parou. Por enquanto...';
}

sub go {
  $paused=0;
  return 'Reiniciou.';
}


Resultado

Consegui produzir um sistema de segurança bastante simples e barato. Ele consome pouquíssima energia (menos de R$10,00 para operar um ano inteiro) e não precisa ser monitorado já que envia alertas. Por usar pouca energia, poderia funcionar ligado a uma bateria ou a um painel solar. Se conectasse a uma rede de celular, seria realmente resiliente.

segunda-feira, 30 de junho de 2014

Raspberry Pi e OpenELEC

As crianças são, surpreendentemente, os maiores usuários do meu Raspberry Pi. Assistir filmes é muito mais simples e rápido do que usar DVDs. Além disso, o meu aparelho de DVD não produz um sinal de alta resolução.

Tenho usado o OpenELEC com um cartão SDHC de 32GB. Ele ocupa cerca de 130MB e deixa o resto do cartão livre. Cada filme ocupa, mesmo em resolução de DVD (720x480), algo entre 500MB e 1GB. Então, consegui colocar todos os DVDs infantis num só cartão.

Além disso, não preciso passar por todas as introduções e menus que os DVDs costumam ter. É um pouco irritante ter que passar por ameaças legais para ver um produto pelo qual paguei.
Posso controlar o OpenELEC pelo celular, usando a aplicação para Android XBMC Remote. O controle remoto utiliza um serviço oferecido pelo OpenELEC via HTTP. Entretanto, ainda é mais simples usar o teclado (mas guardo para impressionar as visitas).

Então, o Pi está se revelando uma ótima opção para computador de viagem. Além de levar filmes para as crianças, poderei fazer cópia de segurança de fotos e filmes. E tudo o que preciso (Pi, cabos, cartões, teclado, etc) cabe dentro de uma caixinha de sorvete de 1,5l e pesa muito menos que um laptop.

terça-feira, 3 de junho de 2014

Raspberry Pi

No final dos anos 1980, o melhor computador disponível era o Archimedes da Acorn. Os primeiros modelos tinham de 512KB a 1MB de RAM e operavam a 4MIPs. O A3000, lançado em 1989, custava 650 libras. Seriam mais de R$5 mil reais hoje (1370 libras de 2012 segundo a calculadora do Banco da Inglaterra), sem contar com as taxas de importação. Em terras brasileiras, tínhamos MSX, PCs, e não muito mais que isso.

Então, com o lançamento do Raspberry Pi, aproveitei a oportunidade de ter alguma coisa semelhante a um Archimedes. O processador é da mesma família, pelo menos (não vamos levantar a questão óbvia de que todos os celulares tem um ARM dentro hoje em dia).

Encomendei da loja inglesa ModMyPi um Pi modelo B (512MB de RAM), uma caixa, e um cartão microSD categoria 10 de 32GB (contendo vários sistemas operacionais para o Pi, inclusive o RISC OS). Gastei 55 libras (uns R$200). Cabos, eu tinha vários sobrando em casa, então só precisei comprar um cabo HDMI para ligar o Pi à TV. Usei um carregador de celular como fonte de energia.

Ele não é muito rápido, mas pode decodificar vídeo. Então, uma de suas utilidades é exibir filmes. Basta gravar o vídeo num pendrive e usar o OpenELEC ou o RaspBMC (ambos os sistemas vêm gravados no cartão de memória).

Apesar de ser bastante modesto na sua capacidade de processamento, ele é rápido o suficiente para emular os computadores de 8 bits dos anos 1980. O primeiro sistema que testei foi o Fuse (emulador de Spectrum). Os jogos são primitivos, mas divertidos. World of Spectrum deve ter quase todos os jogos já escritos para o Spectrum.

Então, essa pequena e barata caixa tem o potencial para tornar-se, sem exigir conhecimento técnico avançado, um centro de diversão, substituindo (com a ajuda da TV) o DVD, o videogame (com jogos mais limitados, claro) e o aparelho de som. Tudo isso consumindo 700mA. Quando tivermos celulares com saída de vídeo e várias portas USB, não haverá motivo para possuir qualquer outro computador (Ubuntu Edge foi a primeira tentativa desse gênero).