This is an old revision of the document!


Smart Hardware Monitor

  • Author: Ionel Patrascu
  • Email: ionel.patrascu3101@stud.acs.pub.ro
  • Master: SRIC

Introduction

Context

The rise of multi-tasking and the increasing demand for seamless user experiences have led to a need for more intuitive and efficient ways to manage information. While traditional methods like pop-up windows or notifications can be disruptive, a dedicated display offering real-time metrics could provide a more discreet and focused approach to managing relevant data.

Problem Description

Current solutions for displaying metrics during active tasks often interrupt the user's workflow. This can be particularly detrimental in activities requiring focus and precision, such as gaming. There is a lack of a dedicated, non-intrusive display solution that can present relevant metrics without requiring users to switch between applications or lose their current focus. This project aims to address this gap by developing an IoT system that utilizes an LCD screen to provide a continuous stream of metrics without disrupting the user's primary activity.

Arhitecture

System Overview

Hardware

Circuit Diagram

The circuit diagram showcases a basic setup for the ESP8266 microcontroller, connected to an I2C LCD display and a joystick. The ESP32, a powerful and versatile microcontroller, serves as the central processing unit for the system. It's connected to the LCD display via a set of wires, for 5V, GND, SDA, and SCL. The ESP32 is also connected to the joystick via a set of wires: 3.3V, GND, VRx (analog), SW (digital).

Pinout Scheme

The Pinout scheme of the ESP8266 board that I used is the following:

Software

Backend

This Python code sets up a Flask web server to provide system hardware information through a REST API endpoint. It first initializes the .NET runtime and imports the OpenHardwareMonitorLib to access hardware data. A Computer object is created, enabling monitoring of CPU, GPU, and RAM. The code then defines a Flask route '/info' that responds to GET requests by collecting data from the enabled hardware sensors, processing it into a dictionary, and returning it as a JSON response. This allows external applications, such as the ESP8266 microcontroller, to retrieve real-time system metrics from the server for display or other purposes.

# Initialize the .NET runtime which we'll use for
# information about the hardware.
clr.AddReference(r'.\OpenHardwareMonitorLib')
from OpenHardwareMonitor.Hardware import Computer
 
# Create a new Computer instance and enable the CPU, GPU
# and RAM sensors.
c = Computer()
c.CPUEnabled = True # get the Info about CPU
c.GPUEnabled = True # get the Info about GPU
c.RAMEnabled = True # get the Info about RAM
c.Open()
 
app = Flask(__name__)
 
@app.route('/info', methods=['GET'])
def get_info():
    # return all the info available
    response = {}
    for hardware in c.Hardware:
        hardware.Update()
        response[hardware.Identifier.ToString()] = {}
        for sensor in hardware.Sensors:
            response[hardware.Identifier.ToString()][sensor.Identifier.ToString()] = sensor.Value
 
    return jsonify(response)

The backend service must be executed as administrator. Otherwise, it won't be able to collect some of the data and under some systems, it might fail to start.

Api Response Example

The API response is a JSON object containing detailed information about the system's hardware components, including CPU, GPU, and RAM. Each component is represented by a unique identifier, and its individual metrics, such as clock speed, load, power consumption, and temperature, are organized under corresponding sub-identifiers.

{
  "/intelcpu/0": {                           // CPU 0
    "/intelcpu/0/clock/0": 99.9998779296875, // Bus Speed
    "/intelcpu/0/clock/1": 3699.99536132813, // Core 0
    "/intelcpu/0/clock/2": 3699.99536132813, // Core 1
    "/intelcpu/0/clock/3": 3699.99536132813, // Core 2
    "/intelcpu/0/clock/4": 3699.99536132813, // Core 3
    "/intelcpu/0/load/0": 4.15613651275635,  // Load total
    "/intelcpu/0/load/1": 3.78488302230835,  // Load core 0
    "/intelcpu/0/load/2": 4.3637752532959,   // Load core 1
    "/intelcpu/0/load/3": 4.15459871292114,  // Load core 2
    "/intelcpu/0/load/4": 4.32131290435791,  // Load core 3
    "/intelcpu/0/power/0": 2.94126510620117, // Power CPU Package
    "/intelcpu/0/power/1": 1.45460450649261, // Power cores
    "/intelcpu/0/power/2": 0,                // Power graphics
    "/intelcpu/0/power/3": 0.542671918869019,// Power DRAM
    "/intelcpu/0/temperature/0": 51,         // Temperature Core 0
    "/intelcpu/0/temperature/1": 54,         // Temperature Core 1
    "/intelcpu/0/temperature/2": 53,         // Temperature Core 2
    "/intelcpu/0/temperature/3": 52,         // Temperature Core 3  
    "/intelcpu/0/temperature/4": 54          // Temperature CPU Package
  },
  "/nvidiagpu/0": {                          // GPU 0
    "/nvidiagpu/0/clock/0": 135,             // GPU Core
    "/nvidiagpu/0/clock/1": 324.000030517578,// Memory
    "/nvidiagpu/0/clock/2": 270,             // Shader           
    "/nvidiagpu/0/control/0": 25,            // Fan
    "/nvidiagpu/0/fan/0": 1066,              // Fan Speed
    "/nvidiagpu/0/load/0": 0,                // Load Core
    "/nvidiagpu/0/load/1": 7,                // Load Frame Buffer
    "/nvidiagpu/0/load/2": 0,                // Load Video Engine
    "/nvidiagpu/0/load/3": 0,                // Load Bus Interface
    "/nvidiagpu/0/load/4": 23.1866836547852, // Load Memory 
    "/nvidiagpu/0/power/0": 27.2940006256104,// Power GPU
    "/nvidiagpu/0/smalldata/1": 3146.2734375,// VRAM Free
    "/nvidiagpu/0/smalldata/2": 949.7265625, // VRAM Used
    "/nvidiagpu/0/smalldata/3": 4096,        // VRAM Total
    "/nvidiagpu/0/temperature/0": 43,        // Temperature GPU
    "/nvidiagpu/0/throughput/0": 0.00390625, // Throughput PCIE Rx
    "/nvidiagpu/0/throughput/1": 0.0009765625 // Throughput PCIE Tx
  },
  "/ram": {
    "/ram/data/0": 13.5922622680664,         // RAM Used
    "/ram/data/1": 18.3470077514648,         // RAM Free
    "/ram/load/0": 42.556583404541           // RAM Load
  }
} 

ESP8266

Constants definition

The constants defined in the code represent various settings and parameters used throughout the program. They are declared using the const keyword, ensuring that their values remain unchanged during program execution.

  • X_PIN: This constant defines the analog pin (A0) connected to the joystick's X-axis. This pin is used to read the joystick's horizontal position.
  • JOYSTICK_THRESHOLD: This constant defines a threshold value (512) used to determine when the joystick is moved left or right. The analogRead value from the joystick is compared to this threshold to trigger state changes.
  • KEY_PIN: This constant defines the digital pin (D3) connected to the joystick's button. This pin is used to detect button presses.
  • actionDelay: This constant defines the delay (1000 milliseconds) between state changes or actions. It helps to avoid rapid transitions and provides a smoother user experience.
  • ssid: This constant stores the name of the Wi-Fi network the ESP8266 should connect to.
  • password: This constant stores the password for the specified Wi-Fi network.
  • serverAddress: This constant stores the IP address of the server providing the system hardware information.
  • serverPort: This constant stores the port number on the server that the ESP8266 should connect to.
  • stateChangeInterval: This constant defines the interval (10000 milliseconds) at which the display state automatically changes if the joystick is not moved. This ensures that the display cycles through different information even if the user is not actively interacting with the joystick.

These constants provide a clear and organized way to manage the configuration parameters of the ESP8266 system, making the code more readable and maintainable.

Send request function

The sendRequest() function is responsible for retrieving system hardware information from the server. It uses the HTTPClient library to send an HTTP GET request to the specified server address and port, requesting data from the /info endpoint. The function includes error handling to ensure a robust connection.

The function first initializes the HTTPClient object and specifies the server address, port, and endpoint. Then, it enters a loop that continues until a successful response is received from the server. Within the loop, it sends the GET request using http.GET(). If the request fails (returns -1), an error message is printed to the serial monitor, and the LCD displays “Conn Error.” and “Retrying…”. The function then waits for 1 second before retrying the request.

If the request is successful (returns a positive value), the function retrieves the response from the server using http.getString(). This response is then deserialized into a JSON document using the deserializeJson() function, making the hardware data accessible for processing and display. Finally, the function closes the HTTP connection using http.end().

// Function to send the request to the server. It will keep sending the request
// until it gets a response from the server. If the server is down, it will keep
// retrying to connect to the server.
// Output: None but it will update the global JSON document with the latest data
// received from the server (in json format)
void sendRequest() {
  http.begin(wifiClient, serverAddress, serverPort, "/info");
  int httpResponseCode = -1;
  String line = "";
  while (httpResponseCode == -1) {
    // Send the request to the server
    httpResponseCode = http.GET();
    if (httpResponseCode == -1) {
      Serial.println("Error sending request. Is the server up?");
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Conn Error.");
      lcd.setCursor(0, 1);
      lcd.print("Retrying...");
      delay(1000);
    }
    else
    {
      if (httpResponseCode > 0) {
        line = http.getString();
        // Deserialize the JSON document
        deserializeJson(doc, line);
      }
    }
  }
  http.end();
}

Setup function

The setup() function initializes the ESP8266 microcontroller, setting up the necessary components and establishing communication with the server. It begins by initializing serial communication for debugging purposes and then initializes the LCD display, turning on its backlight. The ESP8266 then attempts to connect to the specified Wi-Fi network using the provided SSID and password. Once connected, it verifies the connection by sending a request to the server and displaying the connection status on the LCD. Finally, the setup() function configures the joystick button pin as an input with a pull-up resistor.

void setup() {
  Serial.begin(115200); // Initialize serial communication for debugging
  // Initialize the LCD
  lcd.init();
  lcd.backlight(); // Turn on backlight (if you have it)
  // Initialize network connection
  connectToWiFi();
  connectToServer();
  // Set the KEY pin as an input with a pull-up resistor for joyztick button
  pinMode(KEY_PIN, INPUT_PULLUP);
  lastStateChangeTime = millis();
}
iothings/proiecte/2023sric/hardwaremonitor.1716990654.txt.gz · Last modified: 2024/05/29 16:50 by ionel.patrascu3101
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0