yeelight灯泡wifi控制器-Arduino中文社区 - Powered by Discuz! Archiver

vany5921 发表于 2020-7-1 10:53

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]
查看完整版本: yeelight灯泡wifi控制器