树莓派Pico W的初学者组件教程

树莓派pico w组件教程

本 Raspberry Pi Pico W 入门组件教程将教您如何与微控制器互动,从而与 LED、超声波传感器等简单组件以及初学者套件中的许多其他物品互动。

如果您是完全的初学者,本教程将帮助您了解 MicroPython,从而能够读取、编写和修改代码。有了这些知识,您就可以将代码和组件结合起来,创建具有实际用例的东西。

如果您使用的是 Pico,本教程将教您如何无线控制 Pico W。以前,您只能通过开关、按钮或其他物理交互设备与 Pico 进行交互。现在不一样了!现在,您可以用手机或台式机控制组件。

教程流程

简介

  1. 焊接针座引脚
  2. 使用索尼
  3. 更新固件

Pico W 的 Hello World 教程

  1. 在 Pico 上运行一个显示 "Hello World "的网页
  2. 无线控制 LED

更上一层楼

  1. 无线控制 RGB LED
  2. Pico W 的蜂鸣器操作

从传感器传输数据的基本方法

  1. Pico W 和 HC-SR04 超声波传感器
  2. 传送包含传感器数据的网页
  3. 使用 AJAX 减少有效载荷
  4. Pimoroni Phew 简化端点编码

连接网络实用程序

  1. 使用 IFTTT 将 DHT22 传感器的气候数据记录到 Google Sheets 中
  2. 创建具有播放/暂停/跳转功能的 Spotify 遥控器

使用 PiCockpit 进行无代码 GPIO 控制

  1. 在 Pico W 上超级简单地安装 PiCockpit
  2. 使用 PiCockpit 和 Pico W 进行简单的 LED 控制
  3. Pico W、5V 风扇和一个晶体管,由 PiCockpit 控制

MQTT

  1. 使用 Pico W 的 MQTT 和 Node-RED 显示光敏电阻

目录

内容 隐藏

教程目标概述

  • 学习如何与构成大型项目的基本组件互动
  • 无线控制所有这些设备,无需开关、按钮或其他交互设备。
  • 更好地了解 Pico W 的优势

重要链接

Github repo 教程代码(secrets.py 除外)

MicroPython 文档

错误、建议或意见?请在下面的评论框中留言、 发邮件给我推特我.

OSError:[Errno 98] EADDRINUSE

如果出现此错误,请拔下 Raspberry Pi Pico 的电源插头,然后再插上。

您也可以在 Thonny 的 Shell 中键入这些命令:

import machine
machine.reset()

结果

焊接针座引脚

当您购买 Raspberry Pi Pico W 时,它可能没有附带允许您将组件连接到 Pico 的接头。

在撰写本报告时,Pico WH(H 表示标头)尚未发布。 我们的 Pico W 大型文章将跟踪报道其发布情况。

不过,如果您能找到预焊针座的 Pico W,我会建议您购买。

不过,对于我们其他人来说,在 Pico W 上焊接针座是一件很简单的事情。您需要

  • 麵包板
  • 烙铁和焊料
  • 页眉

与 Raspberry Pi Zero 系列的针座不同,Pico W 上的针座不是并排的。它们位于电路板的两端。

一块面包板、Pico W 和 2×20 针座

引脚有长有短。较长的引脚应位于 GPIO 标签(GP0、GP1、GND、VBUS、VSYS 等)所在的一侧。

您希望较长的针脚位于 USB 连接器对面的一侧。

因此,将较长的插针插入面包板。您需要四个孔,孔与孔之间的间距为一个水沟。如果不确定,请用 Pico W 进行测试。

焊接很简单。确保烙铁是热的,并确保使用烙铁头。

我发现最有效的方法是将烙铁头靠近针脚,让焊锡接触到烙铁头,然后看到焊锡顺着针脚流下,形成连接。

焊接完成后,请务必检查并确保没有任何多余的焊料将两个 GPIO 引脚连接在一起,或者电路板上没有剩余的废焊料。

使用 Thonny 作为代码编辑器

Thonny 为 Raspberry Pi Pico W 编程

Thonny 仍是为 Raspberry Pi Pico W 编程的最简单方法。

如果您使用的是 Raspberry Pi 操作系统,那么您已经安装了它。

不过,如果您使用的是 Windows 或 Mac,则需要下载并配置它。

下面的指南将指导您完成这些步骤。

还要确保 请参阅如何将文件上传到 Pico W 的指南。.

上传最新的 UF2 更新固件

当您购买 Pico W 时,您可能已经有了过时的固件。

Pico W 即将发生许多变化,因此现在更新固件是最理想的选择。

自发布之日起,我看到的一些变化是无线局域网接入点功能的改进,未来的更新可能会解锁电路板上的蓝牙功能。

现在更新!下面是我们的大型文章中的指南。


1.在 Pico 上运行一个显示 "Hello World "的网页

Raspberry Pi Pico W 的 "Hello World "项目

Hello World "项目是所有编程教程中最基本的项目之一。

微控制器的 "Hello World "通常是闪烁 LED。 超级简单方法如下

不过,既然 Pico W 可以为网页提供服务,我们就先来学习如何为包含 "Hello World "信息的网页提供服务。

这里使用的设置将构成其余教程的最基本组成部分。

连接 Pico W 有两种方式。 播放与智能手机类似的 SoftAP 热点.如果你想尝试后者、 按此链接.不过,为了与本教程保持一致,我们将始终连接到 WiFi 网络,而不是从 Pico W 广播网络。

因此,从根本上说,为网页提供服务的步骤包括:

  • 连接到WiFi
  • 编写代码,为连接到 Pico W IP 地址的任何人提供 index.html 服务

让我们来设置几个文件。保存这些文件并上传到 Raspberry Pi Pico W。 以下是上传文件的方法,以免您错过。

wifi.py

wifi.py 是一个模板,用于帮助你连接 WiFi 网络。创建一个单独的文件并将其导入 main.py 文件将有助于减少杂乱的代码。

请注意,您应在以下一行中更改您所在国家的代码 rp2.country('DE') 如果您的国家不是德国。

import rp2
import network
import ubinascii
import machine
import urequests as requests
import time
from secrets import secrets


def init_wifi():
    # Set country to avoid possible errors
    rp2.country('DE')

    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)

    # Load login data from different file for safety reasons
    ssid = secrets['ssid']
    pw = secrets['pw']

    wlan.connect(ssid, pw)

    # Wait for connection with 10 second timeout
    timeout = 10
    while timeout > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        timeout -= 1
        print('Waiting for connection...')
        time.sleep(1)

    # Define blinking function for onboard LED to indicate error codes    
    def blink_onboard_led(num_blinks):
        led = machine.Pin('LED', machine.Pin.OUT)
        for i in range(num_blinks):
            led.on()
            time.sleep(.2)
            led.off()
            time.sleep(.2)

    wlan_status = wlan.status()
    blink_onboard_led(wlan_status)

    if wlan_status != 3:
        raise RuntimeError('Wi-Fi connection failed')
    else:
        print('Connected')
        status = wlan.ifconfig()
        print('ip = ' + status[0])

secrets.py

wifi.py 进口 secrets.py在这里您可以存储 WiFi 网络信息。

secrets.py 是一个简单的 JSON 文件,其中包含您的 WiFi SSID 和密码。

secrets = {
    'ssid': 'SM-A520W9371',
    'pw': 'starting',
    }

serve_webpage.py

顾名思义,该页面为连接到 Pico W 的用户提供网站服务。

收到连接后,Pico W 会找到一个名为 index.html 并将其发送给已连接的客户端,如下行所示 response = get_html('index.html').

import socket

def serve_webpage():
    #Function to load in html page    
    def get_html(html_name):
        # open html_name (index.html), 'r' = read-only as variable 'file'
        with open(html_name, 'r') as file:
            html = file.read()
            
        return html

    # HTTP server with socket
    addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

    s = socket.socket()
    s.bind(addr)
    s.listen(1)

    print('Listening on', addr)

    # Listen for connections
    while True:
        try:
            cl, addr = s.accept()
            print('Client connected from', addr)
            response = get_html('index.html')
            cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
            cl.send(response)
            cl.close()
            
        except OSError as e:
            cl.close()
            print('Connection closed')

最后,我们需要创建 index.html 文件,该文件将发送给已连接的客户端。

<!DOCTYPE html>
<html>
    <head>
        <title>Pico W</title>
    </head>
    <body>
        <h1>Hello World</h1>
    </body>
</html>

这是一个简单的 HTML 模板,有两处改动:一处改动了 <title>标记输出 "Pico W "作为标题,<h1> 标记输出 "Hello World"。

main.py

由于我们将所有代码都放在了其他地方,我们的 main.py 文件只需导入并调用这些函数,就能为 Hello World 网页提供服务。

正如您所看到的,我们首先初始化 WiFi,然后才提供网页。

from wifi import init_wifi
from serve_webpage import serve_webpage

init_wifi()
serve_webpage()

你就快成功了

请参考下面的截图,确保

  • 您已向 Raspberry Pi Pico W 上传了五个文件(见左下方红框)。
  • 确保您的解释器设置为 MicroPython (Raspberry Pi Pico) (见右下方方框)
  • 然后,高亮显示 main.py 在代码编辑器中,单击绿色运行按钮(左上角红色方框)
  • 运行后,你将在 Shell 中看到自己的 IP 地址。在浏览器中输入这个地址,就能看到 Hello World 网页。
  • 如果 Shell 未打开,请转到查看 -> Shell。

如果一切顺利,您将看到下面的页面。


2.无线控制 LED

现在,您已经掌握了基础知识,让我们向前迈进一步。

最基本的 Raspberry Pi 项目之一是闪烁 LED。

让我们通过无线方式控制 LED,让它更上一层楼。我们希望能够闪烁、打开和关闭 LED。

为此,您需要设置一个电路和一个网络服务器,其中有三个按钮:ON、OFF、BLINK。

本项目需要一个 LED、一个 330 欧姆的电阻器、一根跳线和一块面包板。

我们将使用红色 LED,因为大多数套件都有这种 LED。请注意,如果使用其他颜色的 LED,则需要调整电阻。

以下是连接组件的方法

  • GPIO 2 -> LED 的长脚(阳极/正极)
  • 接地 -> 330 欧姆电阻 -> LED 短脚(阴极/负极)

控制 Pico W 上 LED 的代码

让我们在上一教程的基础上再接再厉。我们唯一需要修改的两个文件是 index.html 添加按钮和 main.py 的输入与 LED 进行交互。 index.html.

粗体部分表示在以下内容中新增的行 index.html。 他们添加了三个按钮和一段 "控制 LED "的文字。

<!DOCTYPE html>
<html>
    <head>
        <title>Pico W</title>
    </head>
    <body>
        <h1>Pico W</h1>
        <p>Control the LED</p>
        <a href=\"?led=on\"><button>ON</button></a>&nbsp;
        <a href=\"?led=off\"><button>OFF</button></a>
        <a href=\"?led=blink\"><button>BLINK</button></a>
    </body>
</html>

注意,当您按下按钮时,您会看到 Pico W 的 IP 地址中添加了一个参数(例如:"......")。 http://192.168.43.134/%22?led=blink\).这些参数由 Pico W 的后台捕捉并控制 LED。

我们将 serve_webpage.py的代码中 main.py 文件。

这里是 main.py:

from wifi import init_wifi
import socket
import machine
import time

init_wifi()


#LED controls
led = machine.Pin(2, machine.Pin.OUT)
      
def blink_led():
    led.on()
    time.sleep(0.2)
    led.off()
    time.sleep(0.2)

#Function to load in html page    
def get_html(html_name):
    # open html_name (index.html), 'r' = read-only as variable 'file'
    with open(html_name, 'r') as file:
        html = file.read()
        
    return html

# HTTP server with socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('Listening on', addr)

# Listen for connections
while True:
    try:
        cl, addr = s.accept()
        print('Client connected from', addr)
        request = cl.recv(1024)
        print(request)
        
        request = str(request)
        led_on = request.find('?led=on')
        led_off = request.find('?led=off')
        led_blink = request.find('?led=blink')
        print('led_on = ', led_on)
        print('led_off = ', led_off)
        print('led_blink = ', led_blink)
        if led_on > -1:
            print('LED ON')
            led.on()
            
        if led_off > -1:
            print('LED OFF')
            led.off()
            
        if led_blink > -1:
            print('LED BLINK')
            blink_led()
            
        response = get_html('index.html')
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()
        
    except OSError as e:
        cl.close()
        print('Connection closed')

下面是第一部分,也是关键部分:

request = cl.recv(1024)
        print(request)
        
        request = str(request)
        led_on = request.find('?led=on')
        led_off = request.find('?led=off')
        led_blink = request.find('?led=blink')
        print('led_on = ', led_on)
        print('led_off = ', led_off)
        print('led_blink = ', led_blink)
        if led_on > -1:
            print('LED ON')
            led.on()
            
        if led_off > -1:
            print('LED OFF')
            led.off()
            
        if led_blink > -1:
            print('LED BLINK')
            blink_led()

打印变量 "request "时,将输出下面的第一组文本。最后三行是检查 LED 是否打开、关闭或闪烁的打印语句:

b'GET /%22?led=blink\\%22 HTTP/1.1\r\nHost: 192.168.43.134\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\nReferer: http://192.168.43.134/%22?led=on\\%22\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: en-US,en;q=0.9,es;q=0.8,zh-TW;q=0.7,zh-CN;q=0.6,zh;q=0.5\r\n\r\n'
led_on =  456
led_off =  -1
led_blink =  10

上述代码将尝试搜索特定字符串,如"led=on".如果存在,该值将大于-1,从而触发相关的 如果 声明。

例如,如果参数中存在 led=on,那么变量 led_on 的值就会大于-1,因此,...... 如果 led_on > -1 语句触发并运行 led.on();

这里唯一复杂的部分是 闪烁 函数,它将触发该函数:

    def blink_led():
        led.on()
        time.sleep(0.2)
        led.off()
        time.sleep(0.2)

最后,下面介绍如何初始化 GPIO 2 以操作 LED:

import machine
import time
    
#LED controls
led = machine.Pin(2, machine.Pin.OUT)

我们导入机器与 GPIO 引脚交互。正如您在变量 领导我们希望 Pico W 为 GPIO 2 供电。

我们进口 时间 这样我们就可以在 blink_led()。


3.Pico W 上的 RGB LED

要点亮 RGB LED,您需要

  • 三个 330 欧姆电阻
  • 一个 RGB LED
  • 一根跳线

在 RGB LED 上有四条腿。其中一条腿最长。它要么是阴极(负极),要么是阳极(正极)。我的 RGB LED 有一个共用的阴极,所以连接方式是这样的:

图片显示了共阴极 RGB LED 上的 R、G、B 脚。(图片来自 Raspberry Pi 基金会 CC-BY-SA)
  • GPIO 15 -> 330 欧姆电阻 -> 红色 LED
  • GPIO 17 -> 电阻器 -> 绿色 LED
  • GPIO 16 -> 电阻器 -> 蓝色发光二极管

下面是一些代码,看看你的接线是否正确:

import machine

red_led = machine.PWM(machine.Pin(15))
green_led = machine.PWM(machine.Pin(17))
blue_led = machine.PWM(machine.Pin(16))

red_led.duty_u16(65534)
green_led.duty_u16(65534)
blue_led.duty_u16(65534)

在本例中,我们使用的是 PWM,它可以改变 R、G、B LED 的亮度。

您可以将传递给 [color].duty_u16 的值改为 0 到 65534 之间的值。理论上,你应该可以传递 65535,但不知何故,这对我似乎不起作用。

如果输入 "0",就表示亮度为零。如果输入 65534,则表示亮度为 100%。

如果一种颜色为 65534,其他颜色为 0,那么就可以判断出是否将正确的 GPIO 引脚连接到了正确的 LED 颜色上。

那么我们为什么要使用 PWM 呢?因为它能帮助你获得更多的颜色。如果只使用 "开-关 "方法,你可以得到红、绿、蓝、白和无光。有了 PWM,你就可以改变 R、G、B LED 的强度,创造出你能想象到的各种颜色。

现在,让我们创建一个可以无线控制的东西!

index.html

这里的主要变化是 <form 有三个滑块。这些滑块的数值介于 0 和 100 之间。

使用从 0 到 100 的数值有助于将亮度可视化为一个百分比。它还减少了从参数中解析出值所需的代码量(见稍后的 main.py)

设置好 R、G、B LED 的值后,按下提交键,Pico W 就会捕捉到这些数据。

<!DOCTYPE html>
<html>
    <head>
        <title>Pico W</title>
    </head>
      <body>
        <h1>Pico W RGB LED</h1>
        <form id="form">
            
            <input type="range" min="0" max="100" value="slider_value" name="red" id="red">
            <label for="red">R</p>
            
            <input type="range" min="0" max="100" value="slider_value" name="green" id="green">
             <label for="green">G</p>
            
            <input type="range" min="0" max="100" value="slider_value" name="blue" id="blue">
            <label for="blue">B</p>
            
            <input type="submit" id="submit">
        </form>
        <script>
        
            submit.addEventListener('click', function ()  {
                form.submit();
            }, false);
        
        </script>
</html>

main.py

from wifi import init_wifi
import socket
import machine
import time

init_wifi()

#LED controls
red_led = machine.PWM(machine.Pin(15))
green_led = machine.PWM(machine.Pin(17))
blue_led = machine.PWM(machine.Pin(16))

#Function to load in html page    
def get_html(html_name):
    # open html_name (index.html), 'r' = read-only as variable 'file'
    with open(html_name, 'r') as file:
        html = file.read()
    return html

def find_intensity(color, request_str):
    index = request_str.find(color) + len(color)
    offset = 0
    if request_str[index].isdigit():
        offset = 1
        if request_str[index+1].isdigit():
            offset = 2
            if request_str[index+2].isdigit():
                offset = 3

    intensity = int(request_str[index:index+offset])
    return intensity
    
    
# HTTP server with socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('Listening on', addr)

# Listen for connections
while True:
    try:
        cl, addr = s.accept()
        print('Client connected from', addr)
        request = cl.recv(1024)
        
        request_str = str(request)
       
        #find intensity ONLY if the params exist in request
        if request_str.find('red') > -1 :
            #int = get rid of decimal
            #/100*65534 = find_intensity returns something 0 to 100,
            # so x/100 = proportion of 65534 that you want to send to LED
            # 65534 = max number you can use for PWM
            red_intensity = int(find_intensity('red=', request_str) /100 * 65534)
            green_intensity = int(find_intensity('green=', request_str) /100 * 65534)
            blue_intensity = int(find_intensity('blue=', request_str) /100 * 65534)
            
            #print('r=' + str(red_intensity))
            #print('g=' + str(green_intensity))
            #print('b=' + str(blue_intensity))
            
            red_led.duty_u16(red_intensity)
            green_led.duty_u16(green_intensity)
            blue_led.duty_u16(blue_intensity)
                        
        response = get_html('index.html')
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()
        
    except OSError as e:
        cl.close()
        print('Connection closed')

当您在 index.html 网页,Pico W 将获取参数并进行处理。

让我们来看看代码中的一些关键点,上面的代码块中用粗体标出了这些关键点。

查找强度函数

该函数需要两个参数: 颜色 request_str. 颜色 输入 "红"、"绿 "或 "蓝",并找出等号(=)后面的值。

例如,您提交表单后的 URL 是 "http://192.168.1.142/?red=89&green=50&blue=50"。

如果向 find_intensity 传递 "red",它将返回 89。

强度解析器

第二个粗体代码块表示告诉 Pico W 的 GPIO 您想要每个 LED 多大亮度的代码。

首先,我们必须确保 URL 中存在参数。这可以通过 如果 声明 request_str.find('red') > -1.我只是用了 红色 因为如果使用该表单,参数 100% 将包含字符串 "red"。

如果您是第一次访问 Pico W 的 IP 地址(例如 http://192.168.1.142/),您将没有参数,因此如果运行 查找强度.

如果存在参数,我们将根据提交的值找到每个 LED 的强度。让我们看看 红色强度。

red_intensity = int(find_intensity('red=', request_str) /100 * 65534)
...
red_led.duty_u16(red_intensity)

查找强度 返回 0 到 100 的整数。我们将其除以 100,就可以得到一个百分比。这个百分比除以 duty_u16 可以采取的方法。

然而,我们需要一个 䵮䵮 函数来封装它,因为有时您可以得到一个浮点数,而 duty_u16 需要 䵮䵮.例如,您需要 41% 的亮度 - 41% 的 65534 等于 26,868.94。您不能传递这个浮点数,否则程序会崩溃。


4.Pico W 的蜂鸣器操作

蜂鸣器是一个非常重要的基本通知组件,就像 LED 可以告诉你某样东西的状态一样,蜂鸣器也可以给你一个听觉通知。

将蜂鸣器的正极连接至 GPIO 16,并将地线连接至 Pico W 的 GND 引脚。

我没有执行自己的代码,而是选择使用 朱塞佩-卡西巴的执行情况.如果您在 Pico W 上运行了他的代码,您将听到蜂鸣器发出蜂鸣声。

但由于该代码是为 Pico 编写的,因此不具备任何无线互动功能。

那么,我们把叉子拿出来吧!

首先,让我们修改 index.html 来实现按钮。让我们为 "ON"、"OFF"、"SCALE "和 "MUSIC "设置一个按钮。

前两个按钮不言自明。第三个按钮播放 C 音阶,最后一个按钮播放一段音乐。

<!DOCTYPE html>
<html>
    <head>
        <title>Pico W</title>
    </head>
    <body>
        <h1>Pico W Buzzer</h1>
        <p>Control the buzzer</p>
        <a href=\"?buzzer=on\"><button>ON</button></a>&nbsp;
        <a href=\"?buzzer=off\"><button>OFF</button></a>
        <a href=\"?buzzer=scale\"><button>SCALE</button></a>
        <a href=\"?buzzer=music\"><button>MUSIC</button></a>
    </body>
</html>

就像以前一样,我们创建几个 <button> 标记 <a> 标记。点击按钮后,URL 将包含一个参数,例如 /buzzer=on.Pico W 读取此信息并打开蜂鸣器。

现在,让我们看看 Giuseppe 为 Pico 编写的代码:

from machine import Pin, PWM
from time import sleep

buzzerPIN=16
BuzzerObj=PWM(Pin(buzzerPIN))

def buzzer(buzzerPinObject,frequency,sound_duration,silence_duration):
    # Set duty cycle to a positive value to emit sound from buzzer
    buzzerPinObject.duty_u16(int(65536*0.2))
    # Set frequency
    buzzerPinObject.freq(frequency)
    # wait for sound duration
    sleep(sound_duration)
    # Set duty cycle to zero to stop sound
    buzzerPinObject.duty_u16(int(65536*0))
    # Wait for sound interrumption, if needed 
    sleep(silence_duration)


# Play following notes by changing frequency:
#C (DO)
buzzer(BuzzerObj,523,0.5,0.1)

#D (RE)
buzzer(BuzzerObj,587,0.5,0.1)

#E (MI)
buzzer(BuzzerObj,659,0.5,0.1)

#F (FA)
buzzer(BuzzerObj,698,0.5,0.1)

#G (SOL)
buzzer(BuzzerObj,784,0.5,0.1)

#A (LA)
buzzer(BuzzerObj,880,0.5,0.1)

#B (SI)
buzzer(BuzzerObj,987,0.5,0.1)

#Deactivates the buzzer
BuzzerObj.deinit()

当使用函数 蜂鸣器(),其中包含四个参数:蜂鸣器对象、频率(赫兹)、声音持续时间和播放下一个声音前的暂停时间。

让我们修改代码,以便激活 开、关、比例 音乐.

以下是我们如何将 Giuseppe 的代码集成到我们的 main.py:

from wifi import init_wifi
import socket
import machine
import time

init_wifi()

# Buzzer
buzzerPIN = 16
BuzzerObj = machine.PWM(machine.Pin(buzzerPIN))


def buzzer(buzzerPinObject, frequency, sound_duration, silence_duration):
    # Set duty cycle to a positive value to emit sound from buzzer
    buzzerPinObject.duty_u16(int(65536*0.2))
    # Set frequency
    buzzerPinObject.freq(frequency)
    # wait for sound duration
    time.sleep(sound_duration)
    # Set duty cycle to zero to stop sound
    buzzerPinObject.duty_u16(int(65536*0))
    # Wait for sound interrumption, if needed
    time.sleep(silence_duration)

# Function to load in html page


def get_html(html_name):
    # open html_name (index.html), 'r' = read-only as variable 'file'
    with open(html_name, 'r') as file:
        html = file.read()

    return html


# HTTP server with socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('Listening on', addr)

# Listen for connections
while True:
    try:
        cl, addr = s.accept()
        print('Client connected from', addr)
        request = cl.recv(1024)

        request = str(request)
        buzzer_on = request.find('?buzzer=on')
        buzzer_off = request.find('?buzzer=off')
        buzzer_scale = request.find('?buzzer=scale')
        buzzer_music = request.find('?buzzer=music')

        if buzzer_on > -1:
            BuzzerObj.duty_u16(int(65536*0.2))
            BuzzerObj.freq(440)

        if buzzer_off > -1:
            BuzzerObj.duty_u16(0)

        if buzzer_scale > -1:
            #C (DO)
            buzzer(BuzzerObj, 523, 0.5, 0.1)

            #D (RE)
            buzzer(BuzzerObj, 587, 0.5, 0.1)

            #E (MI)
            buzzer(BuzzerObj, 659, 0.5, 0.1)

            #F (FA)
            buzzer(BuzzerObj, 698, 0.5, 0.1)

            #G (SOL)
            buzzer(BuzzerObj, 784, 0.5, 0.1)

            #A (LA)
            buzzer(BuzzerObj, 880, 0.5, 0.1)

            #B (SI)
            buzzer(BuzzerObj, 987, 0.5, 0.1)

            BuzzerObj.deinit()

        if buzzer_music > -1:
            pass

        response = get_html('index.html')
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()

    except OSError as e:
        cl.close()
        print('Connection closed')

在上述实现中,我们没有为 音乐.

代码与上面的红色 LED 教程非常相似,Pico W 会捕获 Pico W IP 地址后面的参数。如果参数 蜂鸣器=ON、 就会播放 440Hz 的声音。如果 buzzer=scale,它就会播放取自 Giuseppe 代码的音阶。

如何实现音乐?音乐的实现比较复杂,因此我们应该创建一个名为 constants.py 并在我们的 main.py.

该代码是从 Rowan Packard 的 Arduino 代码。

constants.py

A3F = 208  # 208 Hz
B3F = 233  # 233 Hz
B3 = 247  # 247 Hz
C4 = 261  # 261 Hz MIDDLE C
C4S = 277  # 277 Hz
E4F = 311  # 311 Hz
F4 = 349  # 349 Hz
A4F = 415  # 415 Hz
B4F = 466  # 466 Hz
B4 = 493  # 493 Hz
C5 = 523  # 523 Hz
C5S = 554  # 554 Hz
E5F = 622  # 622 Hz
F5 = 698  # 698 Hz
F5S = 740  # 740 Hz
A5F = 831  # 831 Hz

main.py (黑体字为新增内容)

from wifi import init_wifi
import socket
import machine
import time
from constants import *

init_wifi()

# Buzzer
buzzerPIN = 16
BuzzerObj = machine.PWM(machine.Pin(buzzerPIN))


def buzzer(buzzerPinObject, frequency, sound_duration, silence_duration):
    # Set duty cycle to a positive value to emit sound from buzzer
    buzzerPinObject.duty_u16(int(65536*0.2))
    # Set frequency
    buzzerPinObject.freq(frequency)
    # wait for sound duration
    time.sleep(sound_duration)
    # Set duty cycle to zero to stop sound
    buzzerPinObject.duty_u16(int(65536*0))
    # Wait for sound interrumption, if needed
    time.sleep(silence_duration)

# Function to load in html page


def get_html(html_name):
    # open html_name (index.html), 'r' = read-only as variable 'file'
    with open(html_name, 'r') as file:
        html = file.read()

    return html


# HTTP server with socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('Listening on', addr)

# Listen for connections
while True:
    try:
        cl, addr = s.accept()
        print('Client connected from', addr)
        request = cl.recv(1024)

        request = str(request)
        buzzer_on = request.find('?buzzer=on')
        buzzer_off = request.find('?buzzer=off')
        buzzer_scale = request.find('?buzzer=scale')
        buzzer_music = request.find('?buzzer=music')

        if buzzer_on > -1:
            BuzzerObj.duty_u16(int(65536*0.2))
            BuzzerObj.freq(440)

        if buzzer_off > -1:
            BuzzerObj.duty_u16(0)

        if buzzer_scale > -1:
            #C (DO)
            buzzer(BuzzerObj, 523, 0.5, 0.1)

            #D (RE)
            buzzer(BuzzerObj, 587, 0.5, 0.1)

            #E (MI)
            buzzer(BuzzerObj, 659, 0.5, 0.1)

            #F (FA)
            buzzer(BuzzerObj, 698, 0.5, 0.1)

            #G (SOL)
            buzzer(BuzzerObj, 784, 0.5, 0.1)

            #A (LA)
            buzzer(BuzzerObj, 880, 0.5, 0.1)

            #B (SI)
            buzzer(BuzzerObj, 987, 0.5, 0.1)

            BuzzerObj.deinit()

        if buzzer_music > -1:
            pause = 0.05
            # pauses between notes
            t = 0.125
            # time that music note plays

            music_notes = [B4F, B4F, A4F, A4F,
                           F5, F5, E5F, B4F, B4F, A4F, A4F, E5F, E5F, C5S, C5, B4F,
                           C5S, C5S, C5S, C5S,
                           C5S, E5F, C5, B4F, A4F, A4F, A4F, E5F, C5S,
                           B4F, B4F, A4F, A4F,
                           F5, F5, E5F, B4F, B4F, A4F, A4F, A5F, C5, C5S, C5, B4F,
                           C5S, C5S, C5S, C5S,
                           C5S, E5F, C5, B4F, A4F, A4F, A4F, E5F, C5S, C5S]

            rhythm = [1, 1, 1, 1,
                      3, 3, 6, 1, 1, 1, 1, 3, 3, 3, 1, 2,
                      1, 1, 1, 1,
                      3, 3, 3, 1, 2, 2, 2, 4, 8,
                      1, 1, 1, 1,
                      3, 3, 6, 1, 1, 1, 1, 3, 3, 3, 1, 2,
                      1, 1, 1, 1,
                      3, 3, 3, 1, 2, 2, 2, 4, 8, 4]

            for i in range(len(music_notes)):
                buzzer(BuzzerObj, music_notes[i], rhythm[i]*t, pause)

        response = get_html('index.html')
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()

    except OSError as e:
        cl.close()
        print('Connection closed')

如您所见,这里有两个数组、 音乐注释律动.然后运行一个 for 循环,将这些值放入 蜂鸣器() 函数。此外,在代码的顶部,我们从 constants.py.

ǞǞǞ 蜂鸣器() 函数还使用了两个新变量 t暂停.这两个变量可以帮助您调整音乐的节奏。 t 定义每个音符的演奏时间,以及 暂停 定义音符之间的静音时间。


5.Pico W 和 HC-SR04 超声波传感器

微型-W-超声波传感器
`

在前面的教程中,我们一直使用 Pico W 向 LED 和蜂鸣器发送命令。

但如果我们用 Pico W 来接收信息呢?

在这种情况下,我们谈论的是 HC-SR04 超声波距离传感器。

当您插入超声波传感器时,请务必了解它是 5V 还是 3.3V 元件。我将 5V 版本插入 3.3V 引脚,程序没有任何反应,下面我将与大家分享。一旦我将电源移到 5V 引脚上,立即就有了反应。

显然,一些较新版本的 HC-SR04 可以接受 3.3V 和 5V 电压。也许最好先试试 3.3V 引脚,看看是否有结果。如果没有,再试试 5V。

这里有原理图和您可以在 Thonny 中运行的程序。如果得到响应,说明您已经按正确的方式插入了所有设备,包括电压。

接线

HC-SR04 传感器标有引脚的接线如下:

  • VCC 至 3.3V 或 5V 引脚 (如有疑问,请先尝试 3.3V 电压)
  • TRIG 至 GPIO 16
  • ECHO 至 GPIO 15
  • 接地至接地

HC-SR04 的测试程序

为了测试您的接线是否正确,请尝试以下代码,它将在 Thonny Shell 上打印出距离。

from machine import Pin
import time
trigger = Pin(16, Pin.OUT)
echo = Pin(15, Pin.IN)
def ultrasonic():
   trigger.low()
   time.sleep_us(1)
   trigger.high()
   time.sleep_us(10)
   trigger.low()
   while echo.value() == 0:
       signaloff = time.ticks_us()
   while echo.value() == 1:
       signalon = time.ticks_us()
   timepassed = signalon - signaloff
   distance = (timepassed * 0.0340) / 2
   print("Distance = ",distance,"cm")
while True:
   ultrasonic()
   time.sleep(1)

输出结果应为

Distance =  9.707001 cm
Distance =  9.707001 cm
Distance =  8.619 cm
Distance =  8.415001 cm
Distance =  8.551001 cm
Distance =  8.551001 cm
Distance =  8.619 cm

如果程序运行后退出,但没有任何输出,则可能是接线错误。当我将传感器插入 3.3V 引脚而不是 5V 引脚时,程序退出时没有任何反应。

获取发送到浏览器的数据

让我们打开用于提供网页的文件,并对其进行修改,以便查看距离值。

这是最终代码:

main.py

from wifi import init_wifi
import socket
from machine import Pin
import time

init_wifi()

# ultrasonic sensor pins and functions
trigger = Pin(16, Pin.OUT)
echo = Pin(15, Pin.IN)


def ultrasonic():
    trigger.low()
    time.sleep_us(1)
    trigger.high()
    time.sleep_us(10)
    trigger.low()
    while echo.value() == 0:
        signaloff = time.ticks_us()
    while echo.value() == 1:
        signalon = time.ticks_us()
    timepassed = signalon - signaloff
    distance = (timepassed * 0.0340) / 2
    return distance

# Function to load in html page

def get_html(html_name, distance):
    # open html_name (index.html), 'r' = read-only as variable 'file'
    with open(html_name, 'r') as file:
        html = file.read()
    content = html.replace(
        "<h2 id=\"ultrasonic\"></h2>", f"<h2 id=\"ultrasonic\">{distance}cm</h2>")

    return content


# HTTP server with socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('Listening on', addr)

# Listen for connections
while True:
    try:
        cl, addr = s.accept()
        print('Client connected from', addr)
        request = cl.recv(1024)
        print(ultrasonic())
        response = get_html('index.html', ultrasonic())
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()

    except OSError as e:
        cl.close()
        print('Connection closed')

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Pico W</title>
    </head>
      <body>
        <h1>Pico W Ultrasonic Distance</h1>
        <h2 id="ultrasonic"></h2>
        <script>
            setInterval(() => location.reload(), 500)
        </script>
</html>

让我们看一些代码片段来了解发生了什么。

获取超声波距离的代码

def ultrasonic():
    trigger.low()
    time.sleep_us(1)
    trigger.high()
    time.sleep_us(10)
    trigger.low()
    while echo.value() == 0:
        signaloff = time.ticks_us()
    while echo.value() == 1:
        signalon = time.ticks_us()
    timepassed = signalon - signaloff
    distance = (timepassed * 0.0340) / 2
    return distance

上述代码块触发超声波发射。该 time.sleep 低点和高点之间的距离是超声波传感器工作所必需的。

为了测量从发射超声波到声波返回所需的时间,我们使用以下方法 time.ticks_us 以测量发射时间和检测到回声的时间。

time.ticks_us 是一个任意数,因此我们必须减去 信号灯 signaloff 让时间流逝。

要得到距离,我们使用公式 距离 = (经过的时间 * 音速) / 2. 声速为 340 米/秒,因此为 0.0340。

之所以要除以 2,是因为声波传到物体后又返回。

为网页提供距离值的代码

def get_html(html_name, distance):
    # open html_name (index.html), 'r' = read-only as variable 'file'
    with open(html_name, 'r') as file:
        html = file.read()
    content = html.replace(
        "<h2 id=\"ultrasonic\"></h2>", f"<h2 id=\"ultrasonic\">{distance}cm</h2>")

    return content

...

response = get_html('index.html', ultrasonic())

与之前的教程相比,该函数稍作修改,增加了一个参数 距离运行 超声波().

功能打开 index.html 文件,但使用 顶替 方法来查找 <h2> 并插入 距离 变量。

index.html 每 500ms pings 服务器一次,以获取新值

index.html

主网页接收一个每 500ms 重载一次网页的功能。每次重新加载都会 ping Pico W 以获取新的超声波距离值。

    <script>
            setInterval(() => location.reload(), 500)
        </script>

6.超声波数据,但让我们使用 AJAX 来减少有效载荷

上一个教程的工作原理是让 Raspberry Pi Pico W 发送一个全新的 index.html 文件。

这样做是可行的,但效率却低得惊人,因为整个 index.html 当您只需要更新超声波距离数据时,系统就会重新发送"......"。

我们希望得到与上一教程相同的结果,但不需要像上一方法那样繁重的工作量。

因此,我们需要让客户端(您的手机或电脑)ping 一个只响应超声波数据的端点。

新方法是这样的:如果人们访问根 URL,例如 192.168.1.119,他们将得到 index.html.

index.html 的 JavaScript 会 ping /data 端点,触发 Pico W 获取超声波距离数据并作出响应。

那么 index.html 将接收这些数据并更新网页。

拼接来自客户端的请求

请记住,在 main.py总有一句话说 requests = cl.recv(1024).请求对象看起来有点像这样:

b'GET /data HTTP/1.1
Host: 192.168.1.119
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.1.119/data
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,es;q=0.8,zh-TW;q=0.7,zh-CN;q=0.6,zh;q=0.5

首先,我们需要过滤掉这堵文字墙。

我们使用 查找() 方法来查找 要求 变量是否有"/data"。如果有,则回应超声波距离数据。如果没有"/data",则用 index.html.

之前

request = cl.recv(1024)
        print(ultrasonic())
        response = get_html('index.html', ultrasonic())

之后

 request = cl.recv(1024)
        request = str(request)
        print (request.find('/data'))
        if (request.find('/data') > -1):
            #if string is found, respond with data.
            response = str(ultrasonic())
        else:
            response = get_html('index.html', ultrasonic())

如果您在浏览器中访问 /data,就会看到打印的距离值,如下所示。

以前,后台几乎可以处理一切。在作为 index.html 提供之前,超声波距离已被修改。

现在 index.html 从 Pico W 获取传感器数据,因此我们必须对 HTML 文件中的 JavaScript 做一些修改。修改内容以粗体标出。

<!DOCTYPE html>
<html>
    <head>
        <title>Pico W</title>
    </head>
      <body>
        <h1>Pico W Ultrasonic Distance</h1>
        <h2 id="ultrasonic"></h2>
        <script>
            //instead of hardcoding, use address which browser accessed Pico W.
            const PicoAddress = window.location.href

            const getData = async () => {
                //there is a slash at the end of PicoAddress, so don't use "/data". use "data"
                const data = await fetch(`${PicoAddress}data`);
                //response is just a string, so use data.text() to decode the Response's body
                const distance = await data.text();
                //target ultrasonic id and change its inner HTML
                ultrasonic.innerHTML = `${distance} cm`;
                //run getData() again.
                setInterval(getData,100)
                //you can run getData() but it seems more optimized if you give it some time to breathe
            };

            getData();
           
        </script>
</html>

代码的核心是 获取 API 和最新的 async/await 在此合成。

功能 getData() ping Pico W 的 /data 端点,Pico W 会作出回应。我们要确保程序在得到完整响应之前不会跳转,要求它 .

Fetch 将成为一个响应对象,您需要使用 Response.text() 方法来获取响应的正文。因此,以下几行 const distance = await data.text();

获得超声波数据后,我们将更改 <h2 id="”ultrasonic”"> 元素的内部 HTML(开始时为空)中的距离数据。您可以使用 本我 而不使用 getElementById()querySelector() 方法。

完成所有代码后,我们要再次运行 getData()。为什么我要使用 设置间隔 设置 100ms 的间隔?

我发现,如果调用 getData()时不设时间间隔,输出之间的停顿会更多。你会得到一连串快速更新,然后暂停。有了 100 毫秒的喘息空间,Pico W 运行得更好了,而且更新看起来多少还是实时的。

如果您想了解引擎盖下发生了什么,请参考 获取 API 文档async/await 文件。


7.Pimoroni 呼,代码更简洁了

Pimoroni Phew 用于传送超声波数据

在上一节中,我们介绍了更新超声波传感器数据的 AJAX 方法。

但有没有更好的办法呢?

Pimoroni's Phew 是一个可以帮助你轻松完成大量网络工作的库,因为你可以避免大量的药物工作。

目标是一致的:

  • 获取超声波数据并显示在 index.html
  • 尽可能降低有效载荷。

方法如下 main.py 看起来像

from wifi import init_wifi
from phew import server
from phew.template import render_template
from machine import Pin
import time

init_wifi()

# ultrasonic sensor pins and functions
trigger = Pin(16, Pin.OUT)
echo = Pin(15, Pin.IN)


# Function to load in html page

@server.route("/data", methods=["GET"])
def ultrasonic(request):
    trigger.low()
    time.sleep_us(1)
    trigger.high()
    time.sleep_us(10)
    trigger.low()
    while echo.value() == 0:
        signaloff = time.ticks_us()
    while echo.value() == 1:
        signalon = time.ticks_us()
    timepassed = signalon - signaloff
    distance = (timepassed * 0.0340) / 2
    return str(distance), 200


@server.catchall()
def catchall(request):
    return render_template("index.html")


server.run()

正如你所看到的,代码的可读性大大提高,因为你可以设置端点,并将它们与返回特定数据的函数连接起来。

你只需调用 Phew 库中的一个函数,而不必再费力地编写代码来运行套接字。

Phew 的一些特点是

  • 不再使用 request.find() 创建端点
  • 没有更多 get_html() 函数打开 index.html 文件,只需使用 Phew 的 render_template()
  • main.py 阅读起来就容易多了,而且只需付出很少的努力!
  • Phew 还添加了日志功能,让你可以更轻松地调试代码。

唯一的缺点是,Phew 仍然是 "一个非常新的项目,充其量只能算作是阿尔法阶段"。因此,有时你可能会遇到意想不到的障碍。

来看看

前面的教程介绍了如何通过电脑/手机与 Pico W 互动。

让我们走出这一步,让 Pico W 与云服务互动。

为此,让我们用 DHT22 传感器制作一个温湿度记录器,通过 IFTTT 将数据发送到 Google Sheets。


8.将 DHT22 温湿度传感器安装到 Pico W 上

Raspberry Pi Pico W 搭配 DHT22 温湿度记录仪。

所有这些步骤都适用于 DHT11 和 DHT22。两者的主要区别在于读数的准确性。DHT11 是蓝色的,而 DHT22 是白色的。

如果您有 DHT11,请注意代码中对 DHT22 的引用应改为 DHT11。例如

import dht
#dht22 = dht.DHT22(Pin(16))
#should be
dht11 = dht.DHT11(Pin(16))
DHT22 引脚

如下图所示,DHT22 从上到下的第一个引脚连接 3.3V。

第二个引脚是数据引脚。您需要为它供电。因此,将一个 10K 欧姆电阻从电源轨连接到它,然后将另一根跳线连接到 Raspberry Pi Pico 上的 GPIO 16。

GND 连接至 GND。

要测试传感器,请执行以下操作:

from machine import Pin
import dht

# ultrasonic sensor pins and functions
dht22 = dht.DHT22(Pin(16))

print(dht22.measure())
print(dht22.temperature())
print(dht22.humidity())

如果你得到 OSError:[Errno 110] ETIMEDOUT 意味着您过早地运行了脚本。DHT22 需要中断两秒钟才能返回另一个值。DHT11 需要一秒钟。

连接 IFTTT 和 Google Sheets

Pico W 将时间、温度和湿度数据记录到 Google Sheets 中

从 Pico W 到 Google Sheets 获取数据的最简单方法是通过 IFTTT。

首先。 注册 IFTTT 账户.

然后,点击 "创建 "按钮创建小程序。

您将看到此屏幕:

点击 "If This(如果)"并搜索 Webhooks。点击 "接收网络请求"。不要选择 JSON 类型。将事件命名为 "dht22"。事件名称非常重要,因为 IFTTT 可以据此知道要触发哪个小程序。

选择此选项,而不是 JSON 有效载荷选项。

您在这里要做的就是创建一个端点,您可以用 DHT22 的传感器数据 ping 这个端点。

然后,点击 "然后"。选择 "Google Sheets"。然后选择 "向电子表格添加行"。你必须链接你的 Google Sheets 账户。

将 "电子表格名称 "和 "驱动器文件夹路径 "改为你想要的任何内容。这里唯一关键的是 "格式化行",你希望它是

{{OccurredAt}} ||| {{Value1}} ||| {{Value2}}

现在,您需要获取 Pico W 可以发送传感器数据的端点。

前往 https://ifttt.com/maker_webhooks 并点击 "文档"。

文档会告诉您密钥、需要发送数据的端点以及如何构建 JSON 主体。

由于您使用了 "dht22 "作为事件名称,因此您的端点是

ttps://maker.ifttt.com/trigger/dht22/with/key/[your_key_here]

您还需要像这样构建 JSON 主体:

{'value1': *** temperature data *** , value2': *** humidity data *** }

对 Pico W 进行编码,以获取 DHT22 数据并将其发送至 IFTTT

以下是方法。

from machine import Pin
from wifi import init_wifi
import urequests
import ujson
import dht
import time

init_wifi()

dht22 = dht.DHT22(Pin(16))


def send_data():
    #tell dht22 to take a reading
    dht22.measure()
    #find temp & humidity data and then jsonify data.
    dht_data = {'value1': str(dht22.temperature()),
                'value2': str(dht22.humidity())}
    post_data = ujson.dumps(dht_data)
    request_url = 'https://maker.ifttt.com/trigger/dht22/with/key/[your_key_here]'
    res = urequests.post(request_url, headers={
                         'content-type': 'application/json'}, data=post_data)
    #log response from IFTTT.
    print(res.text)
    #sleep for a minute before running send_data again
    time.sleep(1*60)
    send_data()


send_data()

如果您要复制这段代码,请确保替换为 [你的钥匙在此] 客栈 request_url 变量。

每分钟都会有一个新的读数记录到 Google Sheet 中,如下所示。

Pico W 将时间、温度和湿度数据记录到 Google Sheets 中

请注意,记录的是摄氏温度。如果您想要华氏温度,公式如下:

fahrenheit = dht22.temperature() * 1.8000 + 32.00

如果您希望更频繁(或更少)地记录数据,请更改 time.sleep().

使用 IFTTT 在发生错误时通知您

当然,这些代码仍然相当脆弱。

比方说,出了点差错。例如,当你放在地板上记录温度时,你的猫拉扯了 3.3V 跳线。

程序会死机,但你不会收到任何通知,直到你发现你的数据没有被记录下来。

如何解决这个问题?

那么,让 IFTTT 在发生这种情况时向你发送通知吧!

您需要在手机上安装 IFTTT 应用程序。请下载。

然后,创建一个新的 applet。

对于 "如果这样 部分,选择 Webhooks -> 接收网络请求.为您的活动命名"错误".

对于"然后这样" 部分,选择"通知"和 "从 IFTTT 应用程序发送通知".

我的信息很简单

Error: {{Value1}}

现在,让我们构建 try-error 块。

from machine import Pin
from wifi import init_wifi
import urequests
import ujson
import dht
import time

init_wifi()

dht22 = dht.DHT22(Pin(16))


def send_data():
    # tell dht22 to take a reading
    dht22.measure()
    # find temp & humidity data and then jsonify data.
    dht_data = {'value1': str(dht22.temperature()),
                'value2': str(dht22.humidity())}
    post_data = ujson.dumps(dht_data)
    request_url = 'https://maker.ifttt.com/trigger/dht22/with/key/[your-key-here]'
    res = urequests.post(request_url, headers={
                         'content-type': 'application/json'}, data=post_data)
    # log response from IFTTT.
    print(res.text)
    # sleep for a minute before running send_data again
    time.sleep(1*60)
    send_data()


try:
    send_data()
except Exception as e:
    print(e)
    request_url = 'https://maker.ifttt.com/trigger/error/with/key/[your-key-here]'
    post_data = ujson.dumps({"value1": str(e)})
    urequests.post(request_url, headers={
        'content-type': 'application/json'}, data=post_data)

试试看。拔下 DHT22 上的 3.3V 接线,就会收到这样的通知:


9.用 Raspberry Pi Pico W 制作 Spotify 物理遥控器

在上一个项目的基础上,我们将使用 IFTTT 来控制 Spotify。

我们将创建一个具有播放、暂停和跳过曲目按钮的设备。

使用 IFTTT 控制 Spotify 的主要好处是非常简单。

缺点是你需要一个付费的 Spotify 账户,而且响应速度较慢。也就是说,如果你按下跳过按钮,你必须等上一段时间才能看到结果。

拥有专用 Spotify 遥控器的好处在于,你可以更换音乐,而无需随身携带手机或打开 Spotify 应用程序。

如果你驾驶过现代汽车,你就会知道方向盘控制有多好。

连接远程 Spotify 控制器

Spotify Raspberry Pi Pico W 控制器
Spotify Raspberry Pi Pico W 控制器。从上到下,按钮分别是暂停、播放、跳过曲目。

您需要...

  • 7x 跳线
  • 3x 按钮
  • 树莓派Pico W
  • Spotify 付费账户

图片上有很多电线交错在一起,所以这里有一个文字说明。

按钮就像开关。您需要将 3V3 引脚连接到每个按钮上,也就是使用面包板上的正极柱。因此

3V3 -> 面包板正极柱 -> 按钮(在面包板沟槽的一侧) -> GPIO(在另一侧)

我的代码将使用 GPIO 16 来控制播放按钮,GPIO 2 来控制暂停按钮,GPIO 15 来控制跳过曲目按钮。

设置 IFTTT 以控制 Spotify

我们将创建三个 IFTTT 小程序来控制 Spotify。

我们必须创建三个小程序,分别用于播放、暂停和跳过功能。

如果您拥有 IFTTT 的高级版本,也许可以使用 JavaScript 筛选器将其全部包含在一个应用程序中。但由于我们没有,所以我们需要每个小程序。

登录后,点击主菜单右上方的 "创建"。

在 "如果这样 "栏中,点击它并搜索 Webhooks。

点击 "If This "或 "Then That",分别选择 Webhooks 和 Spotify。

然后,点击 "接收网络请求"(而不是 "带 JSON 有效负载 "的其他选项)。

事件名称,键入 spotify_skip.

您需要重复此步骤两次,以便 spotify_pausespotify_play 完成创建小程序后。

完成后,转到"那么"栏并点击它。搜索"Spotify".

您必须授权 IFTTT 才能连接 Spotify 一次。

如果您正在进行 spotify_skip 操作时,您需要点击 "跳过跟踪"。但如果你要用一个小程序来执行其他操作,上图就会告诉你该用哪一个。

创建完所有三个小程序后,就可以编写代码了!

为 Pico W 的 Spotify 遥控器编码

首先,您需要知道需要访问的终点。

转到本页 并点击 文件.

你会在那里看到你的密钥。如果你已经完成了上述所有步骤,那么你的端点和我的端点之间的区别就是你的密钥。因此

播放终点: https://maker.ifttt.com/trigger/spotify_play/with/key/[your_key_here]

暂停: https://maker.ifttt.com/trigger/spotify_pause/with/key/[your_key_here]

跳过: https://maker.ifttt.com/trigger/spotify_skip/with/key/[your_key_here]

编码

from machine import Pin
from wifi import init_wifi
import urequests
import time

init_wifi()

play_btn = Pin(16, Pin.IN, Pin.PULL_DOWN)
pause_btn = Pin(2, Pin.IN, Pin.PULL_DOWN)
skip_btn = Pin(15, Pin.IN, Pin.PULL_DOWN)


def play():
    request_url = 'https://maker.ifttt.com/trigger/spotify_play/with/key/[your_key_here]'
    res = urequests.post(request_url)
    # print response from IFTTT.
    print(res.text)


def pause():
    request_url = 'https://maker.ifttt.com/trigger/spotify_pause/with/key/[your_key_here]'
    res = urequests.post(request_url)
    # print response from IFTTT.
    print(res.text)


def skip():
    request_url = 'https://maker.ifttt.com/trigger/spotify_skip/with/key/[your_key_here]'
    res = urequests.post(request_url)
    # print response from IFTTT.
    print(res.text)


try:
    while True:
        if play_btn():
            print('play btn')
            play()
            time.sleep(0.25)
        if pause_btn():
            print('pause btn')
            pause()
            time.sleep(0.25)
        if skip_btn():
            skip()
            print('skip')
            time.sleep(0.25)

except Exception as e:
    print(e)
    request_url = 'https://maker.ifttt.com/trigger/error/with/key/[your_key_here]'
    post_data = ujson.dumps({"value1": str(e)})
    urequests.post(request_url, headers={
        'content-type': 'application/json'}, data=post_data)

让我们来看看这段代码。

请注意,您需要更换 [你的钥匙在此] 通过 文件 链接。

首先,我们为按钮声明变量。

play_btn = Pin(16, Pin.IN, Pin.PULL_DOWN)
pause_btn = Pin(2, Pin.IN, Pin.PULL_DOWN)
skip_btn = Pin(15, Pin.IN, Pin.PULL_DOWN)

目前,如果您不按下按钮,您的变量值将为 0. 如果按下它,它就会变成 1.我们将用它来触发 播放() , 暂停()跳过() 职能

然后,我们为播放、暂停和跳过端点创建函数。一般模板如下

def play():
    request_url = 'https://maker.ifttt.com/trigger/spotify_play/with/key/[your_key_here]'
    res = urequests.post(request_url)
    # print response from IFTTT.
    print(res.text)

其实很简单。如果运行此函数,它将向 IFTTT 发送 POST 请求。发送 GET 请求将不起作用。

然后是 try/except 块。

try:
    while True:
        if play_btn():
            print('play btn')
            play()
            time.sleep(0.25)
        if pause_btn():
            print('pause btn')
            pause()
            time.sleep(0.25)
        if skip_btn():
            skip()
            print('skip')
            time.sleep(0.25)

except Exception as e:
    print(e)
    request_url = 'https://maker.ifttt.com/trigger/error/with/key/[your_key_here]'
    post_data = ujson.dumps({"value1": str(e)})
    urequests.post(request_url, headers={
        'content-type': 'application/json'}, data=post_data)

如果按下按钮,代码就会运行相关功能。例如,按下跳过按钮将运行以下功能 跳过().

A time.sleep(0.25) 将使功能暂停 250 毫秒。如果没有这个功能,即使是短按也会导致 Pico W 过载和崩溃。

ǞǞǞ 除开 块是可选的,但我这样做是因为我已经在 IFTTT 上安装了一个 "错误 "小程序。如果你已经学习了前面的教程,你可能已经使用过了。

基本上,它会发送错误信息、 e,转到 IFTTT,这样你就能以手机应用通知的形式收到错误信息。

为什么不起作用?

使用 IFTTT 作为控制 Spotify 的媒介非常简单,但也有一些缺点。

您必须先按常规方式启动音乐

如果您尝试按下 Pico W 上的播放按钮并期待开始播放音乐......那么,什么也不会发生。

解决办法是在电脑或手机上正常启动音乐。您需要进入应用程序并按下播放键。

我想这是在声明哪个设备是活动设备。完成这些操作后,您就可以使用 Pico W Spotify 遥控器了。

反应缓慢

从按下按钮到做出反应需要几秒钟的时间。不幸的是,情况就是这样。

您可以付费升级 IFTTT,以获得更快的响应速度。至少,他们是这样承诺的。

有没有直接连接 Spotify 的方法?

可以!您可以连接 Spotify 的 API。

它的控制能力大大增强。你可以添加一个旋转编码器来控制音量。你还可以添加一个液晶显示屏,显示正在播放的内容。 点击这里查看 Spotify 的控制台。

令人惊叹,但也更难编程,尤其是在 Pico W 上。

IFTTT 让这一切变得简单,因为他们承担了所有繁重的工作。如果你想成为重任的执行者,请查看认证流程。

Spotify 的授权代码流程图

当然,我们是 Raspberry Pi 发烧友。会有人做的。会是你吗?还是我?请在下面评论。

用PiCockpit无线控制你的Pico W!

你可以通过使用PiCockpit无线控制和获取Pico W的数据。

PiCockpit允许你通过其GPIO小程序通过GUI获得数值、控制和使用PWM。

你也可以通过PiStats小程序查看你的Pico W的统计资料。

将PiCockpit集成到你的Pico W中是非常容易的。

按照这个教程。

用PiCockpit和Pico W编写更少的代码

PiCockpit使你能够轻松地控制你的GPIO引脚,而不需要编写任何代码。

如果你看一下 补习班第2期请注意,仅仅为了切换一个LED,就需要多少代码。

通过我们新的Pico W集成,PiCockpit使它变得更加容易,因为你根本不需要对任何东西进行编程。甚至连WiFi配置都不需要--那是通过我们的设置向导完成的。

10.用PiCockpit和Pico W进行简单的LED控制

如果你已经完全按照我在第2号教程中的方式配置了你的LED,那么剩下的就是在PiCockpit上进行设置。

如果你在进行编码,你将用以下方式声明你的LED在哪个引脚上 led = machine.Pin(2, machine.Pin.OUT)

在PiCockpit上,你将进入你的GPIO小程序,然后滚动到 "GPIO输出(开/关)"。

从下拉菜单中选择BCM02,因为你的LED是在GPIO 2上。

然后,在 "控制 "一栏,拨动开关,将LED灯打开。

你也可以轻松地使用下面的软件PWM部分来控制你的LED的亮度。

注意,你将需要删除之前的设置,因为你不能在同一个GPIO上有两个输出。

当你拨动 "控制 "滑块时,你会注意到LED的亮度在变化。

picockpit gpio pwm远程控制

11.Pico W,5V风扇和一个晶体管,由PiCockpit控制

让我们尝试更全面一点的东西,但使用同样的GPIO输出切换。

为了说明一些实际的使用情况,我将使用PiCockpit为一个5V的风扇供电。

这是一个取自我的Raspberry Pi 4的低功耗5V风扇,所以它完全在Raspberry Pi Pico W的输出能力之内。

也就是说,因为它是一个5V的风扇,我不能使用GPIO引脚。在功耗较低的元件中,如LED,你可以让GPIO承担双重任务,既为元件供电,又作为 "开关 "来开启和关闭它。

但5V的风扇需要太高的电压。所以,下一个最好的方法是在中间放一个晶体管。

这使我能够向风扇提供5V电压,同时确保我能够打开和关闭它。

再一次,由于PiCockpit的存在,我没有进行任何编程。我只做了硬件,它的接线方式如下。

该风扇是一个5V/0.12A的风扇,正极连接到5V(红线),负极连接到晶体管的发射极。

该晶体管是一个PN2222(NPN)晶体管,这意味着当它收到高信号时就会打开。

从左到右,半圆形的部分朝向你,腿是发射器、底座和收集器。

Base脚连接到一个1K电阻,然后连接到GPIO 15。

集电极脚连接到地。

配置PiCockpit使其与晶体管一起工作

再一次,超级简单。

进入GPIO输出部分的下拉菜单,添加BCM15。

一旦进入,你可以点击向下的箭头,将状态名称改为 "风扇关闭 "和 "风扇开启"。

拨动控制开关,你应该看到风扇打开了。

你也可以使用PiStats来查看你的电路板上的温度下降情况。

使用 MQTT 和 Node-RED 以及 Pico W 显示光敏电阻。

本教程的主要目的是介绍 MQTT。

在前面的教程中,我已经向您介绍了如何使用 Pico W 传输数据,但如果您想在云中建立一个中央数据存储库,该怎么办呢?

HiveMQ Cloud 是一项免费服务,我们可以利用它来实现这一目标。通过使用别人的电脑,我们还可以减轻 Pico W 的负担。

此外,与以前使用的方法相比,MQTT 具有很大的优势。首先,它在发送小数据时效率更高。MQTT 协议头的大小为 2 字节。而 HTTP 大约大 4000 倍。

减少本地处理负载和网络负载意味着延长 Pico W 的电池寿命,非常适合电池或太阳能供电的项目。

光敏电阻与 Pico W 的连接

光敏电阻(光电池)非常容易连接。

将光敏电阻横放在面包板的中央沟槽上。

然后,将 3V3 引脚连接到光敏电阻的一侧。

您需要将 ADC 引脚连接到光敏电阻的另一端,因此请连接 GPIO 26。

最后,将一个 10K 欧姆的电阻器从地线连接到光电池。

HiveMQ 云和 Pico W 编码

首先是 在此注册 HiveMQ Cloud。

完成设置并创建群集。它会要求你选择 AWS 或 Azure。对于我们来说,这两者没有区别。

然后点击 "管理群集"。

群组主菜单。注意两个橙色矩形。

记下您的群集 URL,然后单击 "访问管理 "创建新用户。按步骤创建新用户。

有了这些详细信息,您就可以对 Pico W 进行编程,将数据发送到那里。

对 Pico W 进行编码,以接收光电池数据和 MQTTClient

from machine import Pin, ADC
from wifi import init_wifi
import time
from umqtt.simple import MQTTClient

init_wifi()

photoresistor = ADC(Pin(26))


def readLight():
    light = photoresistor.read_u16()
    return light


# Connect MQTT

def connectMQTT():
    client = MQTTClient(client_id=b"[your_client_id]",
                        server=b"[your-host-name]",
                        port=0,
                        user=b"[your-user]",
                        password=b"[your-pw]",
                        keepalive=7200,
                        ssl=True,
                        ssl_params={
                            'server_hostname': '[your-host-name]'}
                        )

    client.connect()
    return client


client = connectMQTT()


def publish(topic, value):
    print(topic)
    print(value)
    client.publish(topic, value)
    print("data published")


while True:
    brightness = str(readLight()) #to publish, must send string

    print(brightness)

    publish('picow/brightness', brightness)

    time.sleep(0.1)

首先,让我们把进口商品整理好。

from machine import Pin, ADC
from wifi import init_wifi
import time
from umqtt.simple import MQTTClient

ǞǞǞ wifi 导入来自前面的教程。

您需要使用 umqtt.simple 库,它可以 可在此处下载.

下载完成后,您可以将其上传到您的电路板 (指南).

您的 Pico W 上应该有这些文件。

然后,创建一个函数来获取光敏电阻的读数:

photoresistor = ADC(Pin(26))

def readLight():
    light = photoresistor.read_u16()
    return light

返回值最大为 65535。颜色越亮,数值越大。

连接 HiveMQ

为了连接到 HiveMQ,您需要向 MQTTClient 类发送一些参数。

# Connect MQTT

def connectMQTT():
    client = MQTTClient(client_id=b"[your_client_id]",
                        server=b"[your-host-name]",
                        port=0,
                        user=b"[your-user]",
                        password=b"[your-pw]",
                        keepalive=7200,
                        ssl=True,
                        ssl_params={
                            'server_hostname': '[your-host-name]'}
                        )

    client.connect()
    return client


client = connectMQTT()

将 [your-host-name] 替换为仪表板上的地址。您需要这样做两次,一次用于 server 和另一个 server_hostname.同时将 [your_client_id] 替换为设备名称,如 "your_picow"。

然后,替换 [your-user][your-pw] 使用在访问管理页面创建的用户(访问管理页面截图如下)。

作为参考,该函数向 HiveMQ 发送数据:

def publish(topic, value):
    print(topic)
    print(value)
    client.publish(topic, value)
    print("data published")

在我们的 while 循环:

while True:
    brightness = str(readLight()) #to publish, must send string

    print(brightness)

    publish('picow/brightness', brightness)

    time.sleep(0.1)

发布时,您必须发送字符串,这就是为什么 brightness = str(readLight()) 就在那里。

如果发送的是整数或浮点数,程序就会死机。

在发布功能中,给你的主题起个名字。说 picow/brightness然后添加要发送的值。在本例中,我们要发送的是字符串化的灯光读数、 brightness.

登录 Web Client 标签时,您应该可以看到正在发布的数据。

左侧为 HiveMQ 的网络客户端,显示已发布的数据。

红色节点

这些只是网上的数字,可能看起来像胡言乱语。如果您想访问 HiveMQ 云上的数据并以图形方式展示这些数据,该怎么办?

与其自己开发,不如直接使用 Node-RED。

通过 Node-RED,您可以非常轻松地从 HiveMQ 获取数据,然后使用图形表示法将其呈现出来。

我们将使用 Node-RED 制作一个仪表。

开始时,您需要具备 nodejs.查看 HiveMQ 文档 查看推荐的版本。

安装好 Node 后,您需要打开命令提示符/终端并运行以下命令(如果您使用的是 Windows 操作系统,请排除 sudo):

sudo npm install -g --unsafe-perm node-red

这将使用节点软件包管理器(npm)在全局范围内安装 Node-RED。

然后,运行 Node-RED,键入 node-red 输入终端/命令提示符。

打开浏览器,前往 http://127.0.0.1:1880 或终端中列出的任何地址。

让我们构建流程。在画布上拖动一个 "mqtt in"。您可以在左侧边栏的 "网络 "选项卡下找到它。

我们需要配置该选项卡,因此双击该矩形并执行以下操作:

在 "主题 "字段中,确保添加 亮度因为这是您从 Pico W 发布的内容。

在 "服务器 "中,点击铅笔图标添加一个新服务器,然后就会进入下一个菜单。

输入新的服务器地址,并将端口改为 8883。勾选 "使用 TLS",但不必添加新的 tls-config。

然后,转到安全选项卡,添加登录凭据。

所有这些细节都可以在您初始化 MQTTClient 的代码中找到。

添加仪器

要添加仪器,必须具备 节点红色仪表板.

在左侧边栏,如果您没有看到这些:

然后转到菜单(右上角按钮)-> 管理调色板。然后转到 "安装 "选项卡,搜索 node-red-dashboard。点击 "安装"。

拖放一个 "量规 "到 mqtt in 矩形,然后从 mqtt in 到测量仪上。

双击矩形仪表,将标签更改为 "亮度",将 "范围 "最大值更改为 65535。

太好了。现在让我们按下 "部署 "键。

如果设置正确,您将看到一个绿色圆圈和矩形下的 "已连接 "字样。如果不正确,终端会提供更多详细信息,说明出错的原因。

随着 Pico W 将数据传输到 HiveMQ 云,现在是时候查看仪表板了。访问 http://127.0.0.1:1880/ui 您就会看到仪表盘经常更新。


欢迎您提出建议。

请在下面的评论框中留言!

6评论

  1. Quang 在1 月 10, 2023在2:21 下午

    你好
    感谢您与我们分享您的知识。
    请问 WiFi 功能是否只能在网络内使用?如果我在不同的 WiFi 网络上,就无法访问 Pico W。如果是这样,您是否有网络外访问的例子?
    谢谢。

    • raspi berry 在2 月 4, 2023在11:52 上午

      是的,由于网络、路由器和防火墙的特性,这些练习只能在同一个 WiFi 网络内进行。
      PiCockpit 本身就是一个跨越网络的解决方案--您可以从互联网的任何地方访问您的 Pico W。
      我们正在努力为平台带来更多功能。

      如果你想自己重新创建类似的功能,你需要在网络上安装某种隧道解决方案,或中继服务器之类的东西。
      如果您想深入了解这一主题,我们可以提供咨询服务。

  2. Peter Mayr 在3 月 29, 2023在10:44 上午

    感谢您的精彩教程。
    遗憾的是,它不起作用。
    我被卡在了 "1.在 Pico 上运行一个显示 "Hello World "的网页 "部分的末尾。

    我的 Firefox 和 Chrome 浏览器只告诉我 "连接中断错误"。
    在索尼,我看到

    已连接
    IP = 192.168.188.198
    监听 ('0.0.0.0', 80)
    客户端从('192.168.188.100', 54025)连接
    连接已关闭

    连接关闭了几次。
    如何修改才能使 Pico W 正常工作?
    提前感谢您的帮助。
    皮特

  3. mokcp 在5 月 3, 2023在10:58 上午

    运行 main.py 时出现错误信息,如何解决?

    文件"",第1行,在
    导入错误:没有名为 "wifi "的模块

    谢谢。

    • PiCaptain 在5 月 10, 2023在12:31 下午

      您必须创建并添加 wifi.py,它显示在页面的稍上方。没有 wifi.py,代码将无法运行。

  4. màn hình led 在8 月 26, 2023在2:18 下午

    Raspberry Pi Pico W 入门组件教程 "是一本非常适合 Raspberry Pi Pico W 平台新手的指南。该教程结构合理、简单易懂,非常适合初学者。它涵盖了基本组件,并提供了清晰的说明,对于希望探索这项技术的人来说是一个很好的起点。其中包含的详细解释和图片增强了学习体验,确保读者能够快速掌握概念。总之,对于那些希望开始使用 Raspberry Pi Pico W 及其组件的人来说,本教程是一个宝贵的资源。

发表评论