Raspberry Pi Pico W

O Pico W é uma placa baseada no microntolador RP2040. Foi desenvolvida para ter um custo reduzido, flexível e com uma uma interface wireless de 2.4GHz (Wi-Fi 802.11n).

Para além da utilização independente (stand alone) podemos usar o pico w para comunicar com outros servers. Pode-se, assim, controlar e obter dados através de webserver central que pode ser um raspberry pi 3 ou superior, ou outro qualquer webserver.

Neste exemplo, vamos considerar o PI 3B o "main server" que lê os dados dos vários pico w "Sub Server".
Basicamente, cada pico w tem um webserver num dos IPs da rede, gera uma página de web. Por sua vez, o "main server" lê os dados apresentados em determinada "div" produzida no html da página.

Ler temperatura de vários PICO W

Primeiro vamos instalar um webserver em cada pico W, ligar à rede Wi-Fi existente, atribuir um IP ao pico W. Antes o pico W deve ter a lib picozero instalada

import network
import socket
from time import sleep
from picozero import pico_temp_sensor, pico_led
import machine

ssid = 'Service Name'
password = 'password'

def connect():
    #Connect to WLAN
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)
    wlan.ifconfig(('192.168.1.50', '255.255.255.0', '192.168.1.254', '8.8.8.8'))
    while wlan.isconnected() == False:
        print('Waiting for connection...')
        sleep(1)        
    ip = wlan.ifconfig()[0]
    print(f'Connected on {ip}')
    return ip

def open_socket(ip):
    # Open a socket
    address = (ip,80)
    connection = socket.socket()
    connection.bind(address)
    connection.listen(1)
    return connection

Já temos a conetividade com a rede wireless local. Vamos criar a nossa págian de web, neste casos vamos usar o sensor de temperatura interno da board, ligar e desligar o led da board, usar um sensor de temperatura mais preciso o DS18B20 e controlar um LED ligado a uma das saídas (que podemos usar para ligar qualquer outra coisa).

def webpage(temperature, state, tmpds):
    #Template HTML
    html = f"""
     <!DOCTYPE html> <html> 
<!-- A form permite ligar e desligar 
o led da board e o led externo --> <form action="./lighton"> <input type="submit" value="Light on" /> </form> <form action="./lightoff"> <input type="submit" value="Light off" /> </form> <form action="./ledon"> <input type="submit" value="ledon" /> </form> <form action="./ledoff"> <input type="submit" value="ledoff" /> </form> <!-- Estado do Led externo ON ou OFF --> <p>LED is {state}</p> <!-- Sensor de temperatura interno da board --> <p> Internal Temp is <div class="temp" id="temp">{temperature}</div> </p> <!-- Sensor de temperatura externo DS18B20 --> <p> External Temp <div class="tmpds" id="tmpds">{tmpds}</div> </p> </body> </html> """ return str(html)

Ler a temperatura do sensor externo DS18B20 no PIN 28 e gravar numa variável "tmpds";

import machine, onewire, ds18x20, time

ds_pin = machine.Pin(28)
ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin))

roms = ds_sensor.scan()
//se quisermos testar se o sensor é encontrado removert #
#print('Found DS devices: ', roms) 
ds_sensor.convert_temp()
tmpds = ds_sensor.read_temp(roms[0]) 

Ler temperatura do sensor na board, ligar o webserver

def serve(connection):
    #Start a web server
    state = 'OFF'
    pico_led.off()
    temperature = 0
    while True:
        client = connection.accept()[0]
        request = client.recv(1024)
        request = str(request)
        try:
            request = request.split()[1]
        except IndexError:
            pass
        if request == '/lighton?':
            pico_led.on()
            state = 'ON'
        elif request =='/lightoff?':
            pico_led.off()
            state = 'OFF'
        elif request =='/ledon?':
            leda=Pin(13,Pin.OUT)
            leda.on()
            state = 'on'
        elif request =='/ledoff?':
            leda=Pin(13,Pin.OUT)
            leda.off()
            state = 'off'    
        temperature = pico_temp_sensor.temp
        html = webpage(temperature, state, tmpds)
        client.send(html)
        client.close()
try:
    ip = connect()
    connection = open_socket(ip)
    serve(connection)
except KeyboardInterrupt:
    machine.reset()
 

Agora já temos o nosso webserver que podemos aceder através do ip 192.168.1.50
Mostra-nos a temperatura, podemos desligar e ligar o led da board ou o led externo. Podemos inserir o código em várias boards, todas com um ip único, este exemplo será o que termina em 50, por exemplo vamos usar o mesmo código mas com o ip a terminar em 51 (192.168.1.51)

Como obter estes dados no mainserver

Neste exemplo usou-se php, mas podem ser usadas outras linguagens de programação

a base do código é ler cada um das placas assim, vamos criar uma função que nos permitirá ler cada uma delas
Criamos um ficheiro php, por exemplo, lerdados.php
<?  php 
function sckd ($ip,$divname){ 
$s=socket_create(AF_INET,SOCK_STREAM,SOL_TCP); 
socket_connect($s,$ip,80); 
socket_send($s,"GET / HTTP/1.1\r\nHost: xx.fakedomain.com\r\n\r\n",1000,0); 
socket_recv($s, $buf, 1000000,0); socket_close($s); 
if (!empty ($buf)){ 
 $doc = new DOMDocument; 
 $doc->loadHTML($buf); 
 $xpath = new DOMXPath($doc); 
 $node = $xpath->query("//div[@id='".$divname."']")->item(0); 
 $extemp = trim($node->nodeValue); 
return $extemp; 
} 
else { 
echo "";
} 

} 
 ?> 

Agora podemos obter os dados de cada uma das board usando ip e a div name, divname é o nome da div onde estão os dados que pretendemos. Criamos um ficheiro rpi.php

<?  php 
include 'lerdados.php';
/* Obter dados na div tmpds na board no ip 50 */
$c=round(sckd('192.168.1.50','tmpds'),2);
echo " Temp DS: ".$c." ºC";

/* Obter dados na div temperature na board no ip 50 */
$d=round(sckd('192.168.1.50','temperature'),2);
echo " Temp interna da board: ".$d." ºC";

/* Obter dados na div temperature na board no ip 51 */
$e=round(sckd('192.168.1.51','temperature'),2);
echo " Temp interna da board: ".$d." ºC";
?> 

Podemos obter qualquer dado que o webserver da board ou várias boards coloquem no interior de uma html div. Se o led está ligado, desligado etc etc

Aqui fica a imagem com o teste do código e hardware necessário neste exemplo

Nota: Neste exemplo foi usada a porta 80, a porta standard para o browser em http1.1, porém, pode ser usada qualquer outra porta o que, por questões de segurança, é conveniente. Neste exemplo não foram usadas nenhumas medidas para limitar o acesso, assim, qualquer browser pode aceder sem limitações ao controlo.