回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页
best-icon

赛博复古风DIY电脑性能监视器 —— bbMonitor 简单

头像 Corebb 2024.04.25 88 0

如果把电脑任务管理器里的性能监视器和老式复古的指针表结合起来,做到现实中会怎么样呢?这就是今天做的东西——bbMonitor。 

想象一下,当你的电脑忙碌时,指针就像是一只活泼的小动物一样在仪表盘上跳跃;当它运行顺畅时,指针则轻盈地舞动。这种奇妙的互动,让你能够更直观地感受到你的电脑在做什么。 其中的原理并不发杂,我们需要在电脑上运行一个软件将数据传给单片机,单片机输出相应比例的电压,再把表盘替换成实际显示的东西,再加点RGB等效,噔噔~就可以啦。

 

开源链接:
https://github.com/RealCorebb/bbMonitor

视频链接:
https://www.bilibili.com/video/BV1uM4m1f75z

1_1.74.1.jpg
2_1.76.2.jpg

代码
#include <Preferences.h>
#include <ESPmDNS.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>

#define P1 38
#define P2 5
#define P3 6
#define P4 7
#define P5 15
#define P6 16
#define P7 17
#define P8 18
#define P9 8
#define P10 9
#define P11 10
#define P12 11
#define P13 12
#define P14 13
#define P15 14
#define P16 21
#define P17 35
#define P18 36
const int pins[] = {P1, P2, P3, P4, P5, P6, P7, P8};
int luminence = 128;

#define LINES 2
#define EACH_PIXEL_COUNT 2
int cols = sizeof(pins) / sizeof(pins[0]) / LINES;

#define STRIP1_PIN    39   // Example pin for strip 1, replace with your actual pin
#define STRIP2_PIN    40   // Example pin for strip 2, replace with your actual pin
#define PIXEL_COUNT   8  // Replace with the actual number of NeoPixels per strip

NeoPixelBus<NeoGrbFeature, NeoEsp32Rmt1Ws2812xMethod> strip1(PIXEL_COUNT, STRIP1_PIN);
NeoPixelBus<NeoGrbFeature, NeoEsp32Rmt2Ws2812xMethod> strip2(PIXEL_COUNT, STRIP2_PIN);

NeoPixelAnimator animations1(PIXEL_COUNT);
NeoPixelAnimator animations2(PIXEL_COUNT);

AnimEaseFunction easing = NeoEase::CubicIn;

#define MAX 250

Preferences preferences;
bool mdnsOn = false;

AsyncWebServer server(80);
AsyncWebSocket ws("/");

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = static_cast<AwsFrameInfo*>(arg);
  static String message;

  if (info->index == 0) {
    // This is a new message, clear our message string
    message = "";
  }

  // Append the data from this frame to our message
  for(size_t i=0; i<len; i++) {
    message += (char)data[i];
  }

  if (info->final) {
    // The final frame has been received, process the message
    handleWebSocketText((uint8_t *)message.c_str(), message.length());
  }
}

void handleWebSocketText(uint8_t *payload, size_t length) {
  // Parse JSON data
  DynamicJsonDocument jsonDoc(512);
  DeserializationError error = deserializeJson(jsonDoc, payload, length);

  if (error) {
    Serial.println("Failed to parse JSON");
    return;
  }

  // Check if the "data" key exists
  if (jsonDoc.containsKey("data")) {
    JsonArray data = jsonDoc["data"];
    Serial.println(data);
    
    // Iterate through the array and set analogWrite values for defined pins
    for (int i = 0; i < data.size(); i++) {
      // Ensure pinIndex is within bounds
      if (i < sizeof(pins) / sizeof(pins[0])) {
        float pinValue = data[i].as<float>(); // Extract the value from the array element
        int pinIndex = i;
        
        analogWrite(pins[pinIndex], MAX * pinValue);
        
        Serial.print("Set PWM value for Pin ");
        Serial.print("P" + String(pinIndex + 1)); // Pin names start from P1
        Serial.print(" to ");
        Serial.println(pinValue);
        
        // Determine the strip and pixel index based on pinIndex
        int stripIndex = pinIndex < cols ? 0 : 1;
        int pixelIndex = (pinIndex & cols - 1) * EACH_PIXEL_COUNT;

        // Set NeoPixel animation based on pinValue
        setNeoPixelAnimation(stripIndex, pixelIndex, pinValue);
      } else {
        Serial.println("Invalid Pin Index: " + String(i));
      }
    }
}
 else if(jsonDoc.containsKey("config")){
    //write the entire json.config string to the preferences config
    luminence = jsonDoc["config"]["brightNess"].as<int>();
    preferences.putString("config", jsonDoc["config"].as<String>());  
 }
 else {
    Serial.println("No 'data' key found in JSON");
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
             void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      ws.cleanupClients();
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

void setup() {
  Serial.begin(115200);
  // put your setup code here, to run once:
  pinMode(P1,OUTPUT);
  pinMode(P2,OUTPUT);
  pinMode(P3,OUTPUT);
  pinMode(P4,OUTPUT);
  pinMode(P5,OUTPUT);
  pinMode(P6,OUTPUT);
  pinMode(P7,OUTPUT);
  pinMode(P8,OUTPUT);

  //Setup WiFi
  String ssid = preferences.getString("ssid","Hollyshit_A");
  String passwd = preferences.getString("passwd","00197633");
  String config = preferences.getString("config","{\"config\":{\"data\":[\"cpu_usage[0]\",\"cpu_usage[1]\",\"cpu_usage[2]\",\"cpu_usage[3]\",\"cpu_usage[4]\",\"cpu_usage[5]\",\"cpu_usage[6]\",\"cpu_usage[7]\"],\"brightNess\":128}}");
  if(ssid != "null" && passwd != "null"){
    WiFi.begin(ssid.c_str(),passwd.c_str());
  }

  //Load Config
  DynamicJsonDocument jsonDoc(512);
  DeserializationError error = deserializeJson(jsonDoc, config.c_str());
  if (error) {
    Serial.println("Failed to parse JSON");
  }
  else{
    luminence = jsonDoc["config"]["brightNess"].as<int>();
  }

  // Setup LED
  strip1.Begin();
  strip2.Begin();
  RgbColor color = RgbColor(25, 25, luminence);
  for(int i = 0; i < PIXEL_COUNT; i ++) {
    strip1.SetPixelColor(i, color);
    strip2.SetPixelColor(i, color);
  }
  strip1.Show();
  strip2.Show();

  // Setup WebSocket
  ws.onEvent(onEvent);
  server.addHandler(&ws);
  server.begin();
}

void setupMDNS(){
  if (!MDNS.begin("bbMonitor")) {
        Serial.println("Error setting up MDNS responder!");
    }
    else{
      MDNS.addService("bbMonitor", "tcp", 80);
      mdnsOn = true;
    }
}

void loop() {
  // put your main code here, to run repeatedly:
  if(!mdnsOn) setupMDNS();
  animations1.UpdateAnimations();
  animations2.UpdateAnimations();
  strip1.Show();
  strip2.Show();
}

void setNeoPixelAnimation(int stripIndex, int pixelIndex, float pinValue) {
  // Define animation parameters
  RgbColor green(0, luminence, 0);
  RgbColor red(luminence, 0, 0);
  
  // Calculate color based on pinValue
  RgbColor targetColor = RgbColor::LinearBlend(green, red, pinValue);
  // Set animation
  if (stripIndex == 0) {
    AnimUpdateCallback animUpdate = [=](const AnimationParam& param)
      {
          float progress = easing(param.progress);
          RgbColor color = RgbColor::LinearBlend(strip1.GetPixelColor(pixelIndex), targetColor, progress);
          for(int i = 0; i < EACH_PIXEL_COUNT; i ++) {
            strip1.SetPixelColor(pixelIndex + i, color);
          }
      };
    animations1.StartAnimation(pixelIndex, 1000, animUpdate);
  } else {
    animations2.StartAnimation(pixelIndex, 1000, [targetColor, pixelIndex](const AnimationParam& param) {
      RgbColor color = RgbColor::LinearBlend(strip2.GetPixelColor(pixelIndex), targetColor, param.progress);
      for(int i = 0; i < EACH_PIXEL_COUNT; i ++) {
        strip2.SetPixelColor(pixelIndex + i, color);
      }
    });
  }
}

评论

user-avatar