IoT项目问题:树莓派Picam照片实时显示至000webhost网页遇Pubnub限制
解决树莓派Picam实时图传Pubnub大小限制的方案
我之前做树莓派IoT实时监控项目时,刚好碰到过Pubnub单条消息35KB限制的问题,给你几个亲测有效的解决思路:
方案1:分片传输Base64数据
既然单条消息放不下整图的Base64,那就把数据拆成多个符合大小限制的分片,前端收到所有分片后再重组解码。
树莓派端Python代码示例
import base64 from pubnub.pubnub import PubNub, PublishResult from pubnub.config import PNConfiguration # 初始化Pubnub(替换成你的密钥) pnconfig = PNConfiguration() pnconfig.subscribe_key = "YOUR_SUBSCRIBE_KEY" pnconfig.publish_key = "YOUR_PUBLISH_KEY" pubnub = PubNub(pnconfig) def split_base64(b64_str, chunk_size=30*1024): # 留5KB余量避免超限制 return [b64_str[i:i+chunk_size] for i in range(0, len(b64_str), chunk_size)] # 读取并转换图片为Base64 with open("/home/pi/picam_photo.jpg", "rb") as f: img_bytes = f.read() img_b64 = base64.b64encode(img_bytes).decode("utf-8") # 拆分分片并发布 chunks = split_base64(img_b64) total_chunks = len(chunks) for idx, chunk in enumerate(chunks): pubnub.publish().channel("picam-stream").message({ "type": "image_chunk", "chunk_idx": idx, "total_chunks": total_chunks, "data": chunk }).sync()
前端JavaScript代码示例
const pubnub = new PubNub({ subscribeKey: "YOUR_SUBSCRIBE_KEY", publishKey: "YOUR_PUBLISH_KEY" }); let imageChunks = {}; let totalChunks = 0; pubnub.subscribe({ channels: ["picam-stream"] }); pubnub.addListener({ message: function(m) { const msg = m.message; if (msg.type === "image_chunk") { imageChunks[msg.chunk_idx] = msg.data; totalChunks = msg.total_chunks; // 检查是否所有分片都已收到 if (Object.keys(imageChunks).length === totalChunks) { // 重组Base64字符串 const fullB64 = Object.values(imageChunks).join(""); // 更新图片显示 document.getElementById("picam-image").src = `data:image/jpeg;base64,${fullB64}`; // 重置分片存储 imageChunks = {}; totalChunks = 0; } } } });
注意:可以加个超时机制,如果超过5秒没收到所有分片,就触发重传请求(树莓派端需要监听这个请求),避免丢包导致卡住。
方案2:压缩图片到Pubnub限制内
如果对画质要求不是特别高,直接在树莓派端压缩图片,把Base64后的大小控制在35KB以内是最省事的方法。
树莓派端Python压缩示例(用PIL库)
from PIL import Image import base64 # 打开Picam拍摄的图片 img = Image.open("/home/pi/picam_photo.jpg") # 压缩:调整分辨率+降低质量 img = img.resize((640, 480)) # 缩小分辨率 img.save("/tmp/compressed_photo.jpg", quality=50, format="JPEG") # 降低JPG质量 # 转Base64并发布 with open("/tmp/compressed_photo.jpg", "rb") as f: img_b64 = base64.b64encode(f.read()).decode("utf-8") # 这里直接用你原来的Pubnub发布代码即可
如果用WebP格式,同样质量下体积比JPG小30%-50%,可以试试img.save("/tmp/compressed_photo.webp", quality=50, format="WEBP"),前端直接支持WebP图片。
方案3:替换为MQTT+HTTP文件上传(更稳定的长期方案)
如果Pubnub的限制实在束缚住了,换成MQTT传图片URL,树莓派直接把图片上传到000webhost的主机上,前端加载URL显示,这是工业级实时监控常用的思路。
步骤1:树莓派端上传图片到000webhost
假设你的000webhost主机有一个PHP接口upload.php(放在网站根目录):
<?php $target_dir = "uploads/"; $target_file = $target_dir . uniqid() . ".jpg"; if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) { echo $target_file; // 返回图片的相对URL } else { echo "error"; } ?>
树莓派端Python上传代码:
import requests import paho.mqtt.client as mqtt # 上传图片到000webhost url = "https://your-000webhost-domain.com/upload.php" files = {"file": open("/home/pi/picam_photo.jpg", "rb")} response = requests.post(url, files=files) img_url = response.text # MQTT发布图片URL(用本地或公共MQTT broker,比如Mosquitto) client = mqtt.Client() client.connect("mqtt-broker-address", 1883, 60) client.publish("picam/stream", img_url) client.disconnect()
步骤2:前端监听MQTT并显示图片
const client = new Paho.MQTT.Client("mqtt-broker-address", 1883, "web-client-id"); client.onMessageArrived = function(message) { const imgUrl = message.payloadString; document.getElementById("picam-image").src = `https://your-000webhost-domain.com/${imgUrl}`; }; client.connect({ onSuccess: function() { client.subscribe("picam/stream"); }});
注意:000webhost的免费主机可能有文件大小和流量限制,记得定期清理旧图片。
内容的提问来源于stack exchange,提问作者Nono
相关产品推荐
相关产品推荐

