mirror of
https://github.com/0015/ThatProject.git
synced 2026-01-12 17:27:43 +03:00
Make your own System Monitor with ESP32 + LVGL 8
This commit is contained in:
@@ -0,0 +1,411 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
/*
|
||||||
|
Make your own System Monitor with ESP32 + LVGL 8
|
||||||
|
For More Information: https://youtu.be/gliwNg25fLE
|
||||||
|
Created by Eric N. (ThatProject)
|
||||||
|
*/
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// Arduino IDE
|
||||||
|
// ESP v2.0.3
|
||||||
|
// LVGL v8.2.0
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
#include <ArduinoJson.h> //https://arduinojson.org/v6/doc/installation/
|
||||||
|
#include <ESP32Time.h> //https://github.com/fbiego/ESP32Time
|
||||||
|
#include <lvgl.h> //https://github.com/lvgl/lvgl
|
||||||
|
|
||||||
|
#define LGFX_USE_V1 //https://github.com/lovyan03/LovyanGFX
|
||||||
|
#include <LovyanGFX.hpp>
|
||||||
|
#include <FT6236.h> //https://github.com/DustinWatts/FT6236
|
||||||
|
#define SDA_FT6236 21
|
||||||
|
#define SCL_FT6236 22
|
||||||
|
FT6236 ts = FT6236();
|
||||||
|
|
||||||
|
class LGFX : public lgfx::LGFX_Device {
|
||||||
|
lgfx::Panel_ST7796 _panel_instance;
|
||||||
|
lgfx::Bus_SPI _bus_instance;
|
||||||
|
lgfx::Light_PWM _light_instance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LGFX(void) {
|
||||||
|
{
|
||||||
|
auto cfg = _bus_instance.config();
|
||||||
|
cfg.spi_host = VSPI_HOST;
|
||||||
|
cfg.spi_mode = 0;
|
||||||
|
cfg.freq_write = 40000000;
|
||||||
|
cfg.freq_read = 16000000;
|
||||||
|
cfg.spi_3wire = false;
|
||||||
|
cfg.use_lock = true;
|
||||||
|
cfg.dma_channel = 1;
|
||||||
|
cfg.pin_sclk = 18;
|
||||||
|
cfg.pin_mosi = 19;
|
||||||
|
cfg.pin_miso = 23;
|
||||||
|
cfg.pin_dc = 27;
|
||||||
|
_bus_instance.config(cfg);
|
||||||
|
_panel_instance.setBus(&_bus_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto cfg = _panel_instance.config();
|
||||||
|
cfg.pin_cs = 5;
|
||||||
|
cfg.pin_rst = -1;
|
||||||
|
cfg.pin_busy = -1;
|
||||||
|
cfg.memory_width = 320;
|
||||||
|
cfg.memory_height = 480;
|
||||||
|
cfg.panel_width = 320;
|
||||||
|
cfg.panel_height = 480;
|
||||||
|
cfg.offset_x = 0;
|
||||||
|
cfg.offset_y = 0;
|
||||||
|
cfg.offset_rotation = 0;
|
||||||
|
cfg.dummy_read_pixel = 8;
|
||||||
|
cfg.dummy_read_bits = 1;
|
||||||
|
cfg.readable = true;
|
||||||
|
cfg.invert = false;
|
||||||
|
cfg.rgb_order = false;
|
||||||
|
cfg.dlen_16bit = false;
|
||||||
|
cfg.bus_shared = true;
|
||||||
|
|
||||||
|
_panel_instance.config(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto cfg = _light_instance.config();
|
||||||
|
|
||||||
|
cfg.pin_bl = 12;
|
||||||
|
cfg.invert = false;
|
||||||
|
cfg.freq = 44100;
|
||||||
|
cfg.pwm_channel = 7;
|
||||||
|
|
||||||
|
_light_instance.config(cfg);
|
||||||
|
_panel_instance.setLight(&_light_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPanel(&_panel_instance);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LGFX tft;
|
||||||
|
|
||||||
|
ESP32Time rtc;
|
||||||
|
|
||||||
|
StaticJsonDocument<512> doc;
|
||||||
|
|
||||||
|
struct queue_t {
|
||||||
|
String data_string;
|
||||||
|
};
|
||||||
|
static QueueHandle_t data_queue;
|
||||||
|
|
||||||
|
/*Change to your screen resolution*/
|
||||||
|
static const uint32_t screenWidth = 480;
|
||||||
|
static const uint32_t screenHeight = 320;
|
||||||
|
static lv_disp_draw_buf_t draw_buf;
|
||||||
|
static lv_color_t buf[screenWidth * 10];
|
||||||
|
int prev_cpu_usage = 0;
|
||||||
|
int prev_mem_usage = 0;
|
||||||
|
|
||||||
|
/* Display flushing */
|
||||||
|
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
|
||||||
|
uint32_t w = (area->x2 - area->x1 + 1);
|
||||||
|
uint32_t h = (area->y2 - area->y1 + 1);
|
||||||
|
|
||||||
|
tft.startWrite();
|
||||||
|
tft.setAddrWindow(area->x1, area->y1, w, h);
|
||||||
|
tft.writePixels((lgfx::rgb565_t *)&color_p->full, w * h);
|
||||||
|
tft.endWrite();
|
||||||
|
|
||||||
|
lv_disp_flush_ready(disp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Read the touchpad*/
|
||||||
|
void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) {
|
||||||
|
if (ts.touched()) {
|
||||||
|
data->state = LV_INDEV_STATE_PR;
|
||||||
|
TS_Point p = ts.getPoint();
|
||||||
|
data->point.x = tft.width() - p.y;
|
||||||
|
data->point.y = p.x;
|
||||||
|
} else {
|
||||||
|
data->state = LV_INDEV_STATE_REL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
tft.begin();
|
||||||
|
tft.setRotation(3);
|
||||||
|
tft.setBrightness(255);
|
||||||
|
|
||||||
|
if (!ts.begin(40, SDA_FT6236, SCL_FT6236)) {
|
||||||
|
Serial.println("Unable to start the capacitive touch Screen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_init();
|
||||||
|
lv_disp_draw_buf_init(&draw_buf, buf, NULL, screenWidth * 10);
|
||||||
|
|
||||||
|
/*Initialize the display*/
|
||||||
|
static lv_disp_drv_t disp_drv;
|
||||||
|
lv_disp_drv_init(&disp_drv);
|
||||||
|
|
||||||
|
/*Change the following line to your display resolution*/
|
||||||
|
disp_drv.hor_res = screenWidth;
|
||||||
|
disp_drv.ver_res = screenHeight;
|
||||||
|
disp_drv.flush_cb = my_disp_flush;
|
||||||
|
disp_drv.draw_buf = &draw_buf;
|
||||||
|
lv_disp_drv_register(&disp_drv);
|
||||||
|
|
||||||
|
/*Initialize the (dummy) input device driver*/
|
||||||
|
static lv_indev_drv_t indev_drv;
|
||||||
|
lv_indev_drv_init(&indev_drv);
|
||||||
|
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||||
|
indev_drv.read_cb = my_touchpad_read;
|
||||||
|
lv_indev_drv_register(&indev_drv);
|
||||||
|
|
||||||
|
lv_main();
|
||||||
|
|
||||||
|
data_queue = xQueueCreate(8, sizeof(queue_t));
|
||||||
|
|
||||||
|
xTaskCreatePinnedToCore(lvglTimerHandler,
|
||||||
|
"lvglTimerHandler",
|
||||||
|
4096,
|
||||||
|
NULL,
|
||||||
|
2,
|
||||||
|
NULL,
|
||||||
|
1);
|
||||||
|
|
||||||
|
xTaskCreatePinnedToCore(serialTask,
|
||||||
|
"serialTask",
|
||||||
|
2048,
|
||||||
|
NULL,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lvglTimerHandler(void *pvParameters) {
|
||||||
|
queue_t q;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (xQueueReceive(data_queue, &q, 0) == pdTRUE) {
|
||||||
|
dataParser(q.data_string);
|
||||||
|
loading_spinner_delete();
|
||||||
|
}
|
||||||
|
lv_timer_handler();
|
||||||
|
vTaskDelay(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {}
|
||||||
|
|
||||||
|
static lv_obj_t *loading_screen;
|
||||||
|
static lv_obj_t *meter;
|
||||||
|
static lv_obj_t *date_time_label;
|
||||||
|
static lv_obj_t *cpu_label;
|
||||||
|
static lv_obj_t *mem_label;
|
||||||
|
static lv_obj_t *battery_label;
|
||||||
|
static lv_meter_indicator_t *cpu_indic;
|
||||||
|
static lv_meter_indicator_t *mem_indic;
|
||||||
|
static lv_obj_t *process_list;
|
||||||
|
static lv_anim_t a;
|
||||||
|
|
||||||
|
static void set_value(void *indic, int32_t v) {
|
||||||
|
lv_meter_set_indicator_end_value(meter, (lv_meter_indicator_t *)indic, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lv_main(void) {
|
||||||
|
meter = lv_meter_create(lv_scr_act());
|
||||||
|
lv_obj_align(meter, LV_ALIGN_BOTTOM_LEFT, 0, 0);
|
||||||
|
lv_obj_set_size(meter, 280, 280);
|
||||||
|
lv_obj_remove_style(meter, NULL, LV_PART_INDICATOR);
|
||||||
|
|
||||||
|
lv_meter_scale_t *scale = lv_meter_add_scale(meter);
|
||||||
|
lv_meter_set_scale_ticks(meter, scale, 11, 2, 10, lv_palette_main(LV_PALETTE_GREY));
|
||||||
|
lv_meter_set_scale_major_ticks(meter, scale, 1, 2, 30, lv_color_hex3(0xeee), 15);
|
||||||
|
lv_meter_set_scale_range(meter, scale, 0, 100, 270, 90);
|
||||||
|
|
||||||
|
cpu_indic = lv_meter_add_arc(meter, scale, 10, lv_palette_main(LV_PALETTE_RED), 0);
|
||||||
|
mem_indic = lv_meter_add_arc(meter, scale, 10, lv_palette_main(LV_PALETTE_BLUE), -20);
|
||||||
|
|
||||||
|
lv_anim_init(&a);
|
||||||
|
lv_anim_set_exec_cb(&a, set_value);
|
||||||
|
|
||||||
|
static lv_style_t style_red;
|
||||||
|
lv_style_init(&style_red);
|
||||||
|
lv_style_set_radius(&style_red, 5);
|
||||||
|
lv_style_set_bg_opa(&style_red, LV_OPA_COVER);
|
||||||
|
lv_style_set_bg_color(&style_red, lv_palette_main(LV_PALETTE_RED));
|
||||||
|
lv_style_set_outline_width(&style_red, 2);
|
||||||
|
lv_style_set_outline_color(&style_red, lv_palette_main(LV_PALETTE_RED));
|
||||||
|
lv_style_set_outline_pad(&style_red, 4);
|
||||||
|
|
||||||
|
static lv_style_t style_blue;
|
||||||
|
lv_style_init(&style_blue);
|
||||||
|
lv_style_set_radius(&style_blue, 5);
|
||||||
|
lv_style_set_bg_opa(&style_blue, LV_OPA_COVER);
|
||||||
|
lv_style_set_bg_color(&style_blue, lv_palette_main(LV_PALETTE_BLUE));
|
||||||
|
lv_style_set_outline_width(&style_blue, 2);
|
||||||
|
lv_style_set_outline_color(&style_blue, lv_palette_main(LV_PALETTE_BLUE));
|
||||||
|
lv_style_set_outline_pad(&style_blue, 4);
|
||||||
|
|
||||||
|
lv_obj_t *red_obj = lv_obj_create(lv_scr_act());
|
||||||
|
lv_obj_set_size(red_obj, 10, 10);
|
||||||
|
lv_obj_add_style(red_obj, &style_red, 0);
|
||||||
|
lv_obj_align(red_obj, LV_ALIGN_CENTER, -60, 80);
|
||||||
|
|
||||||
|
cpu_label = lv_label_create(lv_scr_act());
|
||||||
|
lv_obj_set_width(cpu_label, 200);
|
||||||
|
lv_label_set_text(cpu_label, "CPU Usage: 0%");
|
||||||
|
lv_obj_align_to(cpu_label, red_obj, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
|
||||||
|
|
||||||
|
lv_obj_t *blue_obj = lv_obj_create(lv_scr_act());
|
||||||
|
lv_obj_set_size(blue_obj, 10, 10);
|
||||||
|
lv_obj_add_style(blue_obj, &style_blue, 0);
|
||||||
|
lv_obj_align(blue_obj, LV_ALIGN_CENTER, -60, 110);
|
||||||
|
|
||||||
|
mem_label = lv_label_create(lv_scr_act());
|
||||||
|
lv_obj_set_width(mem_label, 200);
|
||||||
|
lv_label_set_text(mem_label, "MEM Usage: 0%");
|
||||||
|
lv_obj_align_to(mem_label, blue_obj, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
|
||||||
|
|
||||||
|
date_time_label = lv_label_create(lv_scr_act());
|
||||||
|
lv_obj_set_style_text_align(date_time_label, LV_TEXT_ALIGN_RIGHT, 0);
|
||||||
|
lv_obj_align(date_time_label, LV_ALIGN_TOP_RIGHT, -10, 0);
|
||||||
|
lv_label_set_text(date_time_label, "Mon 1:25 PM");
|
||||||
|
|
||||||
|
battery_label = lv_label_create(lv_scr_act());
|
||||||
|
lv_label_set_text(battery_label, LV_SYMBOL_CHARGE " 0%");
|
||||||
|
lv_obj_set_style_text_align(battery_label, LV_TEXT_ALIGN_RIGHT, 0);
|
||||||
|
lv_obj_align(battery_label, LV_ALIGN_TOP_RIGHT, -130, 0);
|
||||||
|
|
||||||
|
process_list = lv_list_create(lv_scr_act());
|
||||||
|
lv_obj_set_size(process_list, 240, 190);
|
||||||
|
lv_obj_align(process_list, LV_ALIGN_TOP_RIGHT, 0, 30);
|
||||||
|
lv_obj_set_style_pad_row(process_list, -10, 0);
|
||||||
|
lv_obj_set_style_pad_hor(process_list, -6, 0);
|
||||||
|
|
||||||
|
loading_spinner_make();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loading_spinner_make() {
|
||||||
|
|
||||||
|
loading_screen = lv_obj_create(lv_scr_act());
|
||||||
|
lv_obj_set_size(loading_screen, 480, 320);
|
||||||
|
lv_obj_center(loading_screen);
|
||||||
|
|
||||||
|
lv_obj_t *loading_spinner = lv_spinner_create(loading_screen, 1000, 60);
|
||||||
|
lv_obj_set_size(loading_spinner, 240, 240);
|
||||||
|
lv_obj_center(loading_spinner);
|
||||||
|
|
||||||
|
lv_obj_t *loading_label = lv_label_create(loading_spinner);
|
||||||
|
lv_label_set_text(loading_label, "Waiting for Data...");
|
||||||
|
lv_obj_center(loading_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loading_spinner_delete() {
|
||||||
|
if (loading_screen != NULL) {
|
||||||
|
lv_obj_del(loading_screen);
|
||||||
|
loading_screen = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialTask(void *pvParameters) {
|
||||||
|
queue_t q;
|
||||||
|
while (1) {
|
||||||
|
if (Serial.available()) {
|
||||||
|
String input = Serial.readStringUntil('\n');
|
||||||
|
input.trim();
|
||||||
|
q.data_string = input;
|
||||||
|
xQueueSend(data_queue, &q, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
vTaskDelay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dataParser(String jsonData) {
|
||||||
|
Serial.println(jsonData);
|
||||||
|
|
||||||
|
if (jsonData.length() < 10)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DeserializationError error = deserializeJson(doc, jsonData);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
Serial.print(F("deserializeJson() failed: "));
|
||||||
|
Serial.println(error.f_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long local_time = doc["local_time"];
|
||||||
|
long utc_offset = doc["utc_offset"];
|
||||||
|
update_time(local_time, utc_offset);
|
||||||
|
|
||||||
|
float cpu_percent_total = doc["cpu_percent_total"];
|
||||||
|
float mem_percent = doc["mem_percent"];
|
||||||
|
update_cpu_mem_usage(cpu_percent_total, mem_percent);
|
||||||
|
|
||||||
|
float battery_percent = doc["battery_percent"];
|
||||||
|
bool power_plugged = doc["power_plugged"];
|
||||||
|
update_battery(battery_percent, power_plugged);
|
||||||
|
|
||||||
|
update_process(doc["cpu_top5_process"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_time(long local_time, long utc_offset) {
|
||||||
|
rtc.setTime(local_time);
|
||||||
|
rtc.offset = utc_offset;
|
||||||
|
lv_label_set_text(date_time_label, rtc.getTime("%a %I:%M %p").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_cpu_mem_usage(float cpu_percent_total, float mem_percent) {
|
||||||
|
String cpu_text = String("CPU Usage: ") + cpu_percent_total + "%";
|
||||||
|
lv_label_set_text(cpu_label, cpu_text.c_str());
|
||||||
|
|
||||||
|
lv_anim_set_var(&a, cpu_indic);
|
||||||
|
lv_anim_set_time(&a, 500);
|
||||||
|
lv_anim_set_values(&a, prev_cpu_usage, int(cpu_percent_total));
|
||||||
|
lv_anim_start(&a);
|
||||||
|
prev_cpu_usage = int(cpu_percent_total);
|
||||||
|
|
||||||
|
String mem_text = String("MEM Usage: ") + mem_percent + "%";
|
||||||
|
lv_label_set_text(mem_label, mem_text.c_str());
|
||||||
|
|
||||||
|
lv_anim_set_var(&a, mem_indic);
|
||||||
|
lv_anim_set_time(&a, 500);
|
||||||
|
lv_anim_set_values(&a, prev_mem_usage, int(mem_percent));
|
||||||
|
lv_anim_start(&a);
|
||||||
|
prev_mem_usage = int(mem_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_battery(float battery_percent, bool power_plugged) {
|
||||||
|
char buffer[16];
|
||||||
|
if (power_plugged) {
|
||||||
|
sprintf(buffer, "\xEF\x83\xA7 %d %%", int(battery_percent));
|
||||||
|
} else {
|
||||||
|
if (battery_percent >= 95) {
|
||||||
|
sprintf(buffer, "\xEF\x89\x80 %d %%", int(battery_percent));
|
||||||
|
} else if (battery_percent >= 75 && battery_percent < 95) {
|
||||||
|
sprintf(buffer, "\xEF\x89\x81 %d %%", int(battery_percent));
|
||||||
|
} else if (battery_percent >= 50 && battery_percent < 75) {
|
||||||
|
sprintf(buffer, "\xEF\x89\x82 %d %%", int(battery_percent));
|
||||||
|
} else if (battery_percent >= 20 && battery_percent < 50) {
|
||||||
|
sprintf(buffer, "\xEF\x89\x83 %d %%", int(battery_percent));
|
||||||
|
} else {
|
||||||
|
sprintf(buffer, "\xEF\x89\x84 %d %%", int(battery_percent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_label_set_text(battery_label, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_process(JsonArray processes) {
|
||||||
|
int arraySize = processes.size();
|
||||||
|
if (arraySize > 0) {
|
||||||
|
lv_obj_clean(process_list);
|
||||||
|
for (int i = 0; i < arraySize; i++) {
|
||||||
|
lv_obj_t *list_item_button = lv_list_add_btn(process_list, LV_SYMBOL_WARNING, processes[i]);
|
||||||
|
lv_obj_t *child = lv_obj_get_child(list_item_button, 1);
|
||||||
|
lv_label_set_long_mode(child, LV_LABEL_LONG_WRAP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
class RepeatedTimer(object):
|
||||||
|
def __init__(self, interval, function, *args, **kwargs):
|
||||||
|
self._timer = None
|
||||||
|
self.interval = interval
|
||||||
|
self.function = function
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.is_running = False
|
||||||
|
self.next_call = time.time()
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def _run(self):
|
||||||
|
self.is_running = False
|
||||||
|
self.start()
|
||||||
|
self.function(*self.args, **self.kwargs)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
if not self.is_running:
|
||||||
|
self.next_call += self.interval
|
||||||
|
self._timer = threading.Timer(self.next_call - time.time(), self._run)
|
||||||
|
self._timer.start()
|
||||||
|
self.is_running = True
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._timer.cancel()
|
||||||
|
self.is_running = False
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
'''
|
||||||
|
Make your own System Monitor with ESP32 + LVGL 8
|
||||||
|
For More Information: https://youtu.be/gliwNg25fLE
|
||||||
|
Created by Eric N. (ThatProject)
|
||||||
|
'''
|
||||||
|
from serial import SerialTimeoutException, SerialException
|
||||||
|
|
||||||
|
from RepeatedTimer import RepeatedTimer
|
||||||
|
import sys
|
||||||
|
import psutil
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
import serial
|
||||||
|
|
||||||
|
serial_baudrate = 115200
|
||||||
|
ser = None
|
||||||
|
update_interval = 2
|
||||||
|
|
||||||
|
def write_to_serial(str_json):
|
||||||
|
try:
|
||||||
|
ser.write(str_json.encode())
|
||||||
|
except SerialTimeoutException:
|
||||||
|
print('[Error] Timeout when writing to the serial.')
|
||||||
|
except SerialException:
|
||||||
|
print('[Error] An unexpected exception occurred while writing to the serial.')
|
||||||
|
|
||||||
|
def process_list(delay=1):
|
||||||
|
proccesses = list(psutil.process_iter())
|
||||||
|
procs = []
|
||||||
|
try:
|
||||||
|
for proc in proccesses:
|
||||||
|
proc.cpu_percent(None)
|
||||||
|
sys.stdout.flush()
|
||||||
|
time.sleep(delay)
|
||||||
|
|
||||||
|
for proc in proccesses:
|
||||||
|
percent = proc.cpu_percent(None)
|
||||||
|
if percent:
|
||||||
|
procs.append((percent, proc.name()))
|
||||||
|
except ProcessLookupError:
|
||||||
|
pass
|
||||||
|
except psutil.NoSuchProcess:
|
||||||
|
pass
|
||||||
|
|
||||||
|
res = sorted(procs, key=lambda x: x[0], reverse=True)[:5]
|
||||||
|
return res
|
||||||
|
|
||||||
|
def get_system_info():
|
||||||
|
data = {}
|
||||||
|
# Get System LocalTime
|
||||||
|
ts = time.time()
|
||||||
|
utc_offset = (datetime.datetime.fromtimestamp(ts) -
|
||||||
|
datetime.datetime.utcfromtimestamp(ts)).total_seconds()
|
||||||
|
data['utc_offset'] = int(utc_offset)
|
||||||
|
|
||||||
|
presentDate = datetime.datetime.now()
|
||||||
|
unix_timestamp = datetime.datetime.timestamp(presentDate)
|
||||||
|
data['local_time'] = int(unix_timestamp)
|
||||||
|
|
||||||
|
# CPU Usage
|
||||||
|
cpu_percent_cores = psutil.cpu_percent(interval=2, percpu=True)
|
||||||
|
avg = sum(cpu_percent_cores) / len(cpu_percent_cores)
|
||||||
|
data['cpu_percent_total'] = round(avg, 2)
|
||||||
|
|
||||||
|
# MEM Usage
|
||||||
|
data['mem_percent'] = psutil.virtual_memory().percent
|
||||||
|
|
||||||
|
# Battery Info
|
||||||
|
battery = psutil.sensors_battery()
|
||||||
|
data['battery_percent'] = battery.percent if battery.percent is not None else 100
|
||||||
|
data['power_plugged'] = battery.power_plugged
|
||||||
|
|
||||||
|
# Top 5 CPU Usage Processes
|
||||||
|
data['cpu_top5_process'] = ['%.1f%% %s' % x for x in process_list()]
|
||||||
|
write_to_serial(json.dumps(data))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description='<Need to set your Serial Port, BaudRate and Interval to fetch system info.> (sudo permission required on Mac)', usage='python main.py --port /dev/cu.SLAB_USBtoUART')
|
||||||
|
parser.add_argument('-p', '--port', help='Set the Connected USB Port')
|
||||||
|
parser.add_argument('-b', '--baud', help='Set Serial Baud Rate(default=115200)', type=int, default=115200)
|
||||||
|
parser.add_argument('-i', '--interval', help='Set Update Interval in Second(default=2)', type=int, default=2)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.port is None:
|
||||||
|
print('usage: sudo python main.py --port /dev/cu.SLAB_USBtoUART')
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if args.baud is not None:
|
||||||
|
serial_baudrate = args.baud
|
||||||
|
|
||||||
|
if args.interval is not None and args.interval > 1:
|
||||||
|
update_interval = args.interval
|
||||||
|
|
||||||
|
ser = serial.Serial(args.port, serial_baudrate)
|
||||||
|
print(ser)
|
||||||
|
|
||||||
|
if ser is not None and ser.is_open:
|
||||||
|
get_system_info()
|
||||||
|
rt = RepeatedTimer(update_interval, get_system_info)
|
||||||
|
else:
|
||||||
|
print('[Error] Check your Serial Port.')
|
||||||
|
sys.exit()
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
psutil
|
||||||
|
pyserial
|
||||||
Reference in New Issue
Block a user