yeelight灯泡wifi控制器
本帖最后由 vany5921 于 2020-7-1 10:54 编辑一个简单的Yeelight灯泡无线M5控制器,可替代手机进行操作,如果手机连接Yeelight时设置了自动光线补偿,那么会对控制器的调光产生一定影响。控制器闲置3秒自动休眠,按B键唤醒,通过陀螺仪调整灯泡亮度,C键开关灯控制。开机黑屏,接入wifi后屏幕会显示内容。 #define M5STACK_MPU6886
#include <ArduinoJson.h>
#include <M5Stack.h>
#include <WiFi.h>
#include "yeelight.h"
#define SSID "SSID"
#define WIFI_PWD "PASSWORD"
#define SLEEP_WAIT 3000
#define ACCEL_THRESHOLD 200
#define MAX_DIMMER_VALUE 50000
#define DIMMER_TO_PERCENT(param) ((100 * (param)) / MAX_DIMMER_VALUE)
void angleDimmer(void* xParam);
void sleepWait(void* xParam);
void waitForWiFi();
void lightPowerToggle();
void lightAdjustBrightness();
void power_on_rutine();
TaskHandle_t sleepTaskHandle;
TaskHandle_t angleTaskHandle;
Yeelight* yeelight;
bool initialized = false;
bool inactive = false;
time_t last_activity = millis();
int32_t dimmer_value = 0;
int current_bright = 1;
int toggle_counter = 1;
String brightness_params;
void setup() {
M5.begin();
M5.Power.begin();
M5.Power.setWakeupButton(BUTTON_B_PIN);
M5.IMU.Init();
WiFi.begin(SSID, WIFI_PWD);
waitForWiFi();
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextColor(GREEN, BLACK);
M5.Lcd.setTextSize(2);
yeelight = new Yeelight();
yeelight->lookup();
}
void loop() {
M5.update();
if (!initialized) {
power_on_rutine();
initialized = true;
inactive = false;
}
if (M5.BtnC.wasPressed()) {
lightPowerToggle();
}
Serial.println(current_bright);
lightAdjustBrightness();
if (inactive) {
vTaskDelete(angleTaskHandle);
vTaskDelete(sleepTaskHandle);
initialized = false;
M5.Power.lightSleep();
}
delay(100);
}
void lightPowerToggle() {
last_activity = millis();
M5.Lcd.setCursor(0, 60);
M5.Lcd.print("Sending power toggle ");
M5.Lcd.println(toggle_counter++);
yeelight->sendCommand("toggle", "[]");
}
void lightAdjustBrightness() {
int new_bright = (int)(dimmer_value / (MAX_DIMMER_VALUE / 100));
String brightness_params;
if (new_bright < 1) {
new_bright = 1;
}
if (new_bright != current_bright) {
current_bright = new_bright;
brightness_params = String("[") + new_bright + ", \"smooth\", 500]";
Serial.println(yeelight->sendCommand("set_bright", brightness_params));
}
}
void power_on_rutine() {
M5.Lcd.fillScreen(BLACK);
last_activity = millis();
xTaskCreate(angleDimmer, "angleDimmer", 4096, NULL, 10, &angleTaskHandle);
xTaskCreate(sleepWait, "sleepWait", XT_STACK_MIN_SIZE, NULL, 9,
&sleepTaskHandle);
waitForWiFi();
M5.Lcd.setCursor(0, 0);
M5.Lcd.println("Connected to Wifi");
while (!yeelight->feedback()) {
yeelight->lookup();
delay(50);
}
M5.Lcd.setCursor(0, 20);
M5.Lcd.println("Light detected");
}
void waitForWiFi() {
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(F("."));
}
}
void angleDimmer(void* xParam) {
int16_t gx, gy, gz;
while (1) {
M5.IMU.getGyroAdc(&gx, &gy, &gz);
if (gz >= ACCEL_THRESHOLD || gz <= -ACCEL_THRESHOLD) {
dimmer_value -= gz;// I want right turns to increment the brightness
last_activity = millis();
}
if (dimmer_value >= MAX_DIMMER_VALUE) {
dimmer_value = MAX_DIMMER_VALUE;
} else if (dimmer_value <= 0) {
dimmer_value = 0;
}
vTaskDelay(100 * portTICK_PERIOD_MS);
}
}
void sleepWait(void* xParam) {
while (1) {
if (millis() > last_activity + SLEEP_WAIT) {
inactive = true;
}
M5.Lcd.setCursor(0, 100);
M5.Lcd.print("Brightness: %");
M5.Lcd.setCursor(140, 100);
M5.Lcd.println(current_bright);
vTaskDelay(500 * portTICK_PERIOD_MS);
}
}
yeelight.cpp
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <WiFiUdp.h>
#include "yeelight.h"
WiFiUDP _udp;
WiFiClient _client;
IPAddress _ipMulti(239, 255, 255, 250);
char _packetBuffer;
String _location, _support;
bool _powered;
char _server;
uint16_t _cmdid = 0, _port = 0;
Yeelight::Yeelight() {}
Yeelight::~Yeelight() { _udp.stop(); }
void Yeelight::lookup() {
#ifdef ESP32
_udp.beginMulticast(_ipMulti, 1982);
_udp.beginMulticastPacket();
#else
_udp.beginMulticast(WiFi.localIP(), _ipMulti, 1982);
_udp.beginPacketMulticast(_ipMulti, 1982, WiFi.localIP());
#endif
_udp.print(
"M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1982\r\nMAN: "
"\"ssdp:discover\"\r\nST: wifi_bulb");
_udp.endPacket();
_udp.begin(1982);
}
int Yeelight::feedback() {
int packetSize = _udp.parsePacket();
if (packetSize) {
int len = _udp.read(_packetBuffer, 550);
if (len > 0) {
_packetBuffer = 0;
}
parseFeedback(_packetBuffer, len);
}
return packetSize;
}
void Yeelight::parseFeedback(char* buffer, size_t len) {
int i = 0, _i = 0;
char _b;
while (i < len) {
if (buffer == '\r' && i + 1 <= len && buffer == '\n') {
_b = 0;
// ----
String _str = String(_b);
if (_str.startsWith("Location: yeelight://")) {
int colon = _str.indexOf(':', 21) + 1;
_location = _str.substring(10);
_str.substring(21, colon).toCharArray(_server, colon - 21);
_port = _str.substring(colon).toInt();
}
if (_str.startsWith("support: ")) {
_support = _str.substring(9);
}
if (_str.startsWith("power: ")) {
_powered = _str.substring(7) == "on";
}
// ----
i = i + 2;
_i = 0;
} else {
_b = buffer;
i++;
_i++;
}
}
}
String Yeelight::sendCommand(String method, String params) {
if (_client.connect(_server, _port)) {
String payload = String("") + "{\"id\":" + (++_cmdid) + ",\"method\":\"" +
method + "\",\"params\":" + params + "}";
_client.println(payload);
}
String result = "";
while (_client.connected()) {
result = _client.readStringUntil('\r');
_client.stop();
}
return result;
}
bool Yeelight::isPowered() { return _powered; }
String Yeelight::getSupport() { return _support; }
String Yeelight::getLocation() { return _location; }
yeelight.h
#ifndef Yeelight_h
#define Yeelight_h
class Yeelight {
public:
Yeelight();
~Yeelight();
void lookup();
int feedback();
String getLocation();
String getSupport();
bool isPowered();
String sendCommand(String method, String params);
private:
void parseFeedback(char* buffer, size_t len);
};
#endif
页:
[1]