first commit

This commit is contained in:
2025-01-10 15:20:33 +08:00
commit 4f5d2aa650
66 changed files with 15921 additions and 0 deletions

5
ESP01-IMAS/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
ESP01-IMAS/.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

39
ESP01-IMAS/include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
ESP01-IMAS/lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

15
ESP01-IMAS/platformio.ini Normal file
View File

@ -0,0 +1,15 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp12e]
platform = espressif8266
board = esp12e
framework = arduino
lib_deps = bblanchon/ArduinoJson@^7.2.1

124
ESP01-IMAS/src/main.cpp Normal file
View File

@ -0,0 +1,124 @@
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
// Wi-Fi 连接信息
const char *ssid = "Xiaomi_3A40";
const char *password = "112233ww";
// 服务器信息
const char *serverIP = "192.168.31.184"; // 服务器 IP 地址
const int serverPort = 80; // 端口号
const char *requestPath = "/ESP01/getData.php"; // 请求路径
#define Sleep_Pin 2
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid, password);
// 连接到 Wi-Fi
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.print(".");
}
Serial.println("\nWi-Fi connected!");
pinMode(Sleep_Pin, OUTPUT);
digitalWrite(Sleep_Pin, LOW);
}
void loop()
{
// 确保 Wi-Fi 连接正常
if (WiFi.status() != WL_CONNECTED)
{
Serial.println("Wi-Fi disconnected, reconnecting...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.print(".");
}
Serial.println("\nReconnected to Wi-Fi!");
}
// 创建客户端
WiFiClient client;
if (client.connect(serverIP, serverPort))
{
Serial.println("Connected to server");
// 发送 GET 请求
client.println(String("GET ") + requestPath + " HTTP/1.1");
client.println(String("Host: ") + serverIP);
client.println("Connection: close");
client.println();
// 等待响应
while (client.connected() || client.available())
{
if (client.available())
{
String line = client.readStringUntil('\n');
if (line == "\r")
{
break; // 头部结束
}
}
}
// 读取 JSON 数据
String jsonData;
while (client.available())
{
jsonData += client.readString();
}
// 打印获取到的 JSON 数据
Serial.println("Received JSON:");
Serial.println(jsonData);
// 解析 JSON 数据
StaticJsonDocument<512> doc;
DeserializationError error = deserializeJson(doc, jsonData);
if (error)
{
Serial.print("Failed to parse JSON: ");
Serial.println(error.c_str());
return;
}
// 提取 JSON 数据
if (doc.containsKey("standby"))
{
String standby = doc["standby"];
Serial.print("Standby mode: ");
Serial.println(standby);
if (standby == "1")
{
Serial.println("Standby mode");
digitalWrite(Sleep_Pin, HIGH); // 打开休眠模式
}
else
{
Serial.println("Normal mode");
digitalWrite(Sleep_Pin, LOW); // 关闭休眠模式
}
}
else
{
Serial.println("Key 'standby' not found in JSON data");
}
}
else
{
Serial.println("Failed to connect to server");
}
// 延时一段时间再发送下一次请求
delay(100);
}

11
ESP01-IMAS/test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html

5
STM32-IMAS/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
STM32-IMAS/.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

39
STM32-IMAS/include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@ -0,0 +1,69 @@
#define __HEIGHT 64
#define __WIDTH 64
// array size is 40000
unsigned char cloudy_icon[__HEIGHT * __WIDTH] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x92, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x1f, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7b, 0x9b, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x7b, 0x7b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x97, 0xbf, 0x00, 0x00, 0x00, 0x92, 0x7b, 0x7b, 0x7b, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x97, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x7b, 0x7b, 0x97, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x93, 0x92, 0xff, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0xff, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xbf, 0x77, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9b, 0x1f, 0x00, 0xff, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x9f, 0x57, 0x97, 0xbf, 0xbf, 0xbf, 0x56, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x57, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x92, 0x92, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x1f, 0x00, 0xb7, 0x97, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x57, 0x00, 0x00, 0x00, 0x1f, 0x97, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0xbf, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x9b, 0x9b, 0x00, 0xff, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xbf, 0x9b, 0x7b, 0x7b, 0x7b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x93, 0x00, 0x1f, 0x9b, 0x9f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x9f, 0x97, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x93, 0x9b, 0x7b, 0x9b, 0x9b, 0x9f, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x9b, 0x9b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x77, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x9b, 0x7b, 0x97, 0x97, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x57, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x9b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x57, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x77, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x9f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x57, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x9b, 0x7b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x7b, 0x9b, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x9b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x7b, 0x9b, 0x9b, 0x9b, 0x7b, 0x7b, 0x9b, 0x7b, 0x7b, 0x7b, 0x9b, 0x9b, 0x9b, 0x7b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x7b, 0x9b, 0x9b, 0x7b, 0x7b, 0x9b, 0x7b, 0x9b, 0x9b, 0x7b, 0x7b, 0x7b, 0x7b, 0x96, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x9f, 0x57, 0x56, 0x56, 0x57, 0x57, 0x57, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x96, 0xbf, 0x57, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

46
STM32-IMAS/lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

23
STM32-IMAS/platformio.ini Normal file
View File

@ -0,0 +1,23 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:genericSTM32F103RC]
platform = ststm32
board = genericSTM32F103RC
framework = arduino
upload_protocol = serial
upload_speed = 500000
lib_deps =
adafruit/Adafruit Unified Sensor@^1.1.14
adafruit/DHT sensor library@^1.4.6
bodmer/TFT_eSPI@^2.5.43
bblanchon/ArduinoJson@^7.2.1
adafruit/Adafruit GFX Library@^1.11.11
adafruit/Adafruit SSD1306@^2.5.13

340
STM32-IMAS/src/main.cpp Normal file
View File

@ -0,0 +1,340 @@
/*
An example digital clock using a TFT LCD screen to show the time.
Demonstrates use of the font printing routines. (Time updates but date does not.)
It uses the time of compile/upload to set the time
For a more accurate clock, it would be better to use the RTClib library.
But this is just a demo...
Make sure all the display driver and pin connections are correct by
editing the User_Setup.h file in the TFT_eSPI library folder.
#########################################################################
###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
#########################################################################
Based on clock sketch by Gilchrist 6/2/2014 1.0
A few colour codes:
code color
0x0000 Black
0xFFFF White
0xBDF7 Light Gray
0x7BEF Dark Gray
0xF800 Red
0xFFE0 Yellow
0xFBE0 Orange
0x79E0 Brown
0x7E0 Green
0x7FF Cyan
0x1F Blue
0xF81F Pink
*/
/******************************/
// #define TFT_CS PB12
// #define TFT_RST PB10
// #define TFT_DC PB1
// #define TFT_MOSI PA7
// #define TFT_SCLK PA5
// #define TFT_MISO PA6
// #define TOUCH_CS PB15
#include <Arduino.h>
#include <TFT_eSPI.h> // TFT 库
#include <SPI.h> // SPI 库
#include "DHT.h"
#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#include "weather_icon.h"
#include "stm32f1xx_hal.h"
#include "ArduinoJson.h"
#define DHTPIN PA1
#define DHTTYPE DHT11 // DHT 11
#define MAX_IMAGE_WIDTH 200 // Adjust for your images
// 定义OLED显示屏的尺寸
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
DHT dht(DHTPIN, DHTTYPE);
TFT_eSPI tft = TFT_eSPI(); // 创建 TFT 对象
HardwareSerial serial1(PA10, PA9); // RX, TX
HardwareSerial serial2(PA3, PA2); // RX, TX
char receivedData0[100]; // 用于存储接收到的数据
// char receivedData[100]; // 用于存储接收到的数据
String receivedData; // 用于存储接收到的数据
int dataIndex = 0; // 数据接收指针
int braceCount = 0; // 用于跟踪大括号的数量
String jsonBuffer = ""; // 用于存储接收的 JSON 数据
bool isJsonComplete = false; // 标记 JSON 是否完整
String humidityStr = "";
String temperatureStr = "";
String fahrenheitStr = "";
String data = "";
enum weather{
SUNNY = 1,
CLOUDY,
RAINY,
SNOWY,
WINDY,
FOG,
UNKNOWN
};
// PNG png; // PNG decoder instance
// int16_t xpos = 100;
// int16_t ypos = 100;
// void pngDraw(PNGDRAW *pDraw);
void displayData(const char *data); // 显示接收到的数据
void displayLocalData(String data);
// void pngDraw(PNGDRAW *pDraw);
void serialEvent1();
void parseJson();
void setup()
{
// 初始化I²C
Wire.begin();
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
{
Serial.println(F("SSD1306 allocation failed"));
for (;;)
; // Don't proceed, loop forever
}
// 初始化 TFT 屏幕
tft.init();
tft.setRotation(2); // 设置屏幕方向
tft.fillScreen(TFT_WHITE); // 清屏
dht.begin(); // 初始化 DHT 传感器
serial1.begin(115200);
serial2.begin(115200);
}
void loop()
{
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f))
{
Serial.println(F("Failed to read from DHT sensor!"));
display.clearDisplay(); // 清屏
display.setCursor(0, 0);
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setTextSize(2); // Normal 1:1 pixel scale
display.println(F("Failed to read from DHT sensor!"));
return;
}
// serialEvent(); // 检查串口数据
humidityStr = String(h,2);
temperatureStr = String(t,2);
fahrenheitStr = String(f,2);
serial1.print("Humidity: ");
serial1.print(humidityStr);
serial1.print("%\n");
serial1.print("Temperature: ");
serial1.print(temperatureStr);
serial1.print("C\n");
serial2.print("Humidity: ");
serial2.print(humidityStr);
serial2.print("%\n");
serial2.print("Temperature: ");
serial2.print(temperatureStr);
serial2.print("C\n");
data = "Humidity: " + humidityStr + "%\n" + "Temperature: " + temperatureStr + "C\n" + "Fahrenheit: " + fahrenheitStr + "F\n";
serial1.print(data); // 打印接收到的数据
display.clearDisplay(); // Clear display
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.print(F("Temperature: "));
display.print(temperatureStr);
display.println(F("C"));
display.display();
// displayLocalData(data); // 显示接收到的数据
// serialEvent1(); // 检查串口数据
}
void serialEvent(){
// 检查是否有数据传入
if (serial2.available())
{
// 从串口读取一个字符
char incomingByte = serial2.read();
serial1.print(incomingByte); // 打印接收到的字符
// 如果接收到换行符或最大长度限制,则显示数据
if (incomingByte == '\n' || dataIndex >= 100)
{
receivedData0[dataIndex] = '\0'; // 结束字符串
displayData(receivedData0); // 显示数据
dataIndex = 0; // 重置接收指针
}
else
{
receivedData0[dataIndex++] = incomingByte; // 将字符存入缓冲区
}
}
// int16_t rc = png.openFLASH((uint8_t *)cloudy_icon, sizeof(cloudy_icon), pngDraw);
// if (rc == PNG_SUCCESS)
// {
// Serial.printf("image specs: (%d x %d), %d bpp, pixel type: %d\n", png.getWidth(), png.getHeight(), png.getBpp(), png.getPixelType());
// tft.startWrite();
// uint32_t dt = millis();
// rc = png.decode(NULL, 0);
// Serial.print(millis() - dt);
// Serial.println("ms");
// tft.endWrite();
// // png.close(); // not needed for memory->memory decode
// }
}
void displayData(const char *data)
{
// 清除屏幕内容
tft.fillScreen(TFT_BLACK);
// 在屏幕上显示接收到的数据
tft.setCursor(10, 10); // 设置光标位置
tft.setTextSize(2); // 设置文本大小
tft.setTextColor(TFT_YELLOW, TFT_BLACK); // 设置文本颜色
tft.println("Received Data: ");
tft.setCursor(10, 26); // 设置光标位置
tft.setTextColor(TFT_WHITE, TFT_BLACK); // 设置文本颜色
tft.setTextSize(3); // 设置文本大小
tft.println(data); // 显示接收到的数据
// tft.drawRect(10, 26, 300, 100, TFT_BLACK); // 绘制矩形框
delay(1000); // 延时 5 秒
}
void displayLocalData(String data)
{
tft.setFreeFont(NULL); // 选择默认字体
// 在屏幕上显示接收到的数据
tft.setTextColor(TFT_RED, TFT_WHITE); // 设置文本颜色
// tft.drawRect(10, 26, 300, 100, TFT_WHITE); // 绘制矩形框
tft.setCursor(10, 0, 1); // 设置光标位置
tft.setTextSize(2); // 设置文本大小
tft.println(data); //
delay(1000); // 延时 5 秒
}
// void pngDraw(PNGDRAW *pDraw)
// {
// uint16_t lineBuffer[MAX_IMAGE_WIDTH];
// png.getLineAsRGB565(pDraw, lineBuffer, PNG_RGB565_BIG_ENDIAN, 0xffffffff);
// tft.pushImage(xpos, ypos + pDraw->y, pDraw->iWidth, 1, lineBuffer);
// }
// void serialEvent1()
// {
// while (serial2.available() > 0)
// {
// char c = serial2.read(); // 读取单个字符
// jsonBuffer += c; // 拼接到缓冲区
// // 读取串口数据
// if (c == '{')
// {
// braceCount++;
// }
// if (c == '}')
// {
// braceCount--;
// }
// if (braceCount == 0)
// {
// isJsonComplete = true;
// }
// }
// if (isJsonComplete)
// {
// serial1.println("Received complete JSON:");
// serial1.println(jsonBuffer);
// parseJson();
// // 处理完 JSON 数据后,清空缓冲区
// jsonBuffer = "";
// isJsonComplete = false;
// }
// }
// void parseJson()
// {
// StaticJsonDocument<512> doc; // 根据你的JSON数据大小调整这个值
// DeserializationError error = deserializeJson(doc, jsonBuffer);
// if (error)
// {
// // 如果解析失败,打印错误信息
// serial1.printf("deserializeJson() failed: %s\n", error.c_str());
// return;
// }
// // 解析成功后你可以通过doc来访问JSON中的数据
// const char *temperature = doc["lives"][0]["temperature"];
// const char *humidity = doc["lives"][0]["humidity"];
// const char *weather = doc["lives"][0]["weather"];
// const char *city = doc["lives"][0]["city"];
// // 根据你的JSON结构添加更多的键
// serial1.printf("temperature: %s\n", temperature);
// serial1.printf("humidity: %s\n", humidity);
// serial1.printf("weather: %s\n", weather);
// serial1.printf("city: %s\n", city);
// serial1.println();
// // 处理其他键的数据
// // 你可以在这里将解析得到的数据发送到TFT屏幕或其他处理
// tft.setCursor(10, 100, 2);
// tft.setTextColor(TFT_BLACK, TFT_WHITE); // 设置文本颜色
// tft.setTextSize(1); // 设置文本大小
// tft.println("city:" + String(city)); // 显示城市名称
// tft.setCursor(10, 120, 2);
// tft.println("Temperature: " + String(temperature) + "C");
// tft.setCursor(10, 136, 2);
// tft.println("Humidity: " + String(humidity) + "%");
// tft.setCursor(10, 152, 2);
// tft.println("Weather: " + String(weather));
// }

11
STM32-IMAS/test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html

5
TFT-ESP32/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
TFT-ESP32/.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

BIN
TFT-ESP32/data/san28.bin Normal file

Binary file not shown.

39
TFT-ESP32/include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
TFT-ESP32/lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

42
TFT-ESP32/platformio.ini Normal file
View File

@ -0,0 +1,42 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
bodmer/TFT_eSPI@^2.5.43
bblanchon/ArduinoJson@^7.2.1
bodmer/JPEGDecoder@^2.0.0
build_flags =
-Os
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-DUSER_SETUP_LOADED=1
-DTFT_INVERSION_ON=1
-DILI9341_DRIVER=1
-DTFT_WIDTH=320
-DTFT_HEIGHT=240
-DTFT_MISO=19
-DTFT_MOSI=23
-DTFT_SCLK=18
-DTFT_CS=15
-DTFT_DC=2
-DTFT_RST=4
-DTOUCH_CS=33
-DLOAD_GLCD=1
-DLOAD_FONT2=1
-DLOAD_FONT4=1
-DLOAD_FONT6=1
-DLOAD_FONT7=1
-DLOAD_FONT8=1
-DLOAD_GFXFF=1
-DSMOOTH_FONT=1
-DSPI_FREQUENCY=27000000

768
TFT-ESP32/src/main.cpp Normal file
View File

@ -0,0 +1,768 @@
// Font file is stored on SD card
#include <SD.h>
#include <HardwareSerial.h>
// Graphics and font library
#include <TFT_eSPI.h>
#include <SPI.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <esp_sleep.h>
#include <JPEGDecoder.h>
#define SD_CS 22 // Set GPIO 5 as chip select for SD card
#define LED_PIN 14 // Set GPIO 14 as LED output
#define HUMIDIFIER_PIN 13 // Set GPIO 13 as humidifier output
// TX (发送)GPIO16UART2_TXD
// RX (接收)GPIO17UART2_RXD
#define MAX_IMAGE_WIDTH 240
int16_t xpos = 0;
int16_t ypos = 0;
const char *ssid = "Xiaomi_3A40";
const char *password = "112233ww";
const char *jsonUrl = "http://monjack.cn/weatherInfo.php";
const char *postUrl = "http://192.168.131.51/postLocalData.php";
const char *postStatusUrl = "http://192.168.131.51/postStatus.php";
int dataIndex = 0;
char receivedData0[100]; // 用于存储接收到的数据
HardwareSerial serial2(2); // UART1 实例化
float local_humidity = 0.0;
float temp_local_humidity = 0.0;
float local_temperature = 0.0;
float temp_local_temperature = 0.0;
u8_t standby = 0;
u8_t reboot = 0;
u8_t humidifier = 1;
u8_t screen = 1;
bool boot = true;
String weather = "";
String temp_weather = "";
String temperature = "25";
String temp_temperature = "";
String humidity = "60";
String temp_humidity = "";
String wind_direction = "东北";
String temp_wind_direction = "";
String comfort_clothing = "穿短裙、短裤、短袖、短外套";
SemaphoreHandle_t xMutex;
TFT_eSPI tft = TFT_eSPI(); // Invoke library
void showTime(uint32_t msTime)
{
// tft.setCursor(0, 0);
// tft.setTextFont(1);
// tft.setTextSize(2);
// tft.setTextColor(TFT_WHITE, TFT_BLACK);
// tft.print(F(" JPEG drawn in "));
// tft.print(msTime);
// tft.println(F(" ms "));
Serial.print(F(" JPEG drawn in "));
Serial.print(msTime);
Serial.println(F(" ms "));
}
// ####################################################################################################
// Draw a JPEG on the TFT, images will be cropped on the right/bottom sides if they do not fit
// ####################################################################################################
// This function assumes xpos,ypos is a valid screen coordinate. For convenience images that do not
// fit totally on the screen are cropped to the nearest MCU size and may leave right/bottom borders.
void jpegRender(int xpos, int ypos)
{
// jpegInfo(); // Print information from the JPEG file (could comment this line out)
uint16_t *pImg;
uint16_t mcu_w = JpegDec.MCUWidth;
uint16_t mcu_h = JpegDec.MCUHeight;
uint32_t max_x = JpegDec.width;
uint32_t max_y = JpegDec.height;
bool swapBytes = tft.getSwapBytes();
tft.setSwapBytes(true);
// Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
// Typically these MCUs are 16x16 pixel blocks
// Determine the width and height of the right and bottom edge image blocks
uint32_t min_w = jpg_min(mcu_w, max_x % mcu_w);
uint32_t min_h = jpg_min(mcu_h, max_y % mcu_h);
// save the current image block size
uint32_t win_w = mcu_w;
uint32_t win_h = mcu_h;
// record the current time so we can measure how long it takes to draw an image
uint32_t drawTime = millis();
// save the coordinate of the right and bottom edges to assist image cropping
// to the screen size
max_x += xpos;
max_y += ypos;
// Fetch data from the file, decode and display
while (JpegDec.read())
{ // While there is more data in the file
pImg = JpegDec.pImage; // Decode a MCU (Minimum Coding Unit, typically a 8x8 or 16x16 pixel block)
// Calculate coordinates of top left corner of current MCU
int mcu_x = JpegDec.MCUx * mcu_w + xpos;
int mcu_y = JpegDec.MCUy * mcu_h + ypos;
// check if the image block size needs to be changed for the right edge
if (mcu_x + mcu_w <= max_x)
win_w = mcu_w;
else
win_w = min_w;
// check if the image block size needs to be changed for the bottom edge
if (mcu_y + mcu_h <= max_y)
win_h = mcu_h;
else
win_h = min_h;
// copy pixels into a contiguous block
if (win_w != mcu_w)
{
uint16_t *cImg;
int p = 0;
cImg = pImg + win_w;
for (int h = 1; h < win_h; h++)
{
p += mcu_w;
for (int w = 0; w < win_w; w++)
{
*cImg = *(pImg + w + p);
cImg++;
}
}
}
// calculate how many pixels must be drawn
uint32_t mcu_pixels = win_w * win_h;
// draw image MCU block only if it will fit on the screen
if ((mcu_x + win_w) <= tft.width() && (mcu_y + win_h) <= tft.height())
tft.pushImage(mcu_x, mcu_y, win_w, win_h, pImg);
else if ((mcu_y + win_h) >= tft.height())
JpegDec.abort(); // Image has run off bottom of screen so abort decoding
}
tft.setSwapBytes(swapBytes);
showTime(millis() - drawTime); // These lines are for sketch testing only
}
// ####################################################################################################
// Print image information to the serial port (optional)
// ####################################################################################################
// JpegDec.decodeFile(...) or JpegDec.decodeArray(...) must be called before this info is available!
void jpegInfo()
{
// Print information extracted from the JPEG file
Serial.println("JPEG image info");
Serial.println("===============");
Serial.print("Width :");
Serial.println(JpegDec.width);
Serial.print("Height :");
Serial.println(JpegDec.height);
Serial.print("Components :");
Serial.println(JpegDec.comps);
Serial.print("MCU / row :");
Serial.println(JpegDec.MCUSPerRow);
Serial.print("MCU / col :");
Serial.println(JpegDec.MCUSPerCol);
Serial.print("Scan type :");
Serial.println(JpegDec.scanType);
Serial.print("MCU width :");
Serial.println(JpegDec.MCUWidth);
Serial.print("MCU height :");
Serial.println(JpegDec.MCUHeight);
Serial.println("===============");
Serial.println("");
}
// ####################################################################################################
// Show the execution time (optional)
// ####################################################################################################
// WARNING: for UNO/AVR legacy reasons printing text to the screen with the Mega might not work for
// sketch sizes greater than ~70KBytes because 16-bit address pointers are used in some libraries.
// The Due will work fine with the HX8357_Due library.
void listDir(fs::FS &fs, const char *dirname, uint8_t levels);
void serialEvent();
void ParseData(char *data);
void displayTask(void *parameter);
void fetchDataTask(void *parameters);
void parseJson(String jsonData);
void getWeatherInfo();
void postData();
void postStatus();
void parseJson2(String jsonData);
void checkStatusTask(void *parameters);
void drawSdJpeg(const char *filename, int xpos, int ypos);
// -------------------------------------------------------------------------
// Setup
// -------------------------------------------------------------------------
void setup(void)
{
Serial.begin(115200); // Used for messages
serial2.begin(115200); // Used for messages
Serial.println("UART2 initialized");
// Connect to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// 设置SPI频率为40MHz
SPISettings spiSettings(40000000, MSBFIRST, SPI_MODE0);
// Initialise the SD library before the TFT so the chip select is defined
if (!SD.begin(SD_CS))
{
Serial.println("Card Mount Failed");
return;
}
// Initialise the TFT after the SD card!
tft.init();
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
listDir(SD, "/", 0);
pinMode(LED_PIN, OUTPUT); // Set LED pin as output
pinMode(HUMIDIFIER_PIN, OUTPUT); // Set humidifier pin as output
digitalWrite(LED_PIN, HIGH); // Turn on LED
digitalWrite(HUMIDIFIER_PIN, HIGH); // Turn on humidifier
Serial.println("SD and TFT initialisation done.");
Serial.println("👌👌👌👌");
postStatus();
int x = 0;
int y = 0;
drawSdJpeg("/Photos/background.jpg", x, y); // This draws a jpeg pulled off the SD Card
// 配置 GPIO 触发唤醒
esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0); // GPIO_NUM_35 为低电平唤醒
// 创建互斥锁
xMutex = xSemaphoreCreateMutex();
// 创建任务
xTaskCreate(displayTask, "Display Task", 4096, NULL, 1, NULL);
xTaskCreate(fetchDataTask, "Fetch Data Task", 4096, NULL, 2, NULL);
xTaskCreate(checkStatusTask, "Check Status Task", 4096, NULL, 3, NULL);
}
// -------------------------------------------------------------------------
// Main loop
// -------------------------------------------------------------------------
void loop()
{
}
void fetchDataTask(void *parameters){
while (true)
{
getWeatherInfo();
postData();
vTaskDelay(500 / portTICK_PERIOD_MS); // 每0.5秒获取一次JSON数据
}
}
void getWeatherInfo(){
if (WiFi.status() == WL_CONNECTED)
{
HTTPClient http;
// 配置HTTP请求
http.begin(jsonUrl);
// 发送HTTP GET请求
int httpCode = http.GET();
if (httpCode > 0)
{
// 如果请求成功
if (httpCode == HTTP_CODE_OK)
{
String payload = http.getString(); // 获取响应字符串
Serial.println("Received JSON data:");
Serial.println(payload);
// 解析JSON数据
parseJson(payload);
}
}
else
{
// 如果请求失败
Serial.print("Error on sending GET: ");
Serial.println(http.errorToString(httpCode).c_str());
}
http.end(); // 结束HTTP请求
}
else
{
Serial.println("Error in WiFi connection");
}
}
void postStatus()
{
if (WiFi.status() == WL_CONNECTED)
{
HTTPClient http;
// 配置HTTP请求
http.begin(postStatusUrl);
// 设置HTTP头部
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<100> doc;
doc["standby"] = standby;
doc["reboot"] = reboot;
doc["humidifier"] = humidifier;
doc["screen"] = screen;
// 序列化JSON数据
String jsonPayload;
serializeJson(doc, jsonPayload);
Serial.print("JSON Payload: ");
Serial.println(jsonPayload);
// 发送HTTP POST请求
int httpCode = http.POST(jsonPayload);
if (httpCode > 0)
{
// 如果请求成功
if (httpCode == HTTP_CODE_OK)
{
String payload = http.getString(); // 获取响应字符串
Serial.println("poststatus状态信息");
Serial.println(payload);
// 解析JSON数据
parseJson2(payload);
}
else
{
Serial.print("Unexpected HTTP code: ");
Serial.println(httpCode);
}
}
else
{
// 如果请求失败
Serial.print("Error on sending POST: ");
Serial.println(http.errorToString(httpCode).c_str());
}
http.end(); // 结束HTTP请求
}
else
{
Serial.println("WiFi is not connected.");
}
}
void postData()
{
if (WiFi.status() == WL_CONNECTED)
{
HTTPClient http;
// 配置HTTP请求
http.begin(postUrl);
// 设置HTTP头部
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<200> doc;
doc["Humidity"] = local_humidity;
doc["Temperature"] = local_temperature;
// 序列化JSON数据
String jsonPayload;
serializeJson(doc, jsonPayload);
Serial.print("JSON Payload: ");
Serial.println(jsonPayload);
// 发送HTTP POST请求
int httpCode = http.POST(jsonPayload);
if (httpCode > 0)
{
// 如果请求成功
if (httpCode == HTTP_CODE_OK)
{
String payload = http.getString(); // 获取响应字符串
Serial.println("状态信息:");
Serial.println(payload);
// 解析JSON数据
parseJson2(payload);
}
}
else
{
// 如果请求失败
Serial.print("Error on sending POST: ");
Serial.println(http.errorToString(httpCode).c_str());
}
http.end(); // 结束HTTP请求
}
else
{
Serial.println("Error in WiFi connection");
}
}
//解析天气情况
void parseJson(String jsonData){
// 定义JSON文档的大小根据实际情况调整
const size_t capacity = JSON_OBJECT_SIZE(2) + 300;
StaticJsonDocument<capacity> doc;
// 解析JSON数据
DeserializationError error = deserializeJson(doc, jsonData);
if (error)
{
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
return;
}
// 获取JSON中的值
String newHumidity = doc["lives"][0]["humidity"] | "0.0";
String newTemperature = doc["lives"][0]["temperature"] | "0.0";
String newWeather = doc["lives"][0]["weather"] | "";
String newWindDirection = doc["lives"][0]["winddirection"] | "东北";
if(newTemperature.toInt()<4){
comfort_clothing = "棉衣或羽绒服";
}else if(newTemperature.toInt()<10){
comfort_clothing = "厚外套";
}else if(newTemperature.toInt()<20){
comfort_clothing = "薄外套、长袖";
}else{
comfort_clothing = "短外套、短裤、短裙";
}
Serial.print("newHumidity: ");
Serial.println(newHumidity);
Serial.print("newTemperature: ");
Serial.println(newTemperature);
Serial.print("Weather: ");
Serial.println(newWeather);
Serial.print("WindDirection: ");
Serial.println(newWindDirection);
// 获取互斥锁
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE)
{
humidity = newHumidity;
temperature = newTemperature;
weather = newWeather;
wind_direction = newWindDirection;
// 释放互斥锁
xSemaphoreGive(xMutex);
}
}
//解析状态信息
void parseJson2(String jsonData){
// 定义JSON文档的大小根据实际情况调整
const size_t capacity = JSON_OBJECT_SIZE(2) + 300;
StaticJsonDocument<capacity> doc;
// 解析JSON数据
DeserializationError error = deserializeJson(doc, jsonData);
if (error)
{
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
return;
}
// 获取JSON中的值
u8_t newStandby = doc["standby"].as<u8_t>();
u8_t newReboot = doc["reboot"].as<u8_t>();
u8_t newHumidifier = doc["humidifier"].as<u8_t>();
u8_t newScreen = doc["screen"].as<u8_t>();
Serial.print("😊😊screen::😊😊");
Serial.println(newScreen);
Serial.print("😊😊standby::😊😊");
Serial.println(newStandby);
Serial.print("😊😊reboot::😊😊");
Serial.println(newReboot);
Serial.print("😊😊humidifier::😊😊");
Serial.println(newHumidifier);
// 获取互斥锁
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE)
{
standby = newStandby;
reboot = newReboot;
humidifier = newHumidifier;
screen = newScreen;
// 释放互斥锁
xSemaphoreGive(xMutex);
}
}
void displayTask(void *parameter)
{
while (true)
{
// Check for incoming serial data
serialEvent();
// Name of font file (library adds leading / and .vlw)
String fileName = "MiSan20Chinese";
if(boot){
tft.loadFont(fileName, SD);
tft.setTextColor(0x5ACB, TFT_WHITE, true);
tft.setCursor(30, 135);
tft.print("病房空气指标");
boot = false;
tft.loadFont("BigFonts45", SD);
tft.setCursor(50, 160);
tft.print("良好");
}
tft.loadFont(fileName, SD); // Use font stored on SD
if (temp_local_temperature != local_temperature)
{
tft.loadFont("MiddleNumFonts25", SD);
tft.setTextColor(0x5ACB, TFT_WHITE, true);
tft.fillRect(220, 195, 70, 20, TFT_WHITE); // Clear screen
tft.setCursor(220, 195);
tft.print(local_temperature);
tft.println("");
temp_local_temperature = local_temperature;
}
if (temp_local_humidity != local_humidity)
{
tft.loadFont("MiddleNumFonts25",SD);
tft.setTextColor(0x5ACB, TFT_WHITE, true);
tft.fillRect(220, 140, 70, 20, TFT_WHITE); // Clear screen
tft.setCursor(220, 140);
tft.print(local_humidity);
tft.println("%");
temp_local_humidity = local_humidity;
}
tft.setTextColor(TFT_WHITE, TFT_BLACK);
if(temp_weather != weather)
{
tft.loadFont("BigFonts45", SD);
tft.setTextColor(TFT_WHITE, 0x5873FF, true);
drawSdJpeg("/Photos/cloudy.jpg",23,20);
tft.setCursor(112, 20);
tft.print(weather);
temp_weather = weather;
}
if(temp_temperature != temperature){
tft.loadFont(fileName, SD);
tft.setTextColor(TFT_WHITE, 0x5873FF,true);
tft.setCursor(240, 20);
tft.print(temperature);
tft.print("");
temp_temperature = temperature;
}
if(temp_humidity != humidity){
tft.setTextColor(TFT_WHITE, 0x5873FF,true);
tft.setCursor(240, 60);
tft.print(humidity);
tft.print("%");
temp_humidity = humidity;
}
// if(temp_wind_direction != wind_direction){
// tft.fillRect(80,130,60,20,TFT_BLACK);
// tft.print(" ");
// tft.print(wind_direction);
// tft.print("风");
// temp_wind_direction = wind_direction;
// }
vTaskDelay(1000 / portTICK_PERIOD_MS); // 每1秒刷新一次屏幕
}
}
void checkStatusTask(void *parameters){
while (true)
{
if(screen == 1){
digitalWrite(LED_PIN, HIGH); // Turn on LED
}else{
digitalWrite(LED_PIN, LOW); // Turn off LED
}
if(reboot == 1){
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE){
reboot = 0;
xSemaphoreGive(xMutex);
}
postStatus();
delay(1000);
ESP.restart();
}
if(standby == 1){
Serial.println("进入待机模式");
delay(1000);
esp_light_sleep_start(); // 进入低功耗模式
}
if(humidifier == 1){
digitalWrite(HUMIDIFIER_PIN, HIGH); // Turn on humidifier
}else{
digitalWrite(HUMIDIFIER_PIN, LOW); // Turn off humidifier
}
vTaskDelay(500 / portTICK_PERIOD_MS); // 每0.秒检查一次数据
}
}
void listDir(fs::FS & fs, const char *dirname, uint8_t levels)
{
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if (!root)
{
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory())
{
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while (file)
{
if (file.isDirectory())
{
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels)
{
listDir(fs, file.name(), levels - 1);
}
}
else
{
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void serialEvent()
{
// 检查是否有数据传入
while (serial2.available())
{
// 从串口读取一个字符
char incomingByte = serial2.read();
// 如果接收到换行符或最大长度限制,则显示数据
if (incomingByte == '\n' || dataIndex >= 100)
{
receivedData0[dataIndex] = '\0'; // 结束字符串
ParseData(receivedData0); // 显示数据
// Serial.println(receivedData0);
dataIndex = 0; // 重置接收指针
}
else
{
receivedData0[dataIndex++] = incomingByte; // 将字符存入缓冲区
}
}
}
void ParseData(char *data) // 解析数据
{
char *token = strtok(data, ":");
while (token != NULL)
{
char *value = strtok(NULL, "C\r\n");
if (value != NULL)
{
if (strcmp(token, "Humidity") == 0)
{
local_humidity = atof(value);
Serial.print("Humidity: ");
Serial.println(local_humidity);
}
else if (strcmp(token, "Temperature") == 0)
{
local_temperature = atof(value);
Serial.print("Temperature: ");
Serial.println(local_temperature);
}
}
token = strtok(NULL, ":");
}
}
void drawSdJpeg(const char *filename, int xpos, int ypos)
{
// Open the named file (the Jpeg decoder library will close it)
File jpegFile = SD.open(filename, FILE_READ); // or, file handle reference for SD library
if (!jpegFile)
{
Serial.print("ERROR: File \"");
Serial.print(filename);
Serial.println("\" not found!");
return;
}
Serial.println("===========================");
Serial.print("Drawing file: ");
Serial.println(filename);
Serial.println("===========================");
// Use one of the following methods to initialise the decoder:
bool decoded = JpegDec.decodeSdFile(jpegFile); // Pass the SD file handle to the decoder,
// bool decoded = JpegDec.decodeSdFile(filename); // or pass the filename (String or character array)
if (decoded)
{
// print information about the image to the serial port
jpegInfo();
// render the image onto the screen at given coordinates
jpegRender(xpos, ypos);
}
else
{
Serial.println("Jpeg file format not supported!");
}
}

11
TFT-ESP32/test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html

82
TFT-ESP32/test/test.cpp Normal file
View File

@ -0,0 +1,82 @@
#include <TFT_eSPI.h> // TFT 显示屏库
TFT_eSPI tft = TFT_eSPI(); // 初始化 TFT 实例
const int screenWidth = 240; // 根据你的屏幕分辨率设置
const int screenHeight = 320;
const int byteWidth = (screenWidth + 7) / 8; // 每行需要的字节数
// 数组用于存储二值化后的屏幕数据
uint8_t binaryImage[screenHeight][byteWidth];
// 将屏幕数据读取并二值化,存储到数组中
void binaryScreenToArray()
{
for (int y = 0; y < screenHeight; y++)
{
uint8_t byteValue = 0;
for (int x = 0; x < screenWidth; x++)
{
// 读取像素颜色
uint16_t color = tft.readPixel(x, y);
// 将颜色二值化假设TFT_WHITE为白色其它为黑色
if (color == TFT_WHITE)
{
byteValue |= (1 << (7 - (x % 8))); // 设置当前位为1白色
}
// 每8个像素存储为一个字节
if (x % 8 == 7 || x == screenWidth - 1)
{
binaryImage[y][x / 8] = byteValue;
byteValue = 0;
}
}
}
}
// 将二值化后的屏幕数据通过串口发送到电脑,值之间用逗号隔开
void sendArrayToPC()
{
Serial.println("Start sending binary screen data:");
for (int y = 0; y < screenHeight; y++)
{
for (int x = 0; x < byteWidth; x++)
{
Serial.print(binaryImage[y][x], HEX); // 以十六进制格式发送每个字节
// 如果不是最后一个字节,则添加逗号
if (x < byteWidth - 1)
{
Serial.print(","); // 用逗号分隔
}
}
Serial.println(); // 每行结束后换行
}
Serial.println("Binary screen data sent.");
}
void setup()
{
Serial.begin(115200); // 初始化串口通信
tft.init(); // 初始化屏幕
tft.setRotation(1); // 根据需要设置屏幕的旋转
tft.fillScreen(TFT_BLACK); // 将屏幕设置为黑色
// 绘制一些内容(测试用)
tft.fillCircle(120, 160, 50, TFT_WHITE); // 在屏幕中间绘制一个白色的圆圈
// 读取并二值化屏幕内容
binaryScreenToArray();
// 将二值化后的数组通过串口传输到电脑
sendArrayToPC();
}
void loop()
{
// 主要功能在 setup 中执行loop 中不做任何操作
}

111
TFT-ESP32/test/testmain.cpp Normal file
View File

@ -0,0 +1,111 @@
//<App !Start!>
// FILE: [main.cpp]
// Created by GUIslice Builder version: [0.17.b34]
//
// GUIslice Builder Generated File
//
// For the latest guides, updates and support view:
// https://github.com/ImpulseAdventure/GUIslice
//
//<App !End!>
// ------------------------------------------------
// Headers to include
// ------------------------------------------------
#include "GUIsliceProjects_GSLC.h"
// ------------------------------------------------
// Program Globals
// ------------------------------------------------
// Save some element references for direct access
//<Save_References !Start!>
//<Save_References !End!>
// Define debug message function
static int16_t DebugOut(char ch)
{
if (ch == (char)'\n')
Serial.println("");
else
Serial.write(ch);
return 0;
}
// ------------------------------------------------
// Callback Methods
// ------------------------------------------------
// Common Button callback
bool CbBtnCommon(void *pvGui, void *pvElemRef, gslc_teTouch eTouch, int16_t nX, int16_t nY)
{
// Typecast the parameters to match the GUI and element types
gslc_tsGui *pGui = (gslc_tsGui *)(pvGui);
gslc_tsElemRef *pElemRef = (gslc_tsElemRef *)(pvElemRef);
gslc_tsElem *pElem = gslc_GetElemFromRef(pGui, pElemRef);
if (eTouch == GSLC_TOUCH_UP_IN)
{
// From the element's ID we can determine which button was pressed.
switch (pElem->nId)
{
//<Button Enums !Start!>
case E_ELEM_BTN1:
break;
case E_ELEM_BTN2:
break;
//<Button Enums !End!>
default:
break;
}
}
return true;
}
//<Checkbox Callback !Start!>
//<Checkbox Callback !End!>
//<Keypad Callback !Start!>
//<Keypad Callback !End!>
//<Spinner Callback !Start!>
//<Spinner Callback !End!>
//<Listbox Callback !Start!>
//<Listbox Callback !End!>
//<Draw Callback !Start!>
//<Draw Callback !End!>
//<Slider Callback !Start!>
//<Slider Callback !End!>
//<Tick Callback !Start!>
//<Tick Callback !End!>
void setup()
{
// ------------------------------------------------
// Initialize
// ------------------------------------------------
Serial.begin(9600);
// Wait for USB Serial
// delay(1000); // NOTE: Some devices require a delay after Serial.begin() before serial port can be used
gslc_InitDebug(&DebugOut);
// ------------------------------------------------
// Create graphic elements
// ------------------------------------------------
InitGUIslice_gen();
}
// -----------------------------------
// Main event loop
// -----------------------------------
void loop()
{
// ------------------------------------------------
// Update GUI Elements
// ------------------------------------------------
// TODO - Add update code for any text, gauges, or sliders
// ------------------------------------------------
// Periodically call GUIslice update function
// ------------------------------------------------
gslc_Update(&m_gui);
}

8
Web/imasBackend/.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

12
Web/imasBackend/.idea/dataSources.xml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="@localhost" uuid="76688b31-a8ea-4f6d-a3ba-125f73939125">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://localhost:3306</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

9
Web/imasBackend/.idea/imas-backend.iml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="jquery" level="application" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="PROJECT" libraries="{jquery}" />
</component>
</project>

8
Web/imasBackend/.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/imas-backend.iml" filepath="$PROJECT_DIR$/.idea/imas-backend.iml" />
</modules>
</component>
</project>

20
Web/imasBackend/.idea/php.xml generated Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="7.2" />
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

4
Web/imasBackend/.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings" defaultProject="true" />
</project>

View File

@ -0,0 +1,21 @@
<?php
include_once("../db_config.php");
date_default_timezone_set('Asia/Shanghai');
header("Content-Type: application/json"); // 返回 JSON 格式的响应
header("Access-Control-Allow-Origin: *"); // 允许跨域请求
header("Access-Control-Allow-Methods: POST, OPTIONS"); // 允许的方法
header("Access-Control-Allow-Headers: Content-Type"); // 允许的请求头
$queryString = "SELECT * FROM status LIMIT 1";
$result = mysqli_query($conn, $queryString);
$row = mysqli_fetch_assoc($result);
$standby = $row['standby'];
$reboot = $row['reboot'];
$data = array(
"standby" => $standby,
"reboot" => $reboot
);
echo json_encode($data);

View File

@ -0,0 +1,8 @@
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "IMAS";
// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);

62
Web/imasBackend/debug.php Normal file
View File

@ -0,0 +1,62 @@
<?php
include_once 'db_config.php';
//header('Content-Type: application/json');
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
if($_SERVER['REQUEST_METHOD'] == 'POST'){
// 获取 POST 数据
$postData = file_get_contents('php://input');
echo $postData;
// 解析 JSON 数据
$data = json_decode($postData, true);
// 检查是否成功解析
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
echo json_encode(['error' => 'JSON 解析错误: ' . json_last_error_msg()]);
exit;
}
// 处理数据
$standby = isset($data['standby']) ? $data['standby'] : 0;
$reboot = isset($data['reboot']) ? $data['reboot'] : 0;
$humidifier = isset($data['humidifier']) ? $data['humidifier'] : 0;
$screen = isset($data['screen']) ? $data['screen'] : 1;
// 处理逻辑示例
$response = [
'message' => '数据接收成功',
'standby' => $standby,
'reboot' => $reboot,
'humidifier' => $humidifier,
'screen' => $screen,
];
// 返回 JSON 响应
$queryString = "UPDATE `status` SET `standby`='$standby', `reboot`='$reboot', `humidifier`='$humidifier', `screen`='$screen'";
mysqli_query($conn, $queryString);
$queryString = "select * FROM status";
$result = mysqli_query($conn, $queryString);
if(mysqli_num_rows($result) > 0){
$data = []; // 初始化为空数组
while ($row = mysqli_fetch_object($result)) { // 获取查询结果作为对象
$data[] = $row; // 将对象追加到数组中
}
echo substr(json_encode($data),1,58) ; // 输出 JSON 格式的响应
}
}else{
$queryString = "select * FROM status";
$result = mysqli_query($conn, $queryString);
if(mysqli_num_rows($result) > 0){
$data = []; // 初始化为空数组
while ($row = mysqli_fetch_object($result)) { // 获取查询结果作为对象
$data[] = $row; // 将对象追加到数组中
}
echo substr(json_encode($data),1,58) ; // 输出 JSON 格式的响应
}
}

View File

@ -0,0 +1,33 @@
<?php
include_once "db_config.php"; // 数据库配置文件
date_default_timezone_set('Asia/Shanghai');
header("Content-Type: application/json"); // 返回 JSON 格式的响应
header("Access-Control-Allow-Origin: *"); // 允许跨域请求
header("Access-Control-Allow-Methods: POST, OPTIONS"); // 允许的方法
header("Access-Control-Allow-Headers: Content-Type"); // 允许的请求头
// 这里假设连接已经建立,并且您有 $link 变量代表数据库连接
// 定义SQL查询获取最近的10条记录
$query = "SELECT * FROM localdata ORDER BY time DESC LIMIT 1";
// 执行查询
$result = mysqli_query($conn, $query);
// 检查查询结果
if (!$result) {
die("查询失败: " . mysqli_error($conn)); // 处理错误
}
// 处理查询结果
$data = [];
while ($row = mysqli_fetch_assoc($result)) {
$data[] = $row; // 将每一行数据存入数组
}
// 返回 JSON 格式的数据
header("Content-Type: application/json");
echo json_encode($data);
// 关闭数据库连接
mysqli_close($conn);

View File

@ -0,0 +1,22 @@
<?php
include_once("db_config.php");
date_default_timezone_set('Asia/Shanghai');
header("Content-Type: application/json"); // 返回 JSON 格式的响应
header("Access-Control-Allow-Origin: *"); // 允许跨域请求
header("Access-Control-Allow-Methods: POST, OPTIONS"); // 允许的方法
header("Access-Control-Allow-Headers: Content-Type"); // 允许的请求头
$queryString = "SELECT * FROM control_list";
$result = mysqli_query($conn, $queryString);
if(mysqli_error($conn)){
echo json_encode(["code" => 1, "msg" => mysqli_error($conn)]);
exit();
}
else{
$data = array();
while($row = mysqli_fetch_assoc($result)){
$data[] = $row;
}
echo json_encode($data);
}

View File

@ -0,0 +1,52 @@
<?php
include_once "db_config.php";
date_default_timezone_set('Asia/Shanghai');
header("Content-Type: application/json"); // 返回 JSON 格式的响应
header("Access-Control-Allow-Origin: *"); // 允许跨域请求
header("Access-Control-Allow-Methods: POST, OPTIONS"); // 允许的方法
header("Access-Control-Allow-Headers: Content-Type"); // 允许的请求头
// 处理 OPTIONS 请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit();
}
// 获取原始 POST 数据
$input = json_decode(file_get_contents("php://input"), true); // 将 JSON 转换为 PHP 数组
// 检查是否成功解析 JSON
if (json_last_error() !== JSON_ERROR_NONE) {
echo json_encode(["error" => "无效的 JSON 数据"]);
exit();
}
$local_temperature = $input["Temperature"] ?? "";
$local_humidity = $input["Humidity"] ?? "";
//$standby = $input["status"]["standby"] ?? 0;
//$reboot = $input["status"]["reboot"] ?? 0;
//$humidifier = $input["status"]["humidifier"] ?? 0;
//$screen = $input["status"]["screen"] ?? 1;
$time = time();
$date = date("Y-m-d H:i:s", $time);
$queryString = "INSERT INTO localdata (time, temperature, humidity) VALUES ('$date', '$local_temperature', '$local_humidity')";
mysqli_query($conn, $queryString);
if(mysqli_error($conn)){
echo json_encode(["error" => "数据库错误"]);
}
$queryString = "select * FROM status";
$result = mysqli_query($conn, $queryString);
if(mysqli_num_rows($result) > 0){
$data = []; // 初始化为空数组
while ($row = mysqli_fetch_object($result)) { // 获取查询结果作为对象
$data[] = $row; // 将对象追加到数组中
echo substr(json_encode($data),1, 58); // 返回 JSON 格式的响应
}
}

View File

@ -0,0 +1,54 @@
<?php
include_once "db_config.php";
date_default_timezone_set('Asia/Shanghai');
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input["boot"]) || !isset($input["shutdown"]) || !isset($input["start"]) ||
!isset($input["end"]) || !isset($input["min_humidity"]) || !isset($input["max_humidity"]) ||
!isset($input["min_temperature"]) || !isset($input["max_temperature"]) ||
!isset($input["enable_boot"]) || !isset($input["enable_humidify"]) ||
!isset($input["enable_temp_threshold"]) || !isset($input["enable_humi_threshold"])) {
echo json_encode(["error" => "无效的请求数据"]);
exit();
}
// 获取输入数据
$boot = $input["boot"];
$shutdown = $input["shutdown"];
$start = $input["start"];
$end = $input["end"];
$min_humidity = $input["min_humidity"];
$max_humidity = $input["max_humidity"];
$min_temperature = $input["min_temperature"];
$max_temperature = $input["max_temperature"];
$enable_boot = $input["enable_boot"];
$enable_humidify = $input["enable_humidify"];
$enable_temp_threshold = $input["enable_temp_threshold"];
$enable_humi_threshold = $input["enable_humi_threshold"];
// 更新数据库
$queryString = "UPDATE control_list SET
boot='$boot',
shutdown='$shutdown',
start='$start',
end='$end',
min_humidity='$min_humidity',
max_humidity='$max_humidity',
min_temperature='$min_temperature',
max_temperature='$max_temperature',
enable_boot='$enable_boot',
enable_humidify='$enable_humidify',
enable_temp_threshold='$enable_temp_threshold',
enable_humi_threshold='$enable_humi_threshold'";
if (mysqli_query($conn, $queryString)) {
echo json_encode(["success" => "设置更新成功"]);
} else {
echo json_encode(["error" => "设置更新失败: " . mysqli_error($conn)]);
}

View File

@ -0,0 +1,41 @@
<?php
include_once "db_config.php";
date_default_timezone_set('Asia/Shanghai');
header("Content-Type: application/json"); // 返回 JSON 格式的响应
header("Access-Control-Allow-Origin: *"); // 允许跨域请求
header("Access-Control-Allow-Methods: POST, OPTIONS"); // 允许的方法
header("Access-Control-Allow-Headers: Content-Type"); // 允许的请求头
// 处理 OPTIONS 请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit();
}
// 获取原始 POST 数据
$input = json_decode(file_get_contents("php://input"), true); // 将 JSON 转换为 PHP 数组
// 检查是否成功解析 JSON
if (json_last_error() !== JSON_ERROR_NONE) {
echo json_encode(["error" => "无效的 JSON 数据"]);
exit();
}
$standby = $input["standby"];
$reboot = $input["reboot"];
$humidifier = $input["humidifier"];
$screen = $input["screen"];
$queryString = "UPDATE status SET standby='$standby', reboot='$reboot', humidifier='$humidifier', screen='$screen'";
mysqli_query($conn, $queryString);
if(mysqli_error($conn)){
echo json_encode(["error" => "状态更新失败"]);
}
else{
echo json_encode(["success" => "状态更新成功"]);
}

18
Web/imasBackend/test.php Normal file
View File

@ -0,0 +1,18 @@
<?php
header('Content-Type: text/html; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header('Access-Control-Allow-Headers: Content-Type');
header('Access-Control-Allow-Headers: Authorization');
header('Access-Control-Allow-Headers: X-Requested-With');
header("Content-Type: application/json"); // 返回 JSON 格式的响应
include_once "db_config.php";
$queryString = "select * FROM status";
$result = mysqli_query($conn, $queryString);
if(mysqli_num_rows($result) > 0){
$data = []; // 初始化为空数组
while ($row = mysqli_fetch_object($result)) { // 获取查询结果作为对象
$data[] = $row; // 将对象追加到数组中
}
echo substr(json_encode($data),1,58) ; // 输出 JSON 格式的响应
}

View File

@ -0,0 +1,7 @@
<?php
header("Access-Control-Allow-Origin: *"); // 允许所有域名访问
header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // 允许的请求方法
header("Access-Control-Allow-Headers: Content-Type"); // 允许的请求头
header("Content-type:application/json");
$weather = json_decode(file_get_contents('https://restapi.amap.com/v3/weather/weatherInfo?key=12085a54026b8e80ed3f69ec9c328e3e&city=510115&extensions=base&output=JSON'));
echo json_encode($weather);

View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

View File

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

12412
Web/imasFrontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
{
"name": "imas",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^1.7.9",
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3",
"bootstrap-timepicker": "^0.5.2",
"bootstrap-vue": "^2.23.1",
"core-js": "^3.8.3",
"flatpickr": "^4.6.13",
"lodash": "^4.17.21",
"pinia": "^2.3.0",
"toastify-js": "^1.12.0",
"vue": "^3.2.13",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.5.0",
"vue3-timepicker": "^1.0.0-beta.2"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@popperjs/core": "^2.11.8",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"bootstrap": "^5.3.3",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"jquery": "^3.7.1"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -0,0 +1,105 @@
<template>
<div class="Main-title h1 mt-0 ms-2 mb-3 ps-3 border-start border-5 border-dark-subtle" @click="clickTitle" >控制中心</div>
<router-view></router-view>
<footer class="mt-5 text-center border-top border-1">Copyright © 2024-2025 <a href="https://blog.monjack.cn" class="btn-link" style="text-decoration: none">王仁杰</a></footer>
</template>
<script>
export default {
name: 'App',
components: {
},
methods: {
clickTitle() {
this.$router.push('/HomeView');
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@100..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=ZCOOL+KuaiLe&display=swap');
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin-top: 20px;
}
.roboto-thin {
font-family: "Roboto", serif;
font-weight: 100;
font-style: normal;
}
.roboto-light {
font-family: "Roboto", serif;
font-weight: 300;
font-style: normal;
}
.roboto-regular {
font-family: "Roboto", serif;
font-weight: 400;
font-style: normal;
}
.roboto-medium {
font-family: "Roboto", serif;
font-weight: 500;
font-style: normal;
}
.roboto-bold {
font-family: "Roboto", serif;
font-weight: 700;
font-style: normal;
}
.roboto-black {
font-family: "Roboto", serif;
font-weight: 900;
font-style: normal;
}
.roboto-thin-italic {
font-family: "Roboto", serif;
font-weight: 100;
font-style: italic;
}
.roboto-light-italic {
font-family: "Roboto", serif;
font-weight: 300;
font-style: italic;
}
.roboto-regular-italic {
font-family: "Roboto", serif;
font-weight: 400;
font-style: italic;
}
.roboto-medium-italic {
font-family: "Roboto", serif;
font-weight: 500;
font-style: italic;
}
.roboto-bold-italic {
font-family: "Roboto", serif;
font-weight: 700;
font-style: italic;
}
.roboto-black-italic {
font-family: "Roboto", serif;
font-weight: 900;
font-style: italic;
}
.Main-title:hover {
color: #007bff;
cursor: pointer;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 KiB

View File

@ -0,0 +1,59 @@
<script>
import {getWeather} from '@/services/weatherService'
import TitleBlock from "@/components/TitleBlock.vue";
export default {
name: "APIView",
components: {
TitleBlock
},
data(){
return(
{
res: '',
weather: '',
temperature: '',
winddirection: '',
windpower: '',
reporttime: ''
}
)
},
async created() {
try {
const weatherData = await getWeather();
this.res = weatherData;
this.weather = weatherData.weather;
this.winddirection = weatherData.winddirection;
this.windpower = weatherData.windpower;
this.temperature = weatherData.temperature;
this.reporttime = weatherData.reporttime;
} catch (error) {
console.error('获取天气数据失败:', error);
}
}
}
</script>
<template>
<TitleBlock :title="'查看API数据'" />
<div class="ms-4 p-2 border rounded-3">
<div>天气 : {{ weather }}</div>
<div>温度 : {{temperature}}</div>
<div>风向 : {{winddirection}}</div>
<div>风力 : {{windpower}}</div>
<div>更新时间 : {{reporttime}}</div>
</div>
<div class="ms-4 mt-3 p-2 border rounded-3">
<json-viewer
:value="res"
:expand-depth=5
copyable
boxed
sort></json-viewer>
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,37 @@
<script>
import Toastify from 'toastify-js';
export default {
name: "ButtonArea",
methods: {
showToast() {
Toastify({
text: "请以管理员身份登录",
duration: 3000,
close: true
}).showToast();
}
}
}
</script>
<template>
<div class="mt-4 text-center">
<router-link to="/APIView">
<button class="btn btn-secondary w-25 shadow-sm m-2 fs-4"><a>查看API</a></button>
</router-link>
<router-link to="/SettingsView">
<button class="btn btn-secondary w-25 shadow-sm m-2 fs-4"><a>设置</a></button>
</router-link>
<router-link to="/DebugView">
<button class="btn btn-secondary w-25 shadow-sm m-2 fs-4">调试</button>
</router-link>
</div>
</template>
<style scoped>
template{
display: flex;
}
</style>

View File

@ -0,0 +1,198 @@
<script>
import TitleBlock from "@/components/TitleBlock.vue";
import $ from "jquery";
export default {
name: "DebugView",
components: {TitleBlock},
created() {
this.getStatusData();
},
data() {
return {
Label_button1: "待机",
Label_button2: "重启",
Label_button3: "启动加湿",
Label_button4: "关闭屏幕",
button1: false,
button2: false,
button3: false,
button4: false,
data: {
standby: 0,
reboot: 0,
humidifier: 0,
screen: 1,
}
};
},
methods: {
button1_click() {
console.log("待机");
this.button1 = true;
setTimeout(() => {
this.button1 = false;
}, 5000);
if (this.Label_button1 === "待机") {
this.Label_button1 = "工作";
this.button2 = true;
this.button3 = true;
this.button4 = true;
this.data.standby = 1;
} else {
this.Label_button1 = "待机";
this.button2 = false;
this.button3 = false;
this.button4 = false;
this.data.standby = 0;
}
this.updateData();
},
button2_click() {
console.log("重启");
this.button1 = true;
this.button2 = true;
this.button3 = true;
this.button4 = true;
setTimeout(() => {
this.button1 = false;
this.button2 = false;
this.button3 = false;
this.button4 = false;
}, 5000);
this.data.reboot = 1;
this.updateData();
this.data.reboot = 0;
},
button3_click() {
console.log("启动加湿");
this.button3 = true;
setTimeout(() => {
this.button3 = false;
}, 1000);
if (this.Label_button3 === "启动加湿") {
this.Label_button3 = "停止加湿";
this.data.humidifier = 1;
} else {
this.Label_button3 = "启动加湿";
this.data.humidifier = 0;
}
this.updateData();
},
button4_click() {
console.log("关闭屏幕");
this.button4 = true;
setTimeout(() => {
this.button4 = false;
}, 1000);
if (this.Label_button4 === "关闭屏幕") {
this.Label_button4 = "打开屏幕";
this.data.screen = 0;
} else {
this.Label_button4 = "关闭屏幕";
this.data.screen = 1;
}
this.updateData();
},
updateData() {
$.ajax({
url: "http://localhost/debug.php",
type: "POST",
contentType: "application/json",
data: JSON.stringify(this.data),
success: (response) => {
console.log(response);
},
error: (xhr, status, error) => {
console.log(error);
console.log(xhr.responseText);
}
}
)
},
getStatusData(){
$.ajax({
url: "http://localhost/debug.php",
type: "GET",
contentType: "application/json",
success: (response) => {
console.log(response);
this.data.standby = parseInt(JSON.parse(response).standby);
this.data.reboot = parseInt(JSON.parse(response).reboot);
this.data.humidifier = parseInt(JSON.parse(response).humidifier);
this.data.screen = parseInt(JSON.parse(response).screen);
if (this.data.standby) {
this.Label_button1 = "工作";
} else {
this.Label_button1 = "待机";
}
if (this.data.reboot) {
this.Label_button2 = "重启中";
} else {
this.Label_button2 = "重启";
}
if (this.data.humidifier) {
this.Label_button3 = "停止加湿";
} else {
this.Label_button3 = "启动加湿";
}
if (this.data.screen) {
this.Label_button4 = "关闭屏幕";
} else {
this.Label_button4 = "打开屏幕";
}
},
error: (xhr, status, error) => {
console.log(error);
console.log(xhr.responseText);
}
}
)
}
},
computed: {
}
}
</script>
<template>
<TitleBlock class="mb-4" title="调试" /><br>
<div class="text-center me-1 pe-5 ps-5">
<table class="table table-sm w-25">
<thead>
<tr>
<th>功能</th>
<th>状态</th>
</tr>
</thead>
<tbody class="table-group-divider">
<tr>
<td>在线状态</td>
<td>{{ data.standby? "离线" : data.reboot? "重启中": "在线" }}</td>
</tr>
<tr>
<td>启动加湿</td>
<td>{{ data.humidifier? "启动中" : "已停止" }}</td>
</tr>
<tr>
<td>关闭屏幕</td>
<td>{{ data.screen? "打开" : "关闭" }}</td>
</tr>
</tbody>
</table>
</div>
<div class="ms-5 mt-4 btn-group">
<button class="btn btn-outline-secondary" v-bind:disabled="button1" @click="button1_click" hidden>{{ Label_button1 }}</button>
<button class="btn btn-outline-secondary" v-bind:disabled="button2" @click="button2_click">{{ Label_button2 }}</button>
<button class="btn btn-outline-secondary" v-bind:disabled="button3" @click="button3_click">{{ Label_button3 }}</button>
<button class="btn btn-outline-secondary" v-bind:disabled="button4" @click="button4_click">{{ Label_button4 }}</button>
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,20 @@
<script>
import ButtonArea from "@/components/ButtonArea.vue";
import WeatherCard from "@/components/WeatherCard.vue";
import RoomCard from "@/components/RoomCard.vue";
export default {
name: "HomeView",
components: {RoomCard, WeatherCard, ButtonArea}
}
</script>
<template>
<WeatherCard style=""></WeatherCard>
<RoomCard></RoomCard>
<ButtonArea></ButtonArea>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,68 @@
<script>
import {getLocalData} from "@/services/weatherService";
export default {
name: "RoomCard",
data() {
return {
RoomTemp: 20,
RoomHumidity: 40,
LastUpdateTime: "未获取",
RoomNumber: "101",
}
},
methods: {
TempMap(temp) {
if (temp < 18) {
return "冷";
} else if (temp < 25) {
return "适中";
} else if (temp >34) {
return "热";
} else{
return "暖";
}
},
HumidityMap(humidity) {
if (humidity < 30) {
return "较干燥";
} else if (humidity < 60) {
return "正常";
} else {
return "较湿";
}
},
},
async created() {
const localData = await getLocalData();
console.log(localData);
this.RoomTemp = localData[0].temperature;
console.log(this.RoomTemp);
this.RoomHumidity = localData[0].humidity;
console.log(this.RoomHumidity);
this.LastUpdateTime = localData[0].time;
},
}
</script>
<template>
<div class="border border-0 border-dark-subtle m-3 p-4 rounded-4 shadow">
<div class="h1 ms-2 mb-2 fw-semibold roboto-bold">房间</div>
<div class="fs-3 ms-3 text-black-75">
<div class="fs-2 mt-3 mb-2 border-bottom border-2">
<span class=""></span>
</div>
<i class="bi bi-thermometer-half"></i>
{{ TempMap(RoomTemp) }} {{ RoomTemp }}
<div class="mt-4 ms-1 fs-4">
<i class="bi bi-moisture"></i> <span class="ms-1 me-4">{{HumidityMap(RoomHumidity)}}</span><span>{{ RoomHumidity }}%</span>
</div>
</div>
<div class="text-end fs-6 fw-light mt-3"><span class="me-4">更新时间</span><span>{{ LastUpdateTime }}</span></div>
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,155 @@
<script>
import TitleBlock from "@/components/TitleBlock.vue";
import TimePicker from "@/components/TimePicker.vue";
import ThresholdPicker from "@/components/ThresholdPicker.vue";
import axios from "axios";
export default {
name: "SettingsView",
components: {TimePicker, TitleBlock, ThresholdPicker},
created() {
this.getSettings();
},
data() {
return {
timeSettings:{
times_Power: {
times:{
PowerOn: "12:00",
PowerOff: "12:30"
},
enable_boot: false,
},
times_Humidity: {
times:{
HumidityOn: "12:00",
HumidityOff: "12:30",
},
enable_boot: false,
},
},
thresholdSettings:{
Threshold_Humidity:{
thresholds: {
min: 20,
max: 80,
},
enable_boot: false,
},
Threshold_Temperature:{
thresholds: {
min: 20,
max: 26,
},
enable_boot: false,
},
},
loaded: true
}
},
methods: {
save() {
this.postSettings();
},
cancel() {
window.location.reload();
},
getSettings() {
axios.get("http://locahost/getSetting.php").then(response => {
console.log(response.data);
this.timeSettings.times_Power = {
times: {
PowerOn: response.data[0].boot,
PowerOff: response.data[0].shutdown,
},
enable_boot: response.data[0].enable_boot == 1,
}
console.log(this.timeSettings.times_Power);
this.timeSettings.times_Humidity = {
times: {
HumidityOn: response.data[0].start,
HumidityOff: response.data[0].end,
},
enable_boot: response.data[0].enable_humidify == 1,
}
this.thresholdSettings.Threshold_Humidity = {
thresholds: {
min: response.data[0].min_humidity,
max: response.data[0].max_humidity,
},
enable_boot: response.data[0].enable_humi_threshold == 1,
}
this.thresholdSettings.Threshold_Temperature = {
thresholds: {
min: response.data[0].min_temperature,
max: response.data[0].max_temperature,
},
enable_boot: response.data[0].enable_temp_threshold == 1,
}
this.loaded = true;
}).catch(error => {
console.log(error);
});
},
postSettings() {
axios.post("http://locahost/postSetting.php", {
boot: this.timeSettings.times_Power.times.PowerOn,
shutdown: this.timeSettings.times_Power.times.PowerOff,
start: this.timeSettings.times_Humidity.times.HumidityOn,
end: this.timeSettings.times_Humidity.times.HumidityOff,
min_humidity: this.thresholdSettings.Threshold_Humidity.thresholds.min,
max_humidity: this.thresholdSettings.Threshold_Humidity.thresholds.max,
min_temperature: this.thresholdSettings.Threshold_Temperature.thresholds.min,
max_temperature: this.thresholdSettings.Threshold_Temperature.thresholds.max,
enable_boot: this.timeSettings.times_Power.enable_boot? 1 : 0,
enable_humidify: this.timeSettings.times_Humidity.enable_boot? 1 : 0,
enable_humi_threshold: this.thresholdSettings.Threshold_Humidity.enable_boot? 1 : 0,
enable_temp_threshold: this.thresholdSettings.Threshold_Temperature.enable_boot? 1 : 0,
}).then(response => {
console.log(response);
this.loaded = false;
}).catch(error => {
console.log(error);
this.loaded = true;
});
}
}
}
</script>
<template>
<div v-if="loaded">
<TitleBlock title="设置" />
<span hidden>{{timeSettings.times_Power.times.PowerOn}}</span>
<span hidden>{{timeSettings.times_Power.times.PowerOff}}</span>
<span hidden>{{timeSettings.times_Humidity.times.HumidityOn}}</span>
<span hidden>{{timeSettings.times_Humidity.times.HumidityOff}}</span>
<span hidden>{{thresholdSettings.Threshold_Humidity.thresholds.min}}</span>
<span hidden>{{thresholdSettings.Threshold_Humidity.thresholds.max}}</span>
<span hidden>{{thresholdSettings.Threshold_Temperature.thresholds.min}}</span>
<span hidden>{{thresholdSettings.Threshold_Temperature.thresholds.max}}</span>
<div class="ms-5 mt-2 fs-5 ">
<TimePicker :pickers="timeSettings.times_Power.times" v-model="timeSettings.times_Power" :title="'定时开关机'" :enable="timeSettings.times_Power.enable_boot" />
</div>
<div class="ms-5 mt-2 fs-5 ">
<TimePicker v-model="timeSettings.times_Humidity" :title="'定时加湿'" :enable="timeSettings.times_Humidity.enable_boot" :pickers=timeSettings.times_Humidity.times />
</div>
<div class="ms-5 mt-2 fs-5 ">
<ThresholdPicker v-model="thresholdSettings.Threshold_Temperature" :title="'温度阈值'" :enable="thresholdSettings.Threshold_Temperature.enable_boot" :Thresholds=thresholdSettings.Threshold_Temperature.thresholds />
</div>
<div class="ms-5 mt-2 fs-5 ">
<ThresholdPicker v-model="thresholdSettings.Threshold_Humidity" :title="'湿度阈值'" :enable="thresholdSettings.Threshold_Humidity.enable_boot" :Thresholds=thresholdSettings.Threshold_Humidity.thresholds />
</div>
<div class="mt-5">
<button class="btn btn-secondary ms-5 mt-2 fs-5" @click="save">保存</button>
<button class="btn btn-secondary ms-5 mt-2 fs-5" @click="cancel">重置</button>
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,85 @@
<script>
export default {
name: "ThresholdPicker",
components: {},
mounted() {
this.LocalThresholds = this.Thresholds
this.showThresholdPicker = this.enable
},
methods: {
updateThresholds() {
this.$emit("update:Thresholds", this.LocalThresholds)
}
},
data() {
return {
showThresholdPicker: false,
LocalThresholds: {
min: "",
max: "",
},
unit: "%"
}
},
props: {
title: {
type: String,
default: ""
},
Thresholds: {
type: Object,
default: () => ({
min: "",
max: "",
})
},
enable: {
type: Boolean,
default: true
}
}
}
</script>
<template>
<div class="d-flex align-items-center flex-wrap">
<div class="form-check form-switch">
<input
type="checkbox"
class="form-check-input"
role="switch"
id="showThresholdPicker"
v-model="showThresholdPicker"
/>
<label class="form-check-label me-4" for="showThresholdPicker">{{ title }}</label>
</div>
<div v-if="showThresholdPicker">
<input
v-for="(threshold, index) in LocalThresholds"
:key="index"
:placeholder="index ==='min'? '输入最小阈值' : '输入最大阈值'"
@input="updateThresholds"
v-model="LocalThresholds[index]"
type="text"
class="picker-input fs-5" />
</div>
</div>
</template>
<style scoped>
.picker-input {
width: 200px;
margin-left: 9px;
padding: 10px 10px 10px;
font-size: 14px;
border: 1px solid #ccc;
outline: none;
}
.picker-input:focus {
border: 2px solid #101010;
border-radius: 5px;
}
</style>

View File

@ -0,0 +1,72 @@
<template>
<div class="d-flex align-items-center flex-wrap ">
<!-- Checkbox to toggle timepicker visibility -->
<div class="form-check form-switch">
<input
type="checkbox"
class="form-check-input"
role="switch"
id="showTimepicker"
v-model="showTimepicker"
/>
<label class="form-check-label me-4" for="showTimepicker">{{ title }}</label>
</div>
<div v-if="showTimepicker">
<VueTimepicker
v-for="(picker, index) in pickers"
:key="index"
:picker="picker"
class="mt-2 ms-2"
:placeholder="index"
v-model="time[index]"
@change="updateTime(index)"
>
<template v-slot:icon>
<i class="bi bi-clock"></i>
</template>
</VueTimepicker>
</div>
</div>
</template>
<script>
import VueTimepicker from "vue3-timepicker";
export default {
name: "TimePicker",
props: {
title: String,
pickers: {
type: Object,
required: true,
default: () => ({
time: "00:00",
}),
},
enable: {
type: Boolean,
default: true,
},
},
data() {
return {
showTimepicker: false,
time: {}, // 本地时间数据
};
},
components: {
VueTimepicker,
},
mounted() {
this.showTimepicker = this.enable;
this.time = { ...this.pickers }; // 初始化 time 数据
},
methods: {
updateTime() {
this.$emit("update:pickers", Object.assign({}, this.time, this.showTimepicker)); // 确保事件名称和父组件一致
},
},
};
</script>
<style>
</style>

View File

@ -0,0 +1,24 @@
<script>
export default {
name: "TitleBlock",
props: {
title: {
type: String,
required: true
}
}
}
</script>
<template>
<div class="title ms-4 ps-1 pt-2 pe-1 mb-3 mt-1 border-bottom border-3 ">
<h2>{{ title }}</h2>
</div>
</template>
<style scoped>
.title {
display: inline-block; /* 使宽度适应内容 */
user-select: none; /* 防止选中文本 */
}
</style>

View File

@ -0,0 +1,152 @@
<script>
import {getWeather, getIPInfo} from "@/services/weatherService";
import TitleBlock from "@/components/TitleBlock.vue";
export default {
name: "WeatherCard",
components: {
TitleBlock
},
data() {
return {
weather: '',
temperature: '',
winddirection: '',
windpower: '',
reporttime: '',
clothingIndex: '',
windspeedMap: {
'0': 0.5,
'1': 0.9,
'2': 2.5,
'3': 4.4,
'4': 6.7,
'5': 9.3,
'6': 12.5,
'7': 15.5,
'8': 19.0,
'9': 22.6,
'10': 26.45,
'11': 30.55,
'12': 32
},
CloudMap: {
'晴': 0,
'阴': 9,
'多云': 6,
'雨': 10,
},
ip: '',
address: '',
}
},
methods: {
GetClothingIndex(temp, windSpeed) {
const tFelt = calculateWindChill(temp, windSpeed);
function calculateWindChill(temp, windSpeed) {
return (
13.12 +
0.6215 * temp -
11.37 * Math.pow(windSpeed, 0.16) +
0.3965 * temp * Math.pow(windSpeed, 0.16)
);
}
if (tFelt > 26) {
return "短袖或薄长袖";
} else if (tFelt >= 20 && tFelt <= 26) {
return "薄外套、长袖";
} else if (tFelt >= 10 && tFelt < 20) {
return "厚外套";
} else if (tFelt >= 0 && tFelt < 10) {
return "棉衣或羽绒服";
} else {
return "加厚羽绒服,注意保暖";
}
}
},
// GetClothingIndex() {
// let Ic, Ts, Tv, Tr, Ta, H, Rat, Ia, V, Nt, Nl;
// Nl = 0;
// Ts = 33;
// V = this.windspeedMap[this.windpower.match(/\d+/g)];
// Nt = this.weather in this.CloudMap? this.CloudMap[this.weather] : 5;
// Ta = 20;
// Ia = 0.40 / Math.pow(V, 0.406);
// Tv = 0.0246 * Math.pow(Math.log10(7.23 * V), 3) - 0.4525 * Math.pow(Math.log10(7.23 * V), 2) + 3.2398 * Math.log10(7.23 * V);
// Tr = 0.42 * (1- 0.45 * (Nt + Nl)) * 0.5 * Ia;
// H = 0.93244 * 4.1841 * (0.104 * Ta*Ta - 5.1403 * Ta + 117.13);
// Ta >= 25?
// Rat = 0.0775 + 0.001 * Ta * (0.1 * Ta * (0.01 * Ta * (1.235 * Ta - 54.8752) + 10.1044) - 3.2813)
// : Rat = 0.24;
// Ic = (Ts - Ta - Tv + Tr)/(H * (1 - Rat) * 0.043) - Ia;
// console.log(Ic);
// return Ic;
//
// }
async created() {
try {
const weatherData = await getWeather();
const ipInfo = await getIPInfo();
this.address = ipInfo.province + ipInfo.city;
this.weather = weatherData.weather;
this.winddirection = weatherData.winddirection;
this.windpower = weatherData.windpower;
this.temperature = weatherData.temperature;
this.reporttime = weatherData.reporttime;
} catch (error) {
console.error('获取天气数据失败:', error);
}
this.clothingIndex = this.GetClothingIndex(this.temperature, this.windspeedMap[this.windpower.match(/\d+/g)]);
},
computed: {
iconClass() {
switch (this.weather) {
case '晴':
return 'bi-sun';
case '阴':
return 'bi-cloud-drizzle';
case '多云':
return 'bi-cloud-fog';
case '雨':
return 'bi-cloud-rain';
case '雪':
return 'bi-cloud-snow';
default:
return 'bi-cloud';
}
}
}
}
</script>
<template>
<TitleBlock title="概览"></TitleBlock>
<div class="border border-0 border-dark-subtle m-3 p-4 rounded-4 shadow">
<div class="h1 ms-2 mb-2 fw-semibold roboto-bold">天气</div>
<div class="fs-3 ms-3 text-black-75">
<div class="fs-2 mt-3 mb-2 border-bottom border-2">
<span class=""></span>
</div>
<div class="fs-4 mb-3 mt-3">{{ address }}</div>
<i :class="iconClass"></i>
{{ weather }} {{ temperature }}
<div class="mt-2 fs-4">
<i class="bi bi-wind"></i> <span class="me-4">{{ winddirection }}</span><span>{{ windpower }}</span>
</div>
<div class="mt-2 fs-4">
<span class="me-4">适宜衣物</span><span>{{ clothingIndex }}</span>
</div>
<div class="text-end fs-6 fw-light mt-3">
点击查看未来天气
</div>
</div>
<div class="text-end fs-6 fw-light mt-1"><span class="me-4">更新时间</span><span>{{reporttime}}</span></div>
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,28 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import 'jquery/dist/jquery.min.js'
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.min.js'
import 'bootstrap-icons/font/bootstrap-icons.css'
import "toastify-js/src/toastify.css"
import Toastify from 'toastify-js'
import 'vue3-timepicker/dist/VueTimepicker.css'
import VueTimepicker from 'vue3-timepicker'
import JsonViewer from 'vue-json-viewer'
import router from './router'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App);
app.use(router);
app.use(JsonViewer);
app.use(VueTimepicker);
app.use(Toastify);
app.use(pinia);
app.mount('#app');

View File

@ -0,0 +1,52 @@
import {createRouter, createWebHistory} from "vue-router";
import WeatherCard from "@/components/WeatherCard.vue";
import RoomCard from "@/components/RoomCard.vue";
import HomeView from "@/components/HomeView.vue";
import DebugView from "@/components/DebugView.vue";
import APIView from "@/components/APIView.vue";
import SettingsView from "@/components/SettingsView.vue";
const routes = [
{
path: '/WeatherCard',
name: 'WeatherCard',
component: WeatherCard
},
{
path: '/RoomCard',
name: 'RoomCard',
component: RoomCard
},
{
path: '/DebugView',
name: 'DebugView',
component: DebugView
},
{
path: '/HomeView',
name: 'HomeView',
component: HomeView
},
{
path: '/',
redirect: '/HomeView',
},
{
path: '/APIView',
name: 'APIView',
component: APIView
},
{
path: '/SettingsView',
name: 'SettingsView',
component: SettingsView
}
]
const router = createRouter({
history: createWebHistory(),
routes
});
export default router

View File

@ -0,0 +1,35 @@
// weatherService.js
import axios from "axios";
export async function getWeather() {
try {
const response = await axios.get("http://monjack.cn/weatherInfo.php");
const weatherData = response.data.lives[0];
return weatherData;
// 将 API 数据更新到 Pinia Store
} catch (error) {
console.error("Failed to fetch weather data:", error);
throw error; // 确保将错误抛出,以便调用者可以捕获
}
}
export async function getIPInfo() {
try {
const response = await axios.get("https://restapi.amap.com/v3/ip?key=12085a54026b8e80ed3f69ec9c328e3e");
return response.data;
// 将 API 数据更新到 Pinia Store
} catch (error) {
console.error("Failed to fetch IP info:", error);
}
}
export async function getLocalData() {
try {
const response = await axios.get("http://localhost/getLocalData.php");
return response.data;
// 将 API 数据更新到 Pinia Store
} catch (error) {
console.error("Failed to fetch local data:", error);
}
}

View File

@ -0,0 +1,22 @@
const { defineConfig } = require('@vue/cli-service')
// module.exports = defineConfig({
// transpileDependencies: true
// })
// defineConfig 这里是vue3 的默认代码
const webpack = require("webpack")
module.exports = defineConfig({
// 配置插件参数
configureWebpack: {
plugins: [
// 配置 jQuery 插件的参数
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default']
})
]
}
})