添加deeresp相关源码和文档
11
README.md
@ -2,6 +2,17 @@ PushDeer是一个可以自行架设的无APP推送服务。
|
|||||||
|
|
||||||
当前状态:API、iOS、Android和Mac第一版已完成,快应用正在开发🚧
|
当前状态:API、iOS、Android和Mac第一版已完成,快应用正在开发🚧
|
||||||
|
|
||||||
|
**🔥 PushDeer支持推送消息到智能设备了**
|
||||||
|
|
||||||
|
👉[点此查看如何将消息推送到成本35元左右的自制设备上](other_devices/README.md)
|
||||||
|
|
||||||
|
||||
|
||||||
|
|-|-|-|
|
||||||
|
|[👨🏻🏫 教程](other_devices/README.md)|[⌨️ 源码](other_devices/deeresp/)|[📼 演示视频,可以听到提示音♪](https://weibo.com/1088413295/LfJtvDx6K?type=comment)|
|
||||||
|
|
||||||
|
![](other_devices/image/deeresp.gif)
|
||||||
|
|
||||||
|
|
||||||
[🐙🐱 GitHub仓库](https://github.com/easychen/pushdeer) [🔮 中国大陆镜像仓库@Gitee](https://gitee.com/easychen/pushdeer)
|
[🐙🐱 GitHub仓库](https://github.com/easychen/pushdeer) [🔮 中国大陆镜像仓库@Gitee](https://gitee.com/easychen/pushdeer)
|
||||||
|
|
||||||
|登入|设备|Key|消息|设置|
|
|登入|设备|Key|消息|设置|
|
||||||
|
@ -1,11 +1,82 @@
|
|||||||
# 使用MQTT接受PushDeer推送的消息
|
> PushDeer可以将消息推送到各种支持MQTT协议的智能设备。
|
||||||
|
|
||||||
|
本文将以 `NodeMCU` 1.0开发板和 1.44寸的 Arduino Black TFT屏幕为例,讲解如何组建一个成本35元人民币左右的硬件设备,并通过PushDeer将消息推送给它。
|
||||||
|
|
||||||
|
最终效果如下图:
|
||||||
|
|
||||||
|
![](image/deeresp.gif)
|
||||||
|
|
||||||
|
[📼 点此查看视频版本,可以听到提示音♪](https://weibo.com/1088413295/LfJtvDx6K?type=comment)
|
||||||
|
|
||||||
|
PS:如果你有硬件量产的经验并有兴趣参与,可以在[微博](https://weibo.com/easy)私信或者评论@Easy。
|
||||||
|
|
||||||
|
## 硬件的购买
|
||||||
|
|
||||||
|
![](image/2022-02-17-00-43-58.png)
|
||||||
|
|
||||||
|
1. 开发板:只要是兼容NodeMCU1.0规范的就行,内存需要4M(32Mbits),更大更好(就能放中文字库了)我选的是CH340接口
|
||||||
|
1. 屏幕:[1.44寸黑色TFT](http://www.lcdwiki.com/zh/1.44inch_SPI_Arduino_Module_Black_SKU:MAR1442),其他兼容ST7735驱动的屏幕也可以,但连线可能就不同了,需要自己配置屏幕库
|
||||||
|
1. 蜂鸣器(可选):来消息时播放提示音
|
||||||
|
|
||||||
|
前边两个加上USB线,[淘宝33.30](https://item.taobao.com/item.htm?spm=a1z09.2.0.0.2c042e8dlNdY3E&id=531755241333&_u=gog6id51b2),无源蜂鸣器:[淘宝3.3](https://detail.tmall.com/item.htm?id=41251333522&spm=a1z09.2.0.0.2c042e8dlNdY3E&_u=gog6id9820&skuId=4323951807546)。不认识店家,就随便搜了就买了。
|
||||||
|
|
||||||
|
## 硬件的连接
|
||||||
|
|
||||||
|
首先把屏幕和开发板连起来,按下图操作:
|
||||||
|
|
||||||
|
![](image/2022-02-16-21-48-45.png)
|
||||||
|
|
||||||
|
然后再把蜂鸣器和开发板连起来
|
||||||
|
|
||||||
|
|蜂鸣器|开发板|
|
||||||
|
|-|-|
|
||||||
|
|GND|G|
|
||||||
|
|VCC|3V|
|
||||||
|
|IO|D8|
|
||||||
|
|
||||||
|
如果你的连线不同,那么程序中的PIN值可能需要随之调整。
|
||||||
|
|
||||||
|
## 将开发板和电脑连起来
|
||||||
|
|
||||||
|
### 串口驱动安装
|
||||||
|
|
||||||
|
用USB线将开发板和电脑连起来,但这时候它们之间还不能通信,因为开发板用串口信号,电脑用USB信号,需要进行转换。
|
||||||
|
|
||||||
|
一般NodeMCU开发板上有自带转换芯片,比如CH3XX或者CPXXX,这里以CH340为例。去它们官网下载[最新的驱动](http://www.wch.cn/products/ch340.html)安装后,两者就能通信了。
|
||||||
|
|
||||||
|
![](image/2022-02-16-21-59-51.png)
|
||||||
|
|
||||||
|
## 配置开发环境
|
||||||
|
|
||||||
|
我们使用 `arduino` 开发环境进行开发,在此之前需要[下载并安装它的IDE](https://www.arduino.cc/en/software)。
|
||||||
|
|
||||||
|
![](image/2022-02-16-22-01-05.png)
|
||||||
|
|
||||||
|
由于我们使用的8266并没有内置到 `ardunio IDE` 中,我们还需要进行一下配置,在设置界面填上附加开发板管理器网址:`https://arduino.esp8266.com/stable/package_esp8266com_index.json`
|
||||||
|
|
||||||
|
![](image/2022-02-16-22-02-36.png)
|
||||||
|
|
||||||
|
然后选择 `工具`→`开发板`→`ESP8266 Boards`→`NodeMCU1.0`
|
||||||
|
|
||||||
|
![](image/2022-02-16-22-04-25.png)
|
||||||
|
|
||||||
|
再调整下开发板使用的串口:
|
||||||
|
|
||||||
|
![](image/2022-02-16-22-07-07.png)
|
||||||
|
|
||||||
|
要确认哪一个串口是开发板的很简单,你拔掉它就不见了…
|
||||||
|
|
||||||
|
这些准备工作做好以后,我们就可以将代码烧录到设备上了。但在这之前,我们需要把MQTT服务器架设起来,之后我们才能把账号等信息烧录进去。
|
||||||
|
|
||||||
|
|
||||||
|
## 使用MQTT接受PushDeer推送的消息
|
||||||
|
|
||||||
PushDeer自架版支持通过MQTT协议向兼容的设备(以下简称设备)发送信息,其主要工作原理是:
|
PushDeer自架版支持通过MQTT协议向兼容的设备(以下简称设备)发送信息,其主要工作原理是:
|
||||||
|
|
||||||
1. 自架版docker-compose文件中预置了MQTT服务器,手动开启后,设备可以通过配置的端口连接到服务器
|
1. 自架版docker-compose文件中预置了MQTT服务器,手动开启后,设备可以通过配置的端口连接到服务器
|
||||||
1. 设备通过订阅主题实时获得消息,文字类型(text/markdown)消息主题为:`{{pushkey}}_text`, 图片类型的主题为`{{pushkey}}_bg_url`
|
1. 设备通过订阅主题实时获得消息,文字类型(text/markdown)消息主题为:`{{pushkey}}_text`, 图片类型的主题为`{{pushkey}}_bg_url`
|
||||||
|
|
||||||
## 开启MQTT服务
|
### 开启MQTT服务
|
||||||
|
|
||||||
修改根目录下的 `docker-compose.self-hosted.yml`:
|
修改根目录下的 `docker-compose.self-hosted.yml`:
|
||||||
|
|
||||||
@ -67,7 +138,7 @@ PushDeer自架版支持通过MQTT协议向兼容的设备(以下简称设备
|
|||||||
docker-compose -f docker-compose.self-hosted.yml up --build -d
|
docker-compose -f docker-compose.self-hosted.yml up --build -d
|
||||||
```
|
```
|
||||||
|
|
||||||
## 连接参数实例
|
### 连接参数实例
|
||||||
|
|
||||||
这里以上边的设置为例,详细说明MQTT连接中用到的值,假设你的`Pushkey` 为 `PDU01234`,那么:
|
这里以上边的设置为例,详细说明MQTT连接中用到的值,假设你的`Pushkey` 为 `PDU01234`,那么:
|
||||||
|
|
||||||
@ -89,4 +160,115 @@ docker-compose -f docker-compose.self-hosted.yml up --build -d
|
|||||||
1. text/markdown类型的消息会通过`PDU01234_text`发送
|
1. text/markdown类型的消息会通过`PDU01234_text`发送
|
||||||
1. image类型的消息会通过`PDU01234_bg_url`发送
|
1. image类型的消息会通过`PDU01234_bg_url`发送
|
||||||
|
|
||||||
|
## 烧录程序到设备
|
||||||
|
|
||||||
|
回到我们的设备这边来。首先用 `arduino IDE` 打开 `deeresp/deeresp.ino`,修改最上边的几行:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define WIFI_SSID "wifi名称"
|
||||||
|
#define WIFI_PASSWORD "wifi密码"
|
||||||
|
#define MQTT_IP "pushdeer公网IP"
|
||||||
|
#define MQTT_USER "MQTT用户名"
|
||||||
|
#define MQTT_PASSWORD "MQTT密码"
|
||||||
|
#define MQTT_TOPIC "PushDeer pushkey" // 这里填PushDeer的Key
|
||||||
|
#define MQTT_PORT 1883
|
||||||
|
```
|
||||||
|
|
||||||
|
这里的信息我们现在都有了,把它们替换掉,然后点击上传图标(向右的箭头),就会编译并烧录程序到设备上了。不过别急,有两个问题需要处理。
|
||||||
|
|
||||||
|
![](image/2022-02-16-23-32-30.png)
|
||||||
|
|
||||||
|
### 添加缺少的库
|
||||||
|
|
||||||
|
如果你在编译的过程中遇到了错误,那么多半是因为缺少库导致的。可以直接在IDE中搜索添加。以 `TJpg_Decoder` 库为例,点开`项目`→`加载库`→`管理库`。
|
||||||
|
|
||||||
|
![](image/2022-02-16-23-35-41.png)
|
||||||
|
|
||||||
|
在弹出的`库管理器`窗口里输入库的名字进行搜索,选择对应库并点击`安装`即可。
|
||||||
|
|
||||||
|
![](image/2022-02-16-23-38-05.png)
|
||||||
|
|
||||||
|
### 屏幕适配
|
||||||
|
|
||||||
|
我们使用了 `TFT_eSPI` 这个库来控制屏幕,它可以适配非常多的屏幕,但我们并没有在代码中告诉它我们用的屏幕是哪一款。这是因为,它要靠修改源代码目录的配置文件来实现的。
|
||||||
|
|
||||||
|
在首选项中找到`项目文件夹`位置。
|
||||||
|
![](image/2022-02-16-23-42-25.png)
|
||||||
|
|
||||||
|
打开该目录,然后找到 `User_Setup.h`文件。
|
||||||
|
|
||||||
|
![](image/2022-02-16-23-44-07.png)
|
||||||
|
|
||||||
|
将以下行之前的注释去掉:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define ST7735_DRIVER
|
||||||
|
#define TFT_RGB_ORDER TFT_BGR
|
||||||
|
#define TFT_WIDTH 128
|
||||||
|
#define TFT_HEIGHT 128
|
||||||
|
#define ST7735_GREENTAB3
|
||||||
|
#define TFT_CS PIN_D1 // Chip select control pin D8
|
||||||
|
#define TFT_DC PIN_D3 // Data Command control pin
|
||||||
|
#define TFT_RST PIN_D2 // Reset pin (could connect to NodeMCU RST, see next line)
|
||||||
|
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
|
||||||
|
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
|
||||||
|
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
|
||||||
|
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
|
||||||
|
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
|
||||||
|
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
|
||||||
|
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
|
||||||
|
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
|
||||||
|
#define SMOOTH_FONT
|
||||||
|
#define SPI_FREQUENCY 27000000
|
||||||
|
#define SPI_READ_FREQUENCY 20000000
|
||||||
|
#define SPI_TOUCH_FREQUENCY 2500000
|
||||||
|
```
|
||||||
|
|
||||||
|
然后再打开同目录下的 `TFT_eSPI.h`,找到 `User_select.h`,打开注释:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <User_Setup.h>
|
||||||
|
// #include <User_Setup_Select.h>
|
||||||
|
```
|
||||||
|
|
||||||
|
这些操作完成后再编译就会发现屏幕正常显示了。如果显示不正常(比如图片颜色、大小不对等),这有可能是因为你用的屏幕硬件规格和我们这里的不同,可以参照注释尝试修改那些配置项。
|
||||||
|
|
||||||
|
## 通过 PushDeer 推送信息到设备
|
||||||
|
|
||||||
|
当程序烧录完成,设备会初始化并自动连接服务器。如果没有初始化,可以按开发板上的reset进行重置。如果在烧录过程中串口无法连接开发板,也请按reset。
|
||||||
|
|
||||||
|
连接完成后可以看到「Waiting for message...」的提示。这时候我们就可以进行推送了。
|
||||||
|
|
||||||
|
![](image/2022-02-17-00-00-43.png)
|
||||||
|
|
||||||
|
推送直接使用 PushDeer 的API。
|
||||||
|
|
||||||
|
`POST /message/push`
|
||||||
|
|
||||||
|
|参数|说明|备注|
|
||||||
|
|-|-|-|
|
||||||
|
|pushkey|PushKey|
|
||||||
|
|text|推送消息内容|
|
||||||
|
|type|格式,选填|文本=text,markdown,图片=image,默认为markdown|
|
||||||
|
|
||||||
|
> type 为 image 时,text 中为要发送图片的URL。
|
||||||
|
> type 为 text 时,且 text 中包含 `♪` 字符时,蜂鸣器会发声
|
||||||
|
|
||||||
|
## 独立架设服务端
|
||||||
|
|
||||||
|
如果你希望为智能设备架设单一的服务端,可以单独使用 `pushdeeresp` 镜像:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -e API_KEY=9LKo3 -e MQTT_PORT=1883 -e MQTT_USER=easy -e MQTT_PASSWORD=y0urp@ss - MQTT_BASE_TOPIC=default -p 1883:1883 -p 80:80
|
||||||
|
```
|
||||||
|
|
||||||
|
启动后,支持`MQTT`和`HTTP`两种方式发送消息。
|
||||||
|
|
||||||
|
其中 `HTTP` 方式如下:访问 `IP/send` 即可发送消息,参数为:
|
||||||
|
|
||||||
|
|参数|说明|备注|
|
||||||
|
|-|-|-|
|
||||||
|
|key|API_key|用于限制权限访问|
|
||||||
|
|content|推送消息内容|
|
||||||
|
|type|格式,选填|文本=text,图片=bg_url,默认为text|
|
||||||
|
|topic|推送到主题,选填|会根据type推送到`${topic}_text`或`${topic}_bg_url`通道|
|
||||||
|
162
other_devices/deeresp/deeresp.ino
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#define WIFI_SSID "wifi名称"
|
||||||
|
#define WIFI_PASSWORD "wifi密码"
|
||||||
|
#define MQTT_IP "pushdeer公网IP"
|
||||||
|
#define MQTT_USER "MQTT用户名"
|
||||||
|
#define MQTT_PASSWORD "MQTT密码"
|
||||||
|
#define MQTT_TOPIC "PushDeer pushkey" // 这里填PushDeer的Key
|
||||||
|
#define MQTT_PORT 1883
|
||||||
|
|
||||||
|
|
||||||
|
// ====== 以下不用修改 ===============
|
||||||
|
#define MQTT_CLIENT_NAME "DeerEsp"
|
||||||
|
#define DOWNLOADED_IMG "/download.jpg"
|
||||||
|
#define BEEP_PIN D8
|
||||||
|
|
||||||
|
#include <EspMQTTClient.h>
|
||||||
|
|
||||||
|
EspMQTTClient mclient(
|
||||||
|
WIFI_SSID,
|
||||||
|
WIFI_PASSWORD,
|
||||||
|
MQTT_IP,
|
||||||
|
MQTT_USER,
|
||||||
|
MQTT_PASSWORD,
|
||||||
|
MQTT_CLIENT_NAME,
|
||||||
|
MQTT_PORT
|
||||||
|
);
|
||||||
|
|
||||||
|
#include "SPI.h"
|
||||||
|
#include <TFT_eSPI.h>
|
||||||
|
TFT_eSPI tft = TFT_eSPI();
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
|
#else
|
||||||
|
#include "SPIFFS.h" // Required for ESP32 only
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <TJpg_Decoder.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
mclient.enableDebuggingMessages();
|
||||||
|
|
||||||
|
tft.begin();
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
tft.setTextColor(0xFFFF,0x0000);tft.setCursor(0, 0, 1);tft.setTextSize(2);tft.println("Init ...");
|
||||||
|
Serial.println("tft init");
|
||||||
|
|
||||||
|
if (!SPIFFS.begin()) {
|
||||||
|
Serial.println("SPIFFS initialisation failed!");
|
||||||
|
while (1) yield(); // Stay here twiddling thumbs waiting
|
||||||
|
}
|
||||||
|
Serial.println("SPIFFS init");
|
||||||
|
|
||||||
|
TJpgDec.setJpgScale(2);
|
||||||
|
TJpgDec.setSwapBytes(true);
|
||||||
|
TJpgDec.setCallback(tft_output);
|
||||||
|
|
||||||
|
Serial.println("TJpgDec init");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onConnectionEstablished()
|
||||||
|
{
|
||||||
|
Serial.println("connected");
|
||||||
|
tft.setTextColor(0xFFFF,0x0000);tft.setCursor(0, 0, 1);tft.println("Waiting for message ...");
|
||||||
|
|
||||||
|
mclient.subscribe(String(MQTT_TOPIC)+"_text", [] (const String &payload)
|
||||||
|
{
|
||||||
|
Serial.println(payload);
|
||||||
|
|
||||||
|
if (SPIFFS.exists(DOWNLOADED_IMG) == true) TJpgDec.drawFsJpg(0, 0, DOWNLOADED_IMG);
|
||||||
|
else tft.fillScreen( TFT_BLACK );
|
||||||
|
|
||||||
|
if(payload.indexOf("♪") >= 0) tone(BEEP_PIN, 1000, 100);
|
||||||
|
|
||||||
|
if( payload.length() > 80 ) tft.setTextSize(1);
|
||||||
|
else tft.setTextSize(2);
|
||||||
|
|
||||||
|
tft.setTextColor(0xFFFF,0x0000);tft.setCursor(0, 0, 1);tft.println(payload);
|
||||||
|
});
|
||||||
|
|
||||||
|
mclient.subscribe(String(MQTT_TOPIC)+"_bg_url", [] (const String &payload)
|
||||||
|
{
|
||||||
|
Serial.println(payload);
|
||||||
|
bool ret = file_put_contents(payload, DOWNLOADED_IMG);
|
||||||
|
if (SPIFFS.exists(DOWNLOADED_IMG) == true) {
|
||||||
|
TJpgDec.drawFsJpg(0, 0, DOWNLOADED_IMG);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
mclient.loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_put_contents(String url, String filename) {
|
||||||
|
|
||||||
|
Serial.println("Downloading " + filename + " from " + url);
|
||||||
|
|
||||||
|
// Check WiFi connection
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
|
||||||
|
Serial.print("[HTTP] begin...\n");
|
||||||
|
|
||||||
|
WiFiClient client;
|
||||||
|
HTTPClient http;
|
||||||
|
http.begin(client, url);
|
||||||
|
|
||||||
|
|
||||||
|
Serial.print("[HTTP] GET...\n");
|
||||||
|
int httpCode = http.GET();
|
||||||
|
if (httpCode > 0) {
|
||||||
|
fs::File f = SPIFFS.open(filename, "w+");
|
||||||
|
if (!f) {
|
||||||
|
Serial.println("file open failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||||
|
if (httpCode == HTTP_CODE_OK) {
|
||||||
|
|
||||||
|
int total = http.getSize();
|
||||||
|
int len = total;
|
||||||
|
|
||||||
|
uint8_t buff[128] = { 0 };
|
||||||
|
WiFiClient * stream = http.getStreamPtr();
|
||||||
|
|
||||||
|
while (http.connected() && (len > 0 || len == -1)) {
|
||||||
|
size_t size = stream->available();
|
||||||
|
|
||||||
|
if (size) {
|
||||||
|
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
|
||||||
|
|
||||||
|
f.write(buff, c);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
len -= c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
Serial.print("[HTTP] connection closed or file end.\n");
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||||
|
Serial.print(httpCode);
|
||||||
|
|
||||||
|
}
|
||||||
|
http.end();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
|
||||||
|
{
|
||||||
|
if ( y >= tft.height() ) return 0;
|
||||||
|
tft.pushImage(x, y, w, h, bitmap);
|
||||||
|
return 1;
|
||||||
|
}
|
BIN
other_devices/image/2022-02-16-21-48-45.png
Normal file
After Width: | Height: | Size: 1.9 MiB |
BIN
other_devices/image/2022-02-16-21-59-51.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
other_devices/image/2022-02-16-22-01-05.png
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
other_devices/image/2022-02-16-22-02-36.png
Normal file
After Width: | Height: | Size: 497 KiB |
BIN
other_devices/image/2022-02-16-22-04-25.png
Normal file
After Width: | Height: | Size: 2.1 MiB |
BIN
other_devices/image/2022-02-16-22-07-07.png
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
other_devices/image/2022-02-16-23-32-30.png
Normal file
After Width: | Height: | Size: 388 KiB |
BIN
other_devices/image/2022-02-16-23-35-41.png
Normal file
After Width: | Height: | Size: 529 KiB |
BIN
other_devices/image/2022-02-16-23-38-05.png
Normal file
After Width: | Height: | Size: 326 KiB |
BIN
other_devices/image/2022-02-16-23-42-25.png
Normal file
After Width: | Height: | Size: 494 KiB |
BIN
other_devices/image/2022-02-16-23-44-07.png
Normal file
After Width: | Height: | Size: 771 KiB |
BIN
other_devices/image/2022-02-17-00-00-43.png
Normal file
After Width: | Height: | Size: 458 KiB |
BIN
other_devices/image/2022-02-17-00-43-58.png
Normal file
After Width: | Height: | Size: 957 KiB |
BIN
other_devices/image/deeresp.gif
Normal file
After Width: | Height: | Size: 4.6 MiB |