Raspberry Pi Pico W + MQTT + HC SR04

Raspberry Pi Pico W + MQTT + HC SR04

Finalmente sono arrivati i Raspberry Pi Pico W. La "W" sta per Wi-Fi o forse Wireless.

Ho iniziato a fare le prime prove scaricando gli esempi e compilandoli.

Se anche tu stai pensando di "giocare" con i Raspberry Pi Pico W sappi che non troverai molta documentazione!

Ne esiste un po per Phyton, ma davvero pochissima per C/C++.

Il repository ufficiale per l'sdk e gli esempi sono:

I primi esperimenti che ho fatto sono stati compilare gli esempi in C/C++  e farli girare sul "Pico W". Non ho avuto particolari problemi se non quelli relativi alla configurazione di Visual Studio Code e tool vari.

Subito dopo ho provato a fare una semplicissima richiesta HTTP. Non esiste un esempio e/o una libreria pronta all'uso e quindi bisogna costruire la richiesta HTTP e inviarla tramite TCP.

GET  / Test/xxx HTTP/1.1\r\nHost: 192.168.100.145:5238\r\n
   

La questione si complica nel momento in cui ho voluto provare a fare una richiesta HTTPS. Immagino che l'unica soluzione sarebbe partire da un libreria di Arduino o ESP8266 (o altro) e riadattarla per il Raspberry Pi Pico W.

Per ora non avendo ne tempo e ne voglia, ho provato a fare lo stesso esperimento con Python. Non conosco Python e non è mai troppo tardi per imparare. Ho utilizzato Thonny per iniziare a prendere la mano con Python, dal semplice Blink sono passato a esempi più complessi.

Mi sono posto un obbiettivo. Interfacciare il Raspberry Pi Pico con un sensore ad ultrasuoni HC SR-04, visualizzare la distanza su un piccolo display ST7789  e inviare la distanza dell'oggetto rilevato tramite MQTT ad un'applicazione desktop fatta in C#.

In realtà avrei potuto utilizzare MQTT anche su HTTP e non su HTTPS, ma va davvero contro i miei principi :P

Le librerie che ho utilizzato sono:

import uos
import machine
from machine import Pin
import st7789py as st7789
import vga2_8x8 as font1
import vga1_16x32 as font2
import random
import network
import time
import urequests
from umqtt.simple import MQTTClient

Determinazione della distanza con Raspberry PI Pico W e HC SR04

trig = Pin(14, Pin.OUT)
echo = Pin(15, Pin.IN, Pin.PULL_DOWN)

Print su display ST7789

Il display che ho utilizzato è un ST7789 240x240 acquistato su AliExpress per qualche euro.

Per gestire il display ho utilizzato https://github.com/devbis/st7789py_mpy che contiene:

  • st7789py 
  • vga2_8x8 
  • vga1_16x32 

Il codice è il seguente:

spi1_sck=10
spi1_mosi=11
spi1_miso=8 
st7789_res = 12
st7789_dc  = 13
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)

display = st7789.ST7789(spi1, disp_width, disp_width,
                          reset=machine.Pin(st7789_res, machine.Pin.OUT),
                          dc=machine.Pin(st7789_dc, machine.Pin.OUT),
                          rotation=0)


display.fill(st7789.BLACK)
display.text(font2, "TEST!", 10, 10)

Invio pacchetto MQTT tramite Raspberry Pi Pico W

Prima di tutto devi registrarti su HiveMQ - Enterprise ready MQTT to move your IoT data

Dopo la registrazione è necessario creare un cluster:

Al cluster va aggiunta una utenza che poi sarà utilizzata per inviare e ricevere i pacchetti:

Adesso passiamo al codice.

La libreria che ho utilizzato umqtt.simple, può essere installata da Thonny (Strumenti -> Gestion Pacchetti).

mqttssl_params= {"server_hostname": "17XXXXXXXXXXXXXX85.s2.eu.hivemq.cloud" }
broker = '17XXXXXXXXXXXXXX85.s2.eu.hivemq.cloud'
mqttport=8883
mqttuser='gimqtttest1'
mqttpassword='LA_PASSWORD'
client_id = 'unclientidacaso'

sub_topic = 'subtopic/1'
pub_topic = 'testtopic/distance'

def sub_cb(topic, msg):
  print((topic, msg))

def connect_and_subscribe():
  global client_id, mqtt_server, topic_sub
  client = MQTTClient(client_id, broker, port=mqttport, user=mqttuser , password=mqttpassword,keepalive=0,ssl=True,ssl_params=mqttssl_params)
  client.set_callback(sub_cb)
  client.connect()
  client.subscribe(sub_topic)
  print('Connected to %s MQTT broker as client ID: %s, subscribed to %s topic' % (broker, client_id, sub_topic))
  return client

def restart_and_reconnect():
  print('Failed to connect to MQTT broker. Reconnecting...')
  time.sleep 10)
  machine.reset()

try:
  client = connect_and_subscribe()
except OSError as e:
  restart_and_reconnect()

pub_msg = 'Hello! Sono il rasberry1!'
client.publish(pub_topic, pub_msg)

Applicazione desktop (C#) per la ricezione del pacchetto MQTT

Per riceve e visualizzare la distanza che il Raspberry Pico W invia ho creato una applicazione WPF in C#.

Prima di tutto è nesessario importare i 2 pacchetti nuget relativi alla libreria MQTTnet:

Il codice C# è il seguente:

private async void BtnTest_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                await Handle_Received_Application_Message();
            }
            catch (Exception ex)
            {
                LogError(ex.ToString());
            }
        }

public async Task Handle_Received_Application_Message()
        {
            var mqttFactory = new MqttFactory();

            var mqttClient = mqttFactory.CreateMqttClient();

            var mqttClientOptions = new MqttClientOptionsBuilder()
                .WithTcpServer(Constants.MqttUrl, Constants.MqttPort)
                .WithCredentials(Constants.MqttUsername, Constants.MqttPassword)
                .WithTls(
                    o =>
                    {
                        o.CertificateValidationHandler = eventArgs =>
                        {

                            return true;
                        };
                    })
                .Build();

            mqttClient.ApplicationMessageReceivedAsync += e =>
            {
                Log("Received application message.");
                Log("Topic: " + e.ApplicationMessage.Topic);

                var payload = System.Text.ASCIIEncoding.ASCII.GetString(e.ApplicationMessage.Payload);
                Log("Payload: " + payload);
                SetDistance(payload);
                return Task.CompletedTask;
            };

            await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);

            var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
               .WithTopicFilter(f => { f.WithTopic("testtopic/distance"); })
               //.WithTopicFilter(f => { f.WithTopic("mqttnet/samples/topic/2"); })
               //.WithTopicFilter(f => { f.WithTopic("mqttnet/samples/topic/2"); })
               .Build();

            await mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);


            Log("MQTT client subscribed to topic.");
        }

Ecco la breadbord: