Fab Academy,源自麻省理工学院的先进教育项目,致力于培养具有全球视野的创新者和制造者。通过密集学习和实践,学生们掌握了从基础到高级的制造技术,学习了如何将创意转化为现实。今天小编给大家带来的是Fab academy学员Dion Tsang的结课项目:Night Lamp With Chinese Traditional Pane,具有中国文化特色的外观结构,同时可以实现远程控制和数据可视化等功能,让我们一起了解这个项目的开发过程。
项目介绍
具有远程切换、颜色调节功能,并提供夜灯所在空间的温度和湿度值的可视化。用户只需在界面上进行相应的操作即可。台灯的外观是一个类似于汉字——“中”的设计。
材料清单
电子元件 | 数量 | 价格 |
LED灯带 | 1 | $34.9 |
XIAO ESP32C3 | 1 | $4.99 |
Grove DHT11 | 1 | $5 |
CONN HEADER SMD 10芯 1.27MM | 1 | $0.88 |
CONN 接头 SMD R/A 4POS 2.54MM | 1 | $0.93 |
CONN 接头 SMD R/A 3POS 2.54MM | 1 | $0.93 |
轻触开关 SPST-NO 顶部驱动表面贴装 | 1 | $1.08 |
LED 蓝色透明 1206 SMD | 1 | $0.23 |
RES 1K 欧姆 1% 1/4W 1206 | 1 | $0.10 |
RES 499K 欧姆 1% 1/4W 1206 | 1 | $0.10 |
跳线 F/F 6“ 20PCS | 1 | $2.10 |
杜邦线 | 1 | $8.99 |
PCB设计与制作
对于PCB的设计、焊接与铣削,主要内容参考:
夜灯,我将包括Xiao ESP32-C3,一个LED条(WS2812B),一个温度和湿度传感器Grove DHT11和其他组件,对于Xiao,我们需要将Fab Electronics Library添加到Kicad。
由于在 Kicad 中找不到这个元件元件,我把它取下来,重新焊接,用 3 组合起来,用连接器(线)连接到板子上。喜欢这个:Pin header 2.54MM 1*40 2*40 P
您可能会注意到 Grove 电缆有 4 种不同的颜色。
引脚 1 - 黄色(例如,I2C Grove 连接器上的 SCL)
引脚 2 - 白色(例如,I2C Grove 连接器上的 SDA)
引脚 3 - 红色 - 所有 Grove 连接器 上的 VCC
引脚 4 - 黑色 - 所有 Grove 连接器上的 GND
我拆下了电缆末端的一端,并使用排针将其连接到 CONN HEADER SMD。
远程控制与数据可视化功能
对于远程控制与数据可视化功能的实现,参考视频:
https://www.bilibili.com/video/BV1U34y1Y7wv/?spm_id_from=333.880.my_history.page.click&vd_source=de467befc07e98c5fa1b53ff474c2875
从这个视频获得电灯的遥控切换。视频中的博主使用 MQTT 实现了对 LED 灯带的远程开/关控制。我从灯的这个观点中获得灵感。这些花型、巧妙的线结构设计和压接设计给我留下了深刻的印象!它的图案让我想起了中国古代的图案,这个想法鼓励我设计一个中国传统图案,尤其是紫禁城文物的一些图案。我希望我能设计这些模式并将它们应用到我的项目工作中。
输入设备
这是一个更新版本,我将使用 XIAO 和 Grove - Ultrasonic Ranger 为我的输入设备周制作一个新项目。
我有来自我们实验室的一种 XIAO:
接下来,让我们开始 PCB 设计吧!
PCB 铣削:
焊接及短路测试
项目代码
本项目具体代码如下:
/*
Originally from MQTT ESP8266 Example
Basic XIAO-ESP32 MQTTS example
Before starting , You should have
- MQTT Broker Name
- MQTT Broker Username
- MQTT Borker Password
Modified by Salman Faris - Added MQTTS Implimenation as per ESP32 and MQTTS.
Modified by Dion Tsang - Added Colorwheel, DHT Datavisualization.
*/
#include <WiFi.h>
#include <PubSubClient.h>
#include "DHT.h"
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define DHTPIN D2
#define DHTTYPE DHT11 // DHT 11
#define NUMPIXELS 80 // Popular NeoPixel ring size
#define PIN D1
#define BUF_SIZE (100)
#define BUF_SIZE2 (100)
DHT dht(DHTPIN, DHTTYPE); // Initialize DHT sensor.
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRBW + NEO_KHZ800);
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 20 // Time (in milliseconds) to pause between pixels
// Update these with values suitable for your network.
const char* ssid = "AndroidAP26ab"; // WiFi Name
const char* password = "tawd7050"; // WiFi Password
const char* mqtt_server = "mqtt.fabcloud.org"; //MQTT Broker Name
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
// int BUILTIN_LED = D10
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(DELAYVAL);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.print("This is length");
Serial.print(length);
Serial.println();
if (strcmp(topic, "fabacademy/myLampSwitch") == 0) {
if ((char)payload[0] == '1') {
pixels.clear(); // Set all pixel colors to 'On'
for (int i = 0; i < NUMPIXELS; i++) {
// pixels.setPixelColor(i, pixels.Color(0, 150, 0));
pixels.setPixelColor(i,0xDE3759);
}
pixels.show(); // Send the updated pixel colors to the hardware
} else if ((char)payload[0] == '0') {
pixels.clear(); // Set all pixel colors to 'Off'
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
}
pixels.show(); // Send the updated pixel colors to the hardware
}
}
if (strcmp(topic, "fabacademy/LampColor") == 0) {
// Parse the hex color code from the payload
char hexColor[7] = { 0 }; // 6 characters + null terminator
if (length == 7) {
// strncpy(hexColor, (char*)payload, 6);
for (int i=1; i <length;i++){
hexColor[i-1]=(char)payload[i];
Serial.println(hexColor[i-1]);
}
hexColor[6] = '\0'; // Ensure null-terminated string
// Serial.println(hexColor);
// Convert hex color code to a 32-bit integer
uint32_t color = (uint32_t)strtol(hexColor, NULL, 16);
// Extract RGB components from the 32-bit color value
byte red = (color >> 16) & 0xFF;
byte green = (color >> 8) & 0xFF;
byte blue = color & 0xFF;
// Set the NeoPixel color using the 32-bit integer
pixels.clear();
for (int i = 1; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(red, green, blue));
}
pixels.show(); // Send the updated pixel colors to the hardware
}
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "XIAO-ESP32-Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
// if (client.connect(clientId.c_str())) {
if (client.connect(clientId.c_str(), "fabacademy", "fabacademy")) {
Serial.println("connected");
// Once connected, publish an announcement...
//client.publish("fabacademy/dionTest/Temperature", "hello world");
// ... and resubscribe
client.subscribe("fabacademy/myLampSwitch");
client.subscribe("fabacademy/LampColor");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(DELAYVAL);
}
}
}
void setup() {
// pinMode(PIN, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
dht.begin();
// END of Trinket-specific code.
pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
delay(DELAYVAL);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
// unsigned long now = millis();
// if (now - lastMsg > 2000) {
// lastMsg = now;
// ++value;
// snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
// Serial.print("Publish message: ");
// Serial.println(msg);
// client.publish("fabacademy/dionTest", msg);
// }
// #define BUF_SIZE (100)
// #define BUF_SIZE2 (100)
char tempra[BUF_SIZE];
snprintf(tempra, BUF_SIZE, "%f", t);
client.publish("fabacademy/Temprature", tempra);
char humidity[BUF_SIZE2];
snprintf(humidity, BUF_SIZE2, "%f", h);
client.publish("fabacademy/Humidity", humidity);
}