4G FS800DTU上传图像至巴法云

目录

1 前言

2 准备工作

2.1 硬件准备

2.2 软件环境

2.3 硬件连接

3 实现方案

4 巴法云平台账号创建与设备联网配置

4.1 创建账号

4.2 进入巴法云

4.3 获取联网参数

4.4 连接巴法云

5 拍照上传至巴法云

6 ESP32-CAM程序

7 总结


1 前言

        巴法云(Bemfa Cloud)是一个专注于 轻量级物联网(IOT)开发的云平台,主要面向智能家居、远程控制、数据监测等场景,提供 MQTT协议 支持,帮助开发者快速实现设备与云端的数据交互。

        FS800DTU核心板是基于飞思创4G Cat.1模组设计的,上面集成了DC-DC、SIM卡、天线和串口电平转换电路,支持5-16V供电输入,我们不需要额外的设计,核心板串口可与单片机直连,再接上天线、SIM卡和供电就可以进行数据交互了。

        FS800DTU支持4路Socket,支持TCP/UDP/HTTP/MQTT等通信协议,适配了阿里云、OneNET等物联网平台。不需要一条一条发AT指令配置,出厂自带YunDTU固件,通过飞思创提供的配置工具直接填写联网参数即可,连上服务器后数据直接透传,小白也能快速上手。

        产品链接:点击跳转

2 准备工作

2.1 硬件准备

  1. FS800DTU核心板(型号:FS-MCore-F8A2M1
  2. 4G物联卡一张,移动,联通,电信均可。
  3. USB转TTL模块,若干根杜邦线。
  4. 4G天线一根。
  5. ESP32-CAM(MicroPython 含摄像头驱动固件)

2.2 软件环境

  1. 巴法云平台
  2. SerialPort_To_Network_ConfigTools 配置工具(用于配置 FS800DTU)
  3. Thonny(ESP32-CAM 开发环境)

2.3 硬件连接

        电源注意事项:在为 ESP32 - CAM 和 FS800DTU 供电时,建议尽量使用 5V/2A 的电源。若供电不足,可能会导致 ESP32 - CAM 拍照失败,以及 FS800DTU 无法正常注册网络,频繁重启。

3 实现方案

        ESP32-CAM 开启 AP 模式并启动 web 服务器,手机连接其生成的 WiFi,在浏览器访问拍照控制界面。按下拍照按钮后,ESP32 - CAM 进行拍照,若拍照数据成功通过串口发送给 FS800DTU,则提示拍照成功,FS800DTU 将收到的照片传输至巴法云;若发送失败,则提示拍照失败。

4 巴法云平台账号创建与设备联网配置

4.1 创建账号

        打开巴法云主页:巴法科技&巴法云-巴法设备云-巴法物联网云平台,登录巴法云平台,有账号的话直接点击登录,没有账号就注册后登录。

4.2 进入巴法云

(1)点击图存储

(2)新建主题,获取私钥

        私钥:b9d8f1671xxxxxxxxe0d3b33e60,该私钥将用于图片上传接口API的 HTTP 头部字段中

4.3 获取联网参数

(1)打开巴法云文档中心简介 | 巴法文档中心,选择图片接口->图片上传接口一

        API: https://images.bemfa.com/upload/v1/upimages.php

        HTTP头部字段:

        Authorization: b9d8f1671xxxxxxxxe0d3b33e60(使用时改为自己的巴法云的私钥)

        Authtopic: test1(使用时改为自己的定义的主题

        Content-Type: image/jpg

4.4 连接巴法云

        使用USB转TTL连接FS800DTU,打开 SerialPort_To_Network_ConfigTools 配置工具,选择 HTTP 协议,并将请求类型设置为 POST。接着,将获取的 API 地址填写到 URL 字段中。 Header 部分,按照 4.3 章节提供的 HTTP 头部字段进行填写,字段之间使用回车换行符([0D][0A])进行分隔,具体格式:Authorization: b9d8f1671xxxxxxxxe0d3b33e60[0D][0A]Authtopic: test1[0D][0A]Content-Type: image/jpg[0D][0A]。

        将配置好参数的FS800DTU与ESP32-CAM进行连接。

5 拍照上传至巴法云

(1)打开Thonny运行程序,获取ESP32-CAM的IP地址。

(2)使用手机连接连接ESP32-CAM的WiFi

(3)浏览器输入ESP32-CAM的IP地址192.168.4.1进入拍照界面。

        注意事项:如果连上WiFi之后发现无法访问该网页,可以尝试关闭手机移动数据,并且关闭手机WiFi设置里的“网络优化”或者“自动切换移动数据”功能。

(4) 点击网页上的拍照按钮,ESP32-CAM会进行拍照,拍照成功后提示拍照完成,失败则提示失败。

(5)提示拍照完成后,刷新巴法云界面,查看上传到图片。

 

6 ESP32-CAM程序

        主程序:负责初始化网络和启动 Web 服务器。

def main():
    try:
        # 初始化网络
        network_manager = NetworkManager()
        network_manager.start_ap(CONFIG['AP_SSID'])
        
        # 启动Web服务器
        server = WebServer(CONFIG['PORT'])
        server.start()
        
    except Exception as e:
        print('Fatal error:', e)
    finally:
        print('System shutdown')

        WebServer 类:实现了一个简单的 Web 服务器,用于接收和处理 HTTP 请求,执行捕获图像并通过串口发送,并通过网络通信与客户端进行数据交互。

class WebServer:
    def __init__(self, port):
        """
        初始化 WebServer 类
        """
        self.port = port
        self.socket = socket.socket()  # 创建一个 socket 对象,用于网络通信
        self.uart = UART(2, baudrate=CONFIG['UART_BAUDRATE'],
                         tx=CONFIG['UART_TX_PIN'], rx=CONFIG['UART_RX_PIN'])  # 初始化 UART 对象,用于串口通信
        
    def load_html(self, filename):
        """
        加载 HTML 文件
        """
        try:
            with open(filename, 'r') as file:
                return file.read()  # 读取 HTML 文件内容并返回
        except Exception as e:
            print(f'Error reading HTML file {filename}: {e}')
            return '<!DOCTYPE html><html><body>Error loading page</body></html>'  # 返回错误提示 HTML
    
    def create_response(self, content_type, body, status_code=200):
        """
        创建 HTTP 响应
        """
        status_text = 'OK' if status_code == 200 else 'Not Found'  # 根据状态码确定状态文本
        response = 'HTTP/1.1 ' + str(status_code) + ' ' + status_text + '\r\n'
        response += 'Content-Type: ' + content_type + '\r\n'
        response += 'Connection: close\r\n'
        response += '\r\n'
        response += body
        return response
    
    def handle_request(self, request):
        """
        处理 HTTP 请求
        """
        # GET 请求处理
        if request.startswith('GET'):
            return self.create_response('text/html', self.load_html(CONFIG['HTML_FILE']))  # 加载并返回 HTML 文件内容
        
        # POST 请求处理
        elif request.startswith('POST'):
            headers_end = request.find('\r\n\r\n') + 4  # 找到请求头的结束位置
            if headers_end >= len(request):
                return self.create_response('text/plain', 'Error: No request body found', 400)  # 请求体不存在,返回错误响应
            
            body = request[headers_end:].strip()  # 提取请求体内容
            print('Received body:', body)
            
            if body == 'capture':
                try:
                    image_data = CameraController.capture_image()  # 调用摄像头控制器捕获图像
                    self.uart.write(image_data)  # 将图像数据通过串口发送
                    print('Photo captured and sent via UART')
                    return self.create_response('application/javascript', 'alert("拍照完成");')  # 返回拍照完成的提示
                except Exception as e:
                    print('Capture failed:', e)
                    return self.create_response('application/javascript', 'alert("拍照失败");', 500)  # 返回拍照失败的提示
            else:
                return self.create_response('application/javascript', 'alert("无效指令");')  # 返回无效指令的提示
        
        # 其他请求
        else:
            return self.create_response('text/plain', 'Not Found', 404)  # 返回 404 错误响应
    
    def start(self):
        """
        启动 Web 服务器
        """
        addr = socket.getaddrinfo('0.0.0.0', self.port)[0][-1]  # 获取服务器地址
        self.socket.bind(addr)  # 绑定地址到 socket
        self.socket.listen(1)  # 开始监听,设置最大连接数为 1
        print(f'Web server started on {addr}')
        
        try:
            while True:
                cl, addr = self.socket.accept()  # 接受客户端连接
                print('Client connected from', addr)
                
                try:
                    request = cl.recv(1024).decode('utf-8')  # 接收客户端请求
                    if not request:
                        continue
                    
                    print('Request:', request.splitlines()[0])  # 打印请求的第一行
                    response = self.handle_request(request)  # 处理请求并获取响应
                    cl.send(response.encode('utf-8'))  # 发送响应给客户端
                except Exception as e:
                    print('Request handling error:', e)
                finally:
                    cl.close()  # 关闭客户端连接
        except KeyboardInterrupt:
            print('Server stopped by user')  # 用户中断服务器时打印提示
        finally:
            self.socket.close()  # 关闭服务器 socket

        HTML页面:提供了一个简单的拍照界面,点击“拍照”按钮后,通过 POST 请求向服务器发送拍照指令,并根据响应状态显示成功或错误消息,同时执行服务器返回的 JavaScript 代码。

        说明:由于ESP32-CAM没有板载按键,这里使用手机访问ESP32-CAM的Web服务器点击拍照来充当拍照按键使用。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>ESP32-CAM</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        /* 页面样式 */
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        button {
            padding: 10px 20px;
            font-size: 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        button:disabled {
            background-color: #cccccc;
        }
        #status {
            margin-top: 20px;
            padding: 10px;
            border-radius: 4px;
        }
        .success { background-color: #dff0d8; color: #3c763d; }
        .error { background-color: #f2dede; color: #a94442; }
    </style>
</head>
<body>
    <h1>ESP32-CAM拍照界面</h1>
    
    <!-- 拍照按钮 -->
    <button id="captureBtn">拍照</button>
    <!-- 状态显示区域 -->
    <div id="status"></div>

<script>
    // 为拍照按钮添加点击事件监听器
    document.getElementById('captureBtn').addEventListener('click', async function() {
        const btn = this; // 引用按钮本身
        const status = document.getElementById('status'); // 引用状态显示区域
        
        try {
            // 发送 POST 请求到服务器根路径,请求体为 'capture'
            const response = await fetch('/', {
                method: 'POST',
                headers: { 'Content-Type': 'text/plain' },
                body: 'capture'
            });
            
            // 检查响应状态
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            
            // 读取响应文本
            const js = await response.text();
            status.className = 'success'; // 设置状态样式为成功
            status.textContent = '拍照指令已发送'; // 显示成功消息
            
            // 执行返回的 JavaScript 代码
            try {
                new Function(js)();
            } catch(e) {
                console.error('JS执行错误:', e); // 捕获并打印 JavaScript 执行错误
            }
            
            // 1秒后自动清除状态消息
            setTimeout(() => {
                status.textContent = '';
                status.className = '';
            }, 1000); 
            
        } catch(error) {
            // 捕获并处理请求失败的情况
            console.error('拍照请求失败:', error);
            status.className = 'error'; // 设置状态样式为错误
            status.textContent = '拍照失败: ' + error.message; // 显示错误消息
            
            // 错误信息3秒后清除
            setTimeout(() => {
                status.textContent = '';
                status.className = '';
            }, 3000);
        } finally {
            btn.disabled = false; // 无论成功或失败,都重新启用按钮
        }
    });
</script>
</body>
</html>

7 总结

        本文介绍了用 ESP32 - CAM 搭配 FS800DTU 上传图像至巴法云的方法,感谢大家的观看。若您对本文章有任何不清楚的地方,可以私信或者在评论区留言,我们看到会及时回复您!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值