前端人基于树莓派 Pico 的第一个远程开关

文章首发个人博客 高小哥漫谈前端

一、缘起

聊聊为什么要写这篇文章?要做这个事情?

从大学学习编程到如今从事大前端相关工作已快 7 年;其中正式工作 5 年;期间一直在做软件开发相关的事情;包括但不限于前端、跨端框架、工程化、低代码、Node 以及老早之前学习的客户端开发; 但一直以来都想去碰一碰硬件相关的东西,直到有这么一个契机。

那就是我家养了几只猫,每次铲屎都很麻烦,在网上买自动铲屎机 便宜的几百块,贵的几千块。于是为了解放我的双手;就想了解一下怎么通过软件控制硬件

对于我们这种硬件门外汉,想要一步步去做控制最大的难题是知识体系的缺失; 完全不知道如何下手,于是我开始了(google/bilibili/xxx)求学之路;和在校学习的不同之处在于,工作后的我们没有大量的时间去学习硬件相关知识;所以我的学习路线是:

  • 先看看别人怎么做
  • 再自己动手
  • 不懂的专业名词 + 知识就搜索学习

# 二、聊聊技术选型

我的目标是做一个自动铲屎机,但是自动铲屎机里面比较重要的是:一个远程控制开关去控制电机的运行; 下面我们就来聊聊远程控制开关的选型;

  • 远程: 要实现远程功能,就需要单片机 和 手机进行通信; IOT 设备 的通信和传统互联网使用的协议有所不同,IOT 更多的使用 MQTT 协议

    MQTT 是一种基于发布/订阅模式的轻量级物联网消息传输协议 ,可以用极少的代码和带宽为联网设备提供实时可靠的消息服务,它适用于硬件资源有限的设备及带宽有限的网络环境。因此,MQTT 协议广泛应用于物联网、移动互联网、智能硬件、车联网、电力能源等行业。

  • 控制: 要控制开关的打开和闭合,需要一块单片机, 网上比较火/教程比较多的是 esp8266 和 树莓派;

    • esp8266: ESP8266 的核心是一块 Diamond Standard 106Micro 控制器,一个低功耗的 32 位 RISC 控制器。它拥有 GPIO、I2C、ADC、SPI、PWM 等模块,你可以用它做一些微控制器能做的事。它还可以支持 AP(Access Point)、STA(Station)、AP+STA 共存模式,并且使用高效的 AT 指令

      esp8266 比较便宜,但是对于我来说不太适用,因为目前只支持 使用 windows 将代码烧录到 板子上;而我家只有一台 mac;

    • 树莓派: 树莓派是目前很火的一款微控制器,有很多型号(2B/3B/4B/400/Pico/Pico W/Pico WH 等);由于目前我并不需要蓝牙/音视频/GPU 等等功能,只需要简单的控制 + wifi 能力,于是选择了 Pico W; 其中选择 Pico 系列还有一个原因是 400 等型号现在太贵了 得 800 左右,而 pico 系列才 100 多

  • 开关: 要实现电路的打开和闭合一方面需要单片机输出控制信号,另一方面需要 一个继电器 去控制电路。

# 三、开始实现

# 1. 整体架构

前端人基于树莓派 Pico 的第一个远程开关

  • 继电器 IN 和树莓派 GPIO 引脚相连
  • 树莓派连接好 wifi 之后通过 建立 mqtt 连接,通过 mqtt broker 同其他客户端进行相连。
  • 移动端 发送 一个 payload,树莓派接收到之后将其转换成 0/1, 从而控制继电器的输入口; 从而控制灯的打开和关闭

# 2. 继电器+树莓派连接图

先了解一下 继电器(我这里使用的是 SRD-05VDC)的构成

前端人基于树莓派 Pico 的第一个远程开关
继电器的输入端:

  • DC+: 接树莓派 3.3v 引脚
  • DC-: 接 GND 引脚
  • IN: 可以通过控制高电平/低电平 从而控制开关的开闭,我这里接的是 GPIO 12 引脚

继电器的输出端:

  • NO: 继电器常开接口
  • COM: 继电器公共接口
  • NC: 继电器常闭接口

如果 线路为 NO + COM那么 开关默认是打开的(也就是没有通电),如果是 NC + COM 那么 开关默认是闭合的(也就是默认通电)

我这里选择 NO + COM 的方式。

前端人基于树莓派 Pico 的第一个远程开关

# 3. mqtt broker

我这里使用的是 EMQX (opens new window):

第一步:使用 docker 启动 broker

# 一键启动 mqtt broker 支持 mqtt/mqtts/ws/wss 协议
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:latest

第二步:在 EMQX 建立 mqtt 链接

前端人基于树莓派 Pico 的第一个远程开关

由于前端不支持 mqtt 协议,所以需要再建立一个 websocket 用于可视化展示; 若你使用的事客户端开发也可以不建立 websocket 连接,直接使用上述的 mqtt 连接即可

前端人基于树莓派 Pico 的第一个远程开关

# 4. 树莓派连接 wifi + mqtt


import time
import network
from machine import Pin
from umqtt.simple import MQTTClient

# 初始化 继电器的输入口,使用GPIO 19引脚
relay = Pin(19, mode = Pin.OUT)
# wifi 名称和密码
wifi_ssid = "" # wifi 名称
wifi_password = "" # wifi 谬吗
mqtt_host = "xxxxx" # 自己的ip,我这里就使用的是电脑的ip
mqtt_username = ""  #  emqt username
mqtt_password = ""  # emqt password
mqtt_receive_topic = "switch-status"  #  MQTT要接收的topic


# 连接wifi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(wifi_ssid, wifi_password)
while wlan.isconnected() == False:
    print('Waiting for connection...')
    time.sleep(1)
print("Connected to WiFi")


#  MQTT Client 随机id
mqtt_client_id = "mrgaogang"

mqtt_client = MQTTClient(
        client_id=mqtt_client_id,
        server=mqtt_host,
        user=mqtt_username,
        password=mqtt_password)



def mqtt_subscription_callback(topic, message):
    print (f'Topic {topic} received message {message}')  
    if message == b'open':
        print("relay ON")
        relay.value(1)
    elif message == b'close':
        print("relay OFF")
        relay.value(0)

mqtt_client.set_callback(mqtt_subscription_callback)
mqtt_client.connect()

mqtt_client.subscribe(mqtt_receive_topic)
print("Connected and subscribed")

try:
    while True:
        print(f'Waiting for messages on {mqtt_receive_topic}')
        mqtt_client.wait_msg()
except Exception as e:
    print(f'Fairelay to wait for MQTT messages: {e}')
finally:
    mqtt_client.disconnect()

# 5. 移动端连接 mqtt

由于移动端(web 端)不支持 mqtt 协议,所以需要使用 ws 协议去链接

// core.ts 核心文件
import { connect, MqttClient } from "mqtt";

export enum MQTT_TOPIC {
  SWITCH_STATUS = "switch-status",
}

export type MQTTUseType = {
  publish?: (payload: string) => void;
  on?: (callback: (data: string) => void) => void;
};

export class MQTTController {
  private static instance: MQTTController;
  private status: "pending" | "success" | "closed";
  private client: MqttClient | undefined;
  private connectStatus: Promise<MQTTController> | undefined;
  static create() {
    if (!MQTTController.instance) {
      MQTTController.instance = new MQTTController();
    }
    return MQTTController.instance;
  }
  constructor() {
    this.status = "pending";
    this.connect();
  }
  private isReady() {
    return this.status === "success";
  }

  private async connect() {
    const client = connect("ws://localhost:8083/mqtt");
    this.status = "pending";
    this.connectStatus = new Promise<MQTTController>((resolve, reject) => {
      client.on("connect", () => {
        console.log("mqtt 连接成功");

        this.status = "success";
        this.client = client;
        resolve(this);
      });
    });
  }

  async use(topic: MQTT_TOPIC): Promise<MQTTUseType> {
    if (this.status === "pending") {
      await this.connectStatus;
    } else if (this.status === "closed") {
      await this.connect();
    }
    const publish = (payload: string) => {
      if (this.isReady()) {
        this.client?.publish(topic, payload);
      }
    };
    const on = (callback: (data: string) => void) => {
      if (this.isReady()) {
        this.client?.subscribe(topic);
        this.client?.on("message", (tpc, msg) => {
          if (tpc === topic) {
            callback(msg.toString());
          }
        });
      }
    };

    return {
      publish,
      on,
    };
  }

  end() {
    if (this.isReady()) {
      this.status = "closed";
      this.client?.end();
    }
  }
}

页面控制

const mqtt = useRef<MQTTUseType>({});

// 建立链接,并使用对应的topic
mqtt.current = await MQTTController.create().use(MQTT_TOPIC.SWITCH_STATUS);
// 监听对应topic 的数据
mqtt.current?.on?.((data) => {
  console.log("receive data", data);
  setChecked(data === "open");
});

// 发送打开消息
mqtt.current?.publish?.("open");

//  发送关闭消息
mqtt.current?.publish?.("close");

完整代码地址: github.com/MrGaoGang/r…

# 四、效果展示

有兴趣的同学可以 使用抖音扫一扫 查看具体视频

前端人基于树莓派 Pico 的第一个远程开关

原文链接:https://juejin.cn/post/7233065830957891644 作者:MrGaoGang

(0)
上一篇 2023年5月15日 上午10:32
下一篇 2023年5月15日 上午10:43

相关推荐

发表回复

登录后才能评论