Initial System Monitor Code
This commit is contained in:
commit
5fd76b071a
9 changed files with 608 additions and 0 deletions
55
README.md
Normal file
55
README.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# ESP8266 Based System Monitor
|
||||
|
||||
## Disclaimer!
|
||||
|
||||
### This project is based on work from [execuc/esp-hw-monitoring](https://github.com/execuc/esp-hw-monitoring) with several modifications to fit my needs. I take no credit for the original work.
|
||||
|
||||
### Modifications include but are not limited to:
|
||||
|
||||
- Major code cleanup
|
||||
- Data format modification
|
||||
- More efficient data reading
|
||||
|
||||
---
|
||||
|
||||
## What is this?
|
||||
|
||||
This is a simple ESP8266 based system monitor that can be used to monitor system information and resources. It also shows the current time as well as the ambient temperature and humidity.
|
||||
|
||||
## Components used
|
||||
|
||||
- ESP8266
|
||||
- 240*320 2.8 inch ILI9341 LCD
|
||||
- DHT22 temperature module (with resistor)
|
||||
|
||||
## Connecting the components
|
||||
|
||||
- Connect the LCD to the ESP8266 as follows:
|
||||
- LCD VCC to ESP8266 3.3V
|
||||
- LCD GND to ESP8266 GND
|
||||
- LCD CS to ESP8266 D2
|
||||
- LCD RESET to ESP8266 D3
|
||||
- LCD DC to ESP8266 D4
|
||||
|
||||
- Connect the DHT22 to the ESP8266 as follows:
|
||||
- DHT22 VCC to ESP8266 3.3V
|
||||
- DHT22 GND to ESP8266 GND
|
||||
- DHT22 DATA to ESP8266 D8
|
||||
|
||||
## How to use
|
||||
|
||||
- Install the Arduino IDE
|
||||
- Install the ESP8266 board
|
||||
- Install the following libraries:
|
||||
- Adafruit GFX Library
|
||||
- Adafruit ILI9341
|
||||
- Adafruit Unified Sensor
|
||||
- DHT sensor library
|
||||
|
||||
- Open the `sysmon.ino` file in the Arduino IDE
|
||||
|
||||
- Upload the code to the ESP8266
|
||||
|
||||
- Run the sysmon.py script on your computer
|
||||
|
||||
- Enjoy!
|
69
cpu.cpp
Normal file
69
cpu.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "cpu.h"
|
||||
|
||||
int16_t cpuUsageGlobal = defaultValue;
|
||||
int16_t cpuUsage[8] = {defaultValue, defaultValue, defaultValue,defaultValue, defaultValue, defaultValue, defaultValue, defaultValue};
|
||||
int16_t cpuTempGlobal = defaultValue;
|
||||
int16_t cpuTemp[8] = {defaultValue, defaultValue, defaultValue,defaultValue, defaultValue, defaultValue, defaultValue, defaultValue};
|
||||
uint32_t ramFree = defaultValue;
|
||||
uint32_t ramMax = defaultValue;
|
||||
|
||||
static int8_t extractArray(String &command, int16_t *array)
|
||||
{
|
||||
int8_t startIndex = 1, lastIndex;
|
||||
int8_t index = 0;
|
||||
bool needStop = false;
|
||||
while(index < 8)
|
||||
{
|
||||
lastIndex = command.indexOf(",", startIndex);
|
||||
if(lastIndex == -1)
|
||||
{
|
||||
lastIndex = command.length() - 1;
|
||||
needStop = true;
|
||||
}
|
||||
|
||||
array[index++] = command.substring(startIndex, lastIndex).toInt();
|
||||
if(needStop)
|
||||
break;
|
||||
startIndex = lastIndex +1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int8_t setCpuTemp(String command)
|
||||
{
|
||||
if(command.substring(0, 1) == "[")
|
||||
{
|
||||
extractArray(command, cpuTemp);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpuTempGlobal = command.toInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t setCpuUsage(String command)
|
||||
{
|
||||
if(command.substring(0, 1) == "[")
|
||||
{
|
||||
extractArray(command, cpuUsage);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpuUsageGlobal = command.toInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t setRamMax(String command)
|
||||
{
|
||||
ramMax = command.toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t setRamFree(String command)
|
||||
{
|
||||
ramFree = command.toInt();
|
||||
return 0;
|
||||
}
|
||||
|
21
cpu.h
Normal file
21
cpu.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef __CPU_H__
|
||||
#define __CPU_H__
|
||||
|
||||
#include<Arduino.h>
|
||||
|
||||
#define defaultValue 0
|
||||
|
||||
extern void initCpuParameters();
|
||||
extern int8_t setCpuTemp(String command);
|
||||
extern int8_t setCpuUsage(String command);
|
||||
extern int8_t setRamMax(String command);
|
||||
extern int8_t setRamFree(String command);
|
||||
|
||||
extern int16_t cpuUsageGlobal;
|
||||
extern int16_t cpuUsage[8];
|
||||
extern int16_t cpuTempGlobal;
|
||||
extern int16_t cpuTemp[8];
|
||||
extern uint32_t ramMax;
|
||||
extern uint32_t ramFree;
|
||||
|
||||
#endif // __CPU_H__
|
19
datetimeHandler.cpp
Normal file
19
datetimeHandler.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include "datetimeHandler.h"
|
||||
|
||||
uint8_t localTemp = 255;
|
||||
uint8_t localHum = 255;
|
||||
uint8_t hour = 0;
|
||||
uint8_t minute = 0;
|
||||
uint8_t time_tab[6] = {'-', '-', ':', '-', '-', 0};
|
||||
|
||||
void setTime(String time)
|
||||
{
|
||||
if(time.length() == 8)
|
||||
{
|
||||
hour = time.substring(0,2).toInt();
|
||||
time.substring(0,5).getBytes(time_tab, 5+1);
|
||||
minute = time.substring(3,5).toInt();
|
||||
}
|
||||
}
|
||||
|
||||
|
13
datetimeHandler.h
Normal file
13
datetimeHandler.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef __DATETIMEHANDLER_H__
|
||||
#define __DATETIMEHANDLER_H__
|
||||
|
||||
#include<Arduino.h>
|
||||
|
||||
extern uint8_t localTemp;
|
||||
extern uint8_t localHum;
|
||||
extern uint8_t hour;
|
||||
extern uint8_t minute;
|
||||
extern uint8_t time_tab[6];
|
||||
extern void setTime(String time);
|
||||
|
||||
#endif // __DATETIMEHANDLER_H__
|
210
gfx_1.cpp
Normal file
210
gfx_1.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
#include "gfx_1.h"
|
||||
#include "datetimeHandler.h"
|
||||
#include "cpu.h"
|
||||
#include "Adafruit_GFX.h"
|
||||
#include <Adafruit_ILI9341.h>
|
||||
|
||||
bool gfx1_refresh = true;
|
||||
static uint8_t s_time_tab[6] = {'0', '0', ':', '0', '0', 0};
|
||||
static uint8_t s_localHum = 0, s_localTemp = 0, s_cpuTemp = 255;
|
||||
static int16_t s_cpu_usage = 255;
|
||||
static uint32_t s_ram_free = 255, s_ram_max = 255;
|
||||
|
||||
|
||||
// 5px size
|
||||
static void gfx_update_toolbar();
|
||||
static void gfx_update_cpu();
|
||||
static void gfx_update_mem();
|
||||
|
||||
static void writeArray(const char *buf)
|
||||
{
|
||||
uint8_t c= 0;
|
||||
while(buf[c] != 0)
|
||||
tft.write(buf[c++]);
|
||||
}
|
||||
|
||||
|
||||
void gfx1_udpate()
|
||||
{
|
||||
// if(!gfx1_refresh)
|
||||
// return ;
|
||||
|
||||
gfx1_refresh = false;
|
||||
gfx_update_toolbar();
|
||||
gfx_update_cpu();
|
||||
gfx_update_mem();
|
||||
}
|
||||
|
||||
#define LINE_Y_REL 29
|
||||
#define TEXT_Y_REL 9
|
||||
#define FIRST_TEXT_Y_REL 40
|
||||
#define TEXT_ESPACE_Y 35
|
||||
#define TEXT_ESPACE_SHORT_Y 25
|
||||
|
||||
char buf[20];
|
||||
|
||||
void gfx1_layout()
|
||||
{
|
||||
uint8_t c= 0;
|
||||
|
||||
tft.fillScreen(ILI9341_BLACK);
|
||||
tft.drawLine(10, 18, 310, 18, ILI9341_YELLOW);
|
||||
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
|
||||
tft.setCursor(35, 0);
|
||||
tft.setTextSize(1);
|
||||
tft.write('o');
|
||||
tft.setTextSize(2);
|
||||
tft.setCursor(35+8, 2);
|
||||
tft.write('C');
|
||||
//Humidity
|
||||
tft.setCursor(300, 2);
|
||||
tft.write('%');
|
||||
|
||||
// CPU rect
|
||||
tft.setTextSize(2);
|
||||
tft.drawRoundRect(5, 45, 150, 90, 10, ILI9341_DARKCYAN);
|
||||
tft.drawLine(5, 45+LINE_Y_REL, 154, 45+LINE_Y_REL, ILI9341_DARKCYAN);
|
||||
tft.setTextColor(ILI9341_DARKCYAN, ILI9341_BLACK);
|
||||
tft.setCursor(60, 45+TEXT_Y_REL);
|
||||
sprintf(buf, "CPU");
|
||||
writeArray(buf);
|
||||
tft.setCursor(15, 45+FIRST_TEXT_Y_REL);
|
||||
sprintf(buf, "Usage:");
|
||||
writeArray(buf);
|
||||
tft.setCursor(15, 45+FIRST_TEXT_Y_REL + TEXT_ESPACE_SHORT_Y);
|
||||
sprintf(buf, "Temp:");
|
||||
writeArray(buf);
|
||||
tft.setCursor(15, 45+FIRST_TEXT_Y_REL + TEXT_ESPACE_SHORT_Y *2);
|
||||
|
||||
// memory
|
||||
tft.drawRoundRect(165, 45, 150, 90, 10, ILI9341_GREEN);
|
||||
tft.drawLine(165, 45+LINE_Y_REL, 314, 45+LINE_Y_REL, ILI9341_GREEN);
|
||||
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
|
||||
tft.setCursor(205, 45+TEXT_Y_REL);
|
||||
sprintf(buf, "MEMORY");
|
||||
writeArray(buf);
|
||||
tft.setCursor(175, 45+FIRST_TEXT_Y_REL);
|
||||
sprintf(buf, "Max:");
|
||||
writeArray(buf);
|
||||
tft.setCursor(175, 45+FIRST_TEXT_Y_REL + TEXT_ESPACE_SHORT_Y);
|
||||
sprintf(buf, "Free:");
|
||||
writeArray(buf);
|
||||
|
||||
gfx1_refresh = true;
|
||||
gfx1_udpate();
|
||||
}
|
||||
|
||||
void get_formated_space(int32_t valueMb)
|
||||
{
|
||||
int8_t unity = 0;
|
||||
if(valueMb > 999)
|
||||
{
|
||||
valueMb = valueMb / 1024;
|
||||
unity = 1; // GB
|
||||
}
|
||||
|
||||
if(valueMb > 9999)
|
||||
{
|
||||
valueMb = valueMb / 1024;
|
||||
unity = 2; // TB
|
||||
}
|
||||
|
||||
if(unity == 0)
|
||||
sprintf(buf, "%4d MB", valueMb);
|
||||
else if(unity == 1)
|
||||
sprintf(buf, "%4d GB", valueMb);
|
||||
else
|
||||
sprintf(buf, "%4d TB", valueMb);
|
||||
}
|
||||
|
||||
static void gfx_update_mem()
|
||||
{
|
||||
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
|
||||
if(s_ram_max != ramMax)
|
||||
{
|
||||
tft.setCursor(175 + 50, 45+FIRST_TEXT_Y_REL);
|
||||
get_formated_space(ramMax);
|
||||
writeArray(buf);
|
||||
s_ram_free = ramMax;
|
||||
}
|
||||
|
||||
if(s_ram_free != ramFree)
|
||||
{
|
||||
tft.setCursor(175 + 50, 45+FIRST_TEXT_Y_REL + TEXT_ESPACE_SHORT_Y);
|
||||
get_formated_space(ramFree);
|
||||
writeArray(buf);
|
||||
s_ram_free = ramFree;
|
||||
}
|
||||
}
|
||||
|
||||
//s_cpu_usage = 0;
|
||||
static void gfx_update_cpu()
|
||||
{
|
||||
tft.setTextColor(ILI9341_DARKCYAN, ILI9341_BLACK);
|
||||
if(cpuUsageGlobal != s_cpu_usage)
|
||||
{
|
||||
tft.setCursor(15+75, 45+FIRST_TEXT_Y_REL);
|
||||
sprintf(buf, "%3d %%", cpuUsageGlobal);
|
||||
writeArray(buf);
|
||||
s_cpu_usage = cpuUsageGlobal;
|
||||
}
|
||||
if(s_cpuTemp != cpuTempGlobal)
|
||||
{
|
||||
tft.setCursor(15 + 75, 45+FIRST_TEXT_Y_REL + TEXT_ESPACE_SHORT_Y);
|
||||
sprintf(buf, "%3d ", cpuTempGlobal);
|
||||
writeArray(buf);
|
||||
tft.setCursor(15 + 115, 45+FIRST_TEXT_Y_REL + TEXT_ESPACE_SHORT_Y - 2);
|
||||
tft.setTextSize(1);
|
||||
tft.write('o');
|
||||
tft.setTextSize(2);
|
||||
tft.setCursor(15 + 115 +8, 45+FIRST_TEXT_Y_REL + TEXT_ESPACE_SHORT_Y);
|
||||
tft.write('C');
|
||||
s_cpuTemp = cpuTempGlobal;
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_update_toolbar()
|
||||
{
|
||||
uint8_t c= 0;
|
||||
char buf[5];
|
||||
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
|
||||
//time
|
||||
if(s_time_tab[4] != time_tab[4] || s_time_tab[3] != time_tab[3]
|
||||
|| s_time_tab[1] != time_tab[1] || s_time_tab[0] != time_tab[0])
|
||||
{
|
||||
tft.setTextSize(2);
|
||||
tft.setCursor(135, 2);
|
||||
|
||||
while(c < 5)
|
||||
{
|
||||
uint8_t car = time_tab[c];
|
||||
s_time_tab[c] = car;
|
||||
tft.write(car);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
//temp
|
||||
if(s_localTemp != localTemp)
|
||||
{
|
||||
tft.setCursor(10, 2);
|
||||
if(localTemp != 255)
|
||||
sprintf(buf, "%2d", localTemp);
|
||||
else
|
||||
sprintf(buf, "--");
|
||||
writeArray(buf);
|
||||
s_localTemp = localTemp;
|
||||
}
|
||||
|
||||
// humidity
|
||||
if(s_localHum != localHum)
|
||||
{
|
||||
tft.setCursor(275, 2);
|
||||
if(localHum != 255)
|
||||
sprintf(buf, "%2d", localHum);
|
||||
else
|
||||
sprintf(buf, "--");
|
||||
writeArray(buf);
|
||||
s_localHum = localHum;
|
||||
}
|
||||
}
|
14
gfx_1.h
Normal file
14
gfx_1.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef __GFX_1_H__
|
||||
#define __GFX_1_H__
|
||||
|
||||
#include "Adafruit_ILI9341.h"
|
||||
|
||||
extern Adafruit_ILI9341 tft;
|
||||
|
||||
extern void gfx1_udpate();
|
||||
extern void gfx1_layout();
|
||||
|
||||
extern bool gfx1_refresh;
|
||||
|
||||
|
||||
#endif
|
108
sysmon.ino
Normal file
108
sysmon.ino
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "Adafruit_GFX.h"
|
||||
#include "Adafruit_ILI9341.h"
|
||||
#include <XPT2046_Touchscreen.h>
|
||||
#include "DHT.h"
|
||||
#include "cpu.h"
|
||||
#include "datetimeHandler.h"
|
||||
#include "gfx_1.h"
|
||||
|
||||
#define TFT_DC D4
|
||||
#define TFT_CS D2
|
||||
#define TFT_RESET D3
|
||||
#define DHTPIN D8
|
||||
#define DHTTYPE DHT22
|
||||
|
||||
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
|
||||
DHT dht(DHTPIN, DHTTYPE);
|
||||
|
||||
static uint32_t tempTime = 0;
|
||||
static uint32_t rtcTime = 0;
|
||||
static uint32_t displayTime = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
initHardware();
|
||||
gfx1_layout();
|
||||
}
|
||||
|
||||
void update(String command) {
|
||||
int delimiterIndex = command.indexOf('=');
|
||||
// Serial.println(command);
|
||||
if (delimiterIndex != -1) {
|
||||
String key = command.substring(0, delimiterIndex);
|
||||
String value = command.substring(delimiterIndex + 1);
|
||||
Serial.print(key);
|
||||
|
||||
// Check the key and assign the corresponding value
|
||||
if (key.equals("CpuTemp")) {
|
||||
setCpuTemp(value);
|
||||
Serial.print("Received CPU temperature: ");
|
||||
Serial.println(value);
|
||||
// gfx1_udpate();
|
||||
} else if (key.equals("CpuUsage")) {
|
||||
setCpuUsage(value);
|
||||
Serial.print("Received CPU usage: ");
|
||||
Serial.println(value);
|
||||
// gfx1_udpate();
|
||||
} else if (key.equals("RamFree")) {
|
||||
setRamFree(value);
|
||||
Serial.print("Received Ram free: ");
|
||||
Serial.println(value);
|
||||
// gfx1_udpate();
|
||||
} else if (key.equals("RamMax")) {
|
||||
setRamMax(value);
|
||||
Serial.print("Received Ram max: ");
|
||||
Serial.println(value);
|
||||
// gfx1_udpate();
|
||||
} else if (key.equals("Time")) {
|
||||
setTime(value);
|
||||
Serial.print("Received Time: ");
|
||||
Serial.println(value);
|
||||
// gfx1_udpate();
|
||||
}
|
||||
}
|
||||
gfx1_refresh = true;
|
||||
gfx1_udpate();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.println("Enter data:");
|
||||
// while (Serial.available() == 0) {}
|
||||
String command = Serial.readString();
|
||||
command.trim();
|
||||
Serial.println(command);
|
||||
|
||||
if(!isnan(dht.readTemperature()))
|
||||
{
|
||||
localHum = dht.readHumidity();
|
||||
localTemp = dht.readTemperature() - 4;
|
||||
Serial.println(localTemp);
|
||||
gfx1_refresh = true;
|
||||
gfx1_udpate();
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// localHum = 255;
|
||||
// localTemp = 255;
|
||||
// }
|
||||
|
||||
update(command);
|
||||
// delay(1000);
|
||||
|
||||
// if ( currentTime > displayTime ) {
|
||||
// displayTime = currentTime + 100000;
|
||||
// }
|
||||
}
|
||||
|
||||
void initHardware()
|
||||
{
|
||||
pinMode(TFT_RESET, OUTPUT);
|
||||
digitalWrite(TFT_RESET, LOW);
|
||||
delay(1000);
|
||||
digitalWrite(TFT_RESET, HIGH);
|
||||
delay(1000);
|
||||
tft.begin();
|
||||
tft.setRotation(3);
|
||||
dht.begin();
|
||||
// delay(3000);
|
||||
}
|
99
sysmon.py
Normal file
99
sysmon.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
import psutil
|
||||
import serial
|
||||
from gettext import c2py
|
||||
from time import sleep
|
||||
import sensors
|
||||
import subprocess
|
||||
import math
|
||||
import pyowm
|
||||
import os
|
||||
|
||||
CPU_TEMP_PATH = '/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon2/temp1_input'
|
||||
|
||||
file_descriptor = '/dev/ttyUSB0'
|
||||
baud_rate = 9600
|
||||
|
||||
arduino = serial.Serial(port=file_descriptor, baudrate=baud_rate)
|
||||
sleep(6)
|
||||
|
||||
def send_command(command):
|
||||
print("sent: " + command)
|
||||
arduino.write(command.encode())
|
||||
sleep(0.1)
|
||||
|
||||
def set_time(date_time):
|
||||
request = '\nTime=%s\r\n' % date_time.strftime('%H:%M:%S')
|
||||
send_command(request)
|
||||
|
||||
|
||||
def set_max():
|
||||
ram_max = int(psutil.virtual_memory().total / (1024.*1024.))
|
||||
request = 'RamMax=%d\r\n' % ram_max
|
||||
send_command(request)
|
||||
|
||||
def set_free():
|
||||
ram_free = int(psutil.virtual_memory().free / (1024.*1024.))
|
||||
request = 'RamFree=%d\r\n' % ram_free
|
||||
send_command(request)
|
||||
|
||||
def set_system_info():
|
||||
with open('/etc/os-release', 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith('NAME='):
|
||||
OSName = line.split('"')[1]
|
||||
break
|
||||
request = 'OS=%s\r\n' % OSName
|
||||
send_command(request)
|
||||
sleep(1)
|
||||
|
||||
with open('/proc/version', 'r') as f:
|
||||
for line in f:
|
||||
Kernel = line.split(' ')[2].split('-')[0]
|
||||
break
|
||||
request = 'Kernel=%s\r\n' % Kernel
|
||||
send_command(request)
|
||||
sleep(1)
|
||||
|
||||
def set_uptime():
|
||||
uptime_seconds = psutil.boot_time()
|
||||
uptime = datetime.now() - datetime.fromtimestamp(uptime_seconds)
|
||||
uptime_hours = int(uptime.total_seconds() // 3600)
|
||||
uptime_minutes = int((uptime.total_seconds() % 3600) // 60)
|
||||
uptime = f"{uptime_hours:02d}:{uptime_minutes:02d}"
|
||||
request = 'Uptime=%s\r\n' % uptime
|
||||
send_command(request)
|
||||
|
||||
def start(tty_serial):
|
||||
|
||||
set_system_info()
|
||||
while 1:
|
||||
set_uptime()
|
||||
sleep(1)
|
||||
cpu_temp = int(subprocess.check_output(['cat', CPU_TEMP_PATH]))/1000
|
||||
requests = "\nCpuTemp="+str(math.trunc(cpu_temp))
|
||||
send_command(requests)
|
||||
sleep(1)
|
||||
cpu_pct = psutil.cpu_percent(interval=None, percpu=False)
|
||||
cpu_global = int(cpu_pct)
|
||||
request = "\nCpuUsage=" + str(math.trunc(cpu_global))
|
||||
send_command(request)
|
||||
sleep(1)
|
||||
set_time(datetime.now())
|
||||
sleep(1)
|
||||
set_max()
|
||||
sleep(1)
|
||||
set_free()
|
||||
sleep(1)
|
||||
|
||||
|
||||
def main():
|
||||
start('/dev/ttyUSB0')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in a new issue