跨设备实现观察者模式:Arduino传感器与远端观测端的联动实现问询
Great question! When your Subject (Arduino with sensors) and Observers (web app/mobile app) live on entirely separate devices, the standard in-memory Observer Pattern won’t work—we need to introduce a network layer to bridge the physical gap. Let’s walk through the most practical, scalable approaches to implement this:
Instead of calling Update() directly in-memory, we’ll replace that direct method call with a network message. The Subject (Arduino) sends a message when sensor data changes, and Observers (web/app) listen for those messages to trigger their own Update() logic.
1. Polling (Observer Pulls Data)
This is the simplest approach—Observers periodically ask the Subject for the latest data.
How to Implement:
- Arduino Side:
- If using an ESP8266/ESP32 (WiFi-enabled), run a tiny HTTP server or push sensor data to a cloud database (like Firebase Realtime Database) whenever readings change.
- For basic setups, use libraries like
ESPAsyncWebServerto expose an endpoint (e.g.,/sensor-data) that returns current readings as JSON.
- Observer Side (Web/App):
- Set a timer (e.g., every 2-5 seconds) to send an HTTP GET request to the Arduino’s endpoint or cloud database.
- When new data is received, call your Observer’s
Update()method to refresh the display.
Pros & Cons:
- ✅ Super easy to implement, no complex messaging infrastructure needed
- ❌ Higher latency (you only get updates on the next poll)
- ❌ Wastes bandwidth if data hasn’t changed between polls
2. MQTT Publish/Subscribe (Best for IoT Scenarios)
MQTT is a lightweight messaging protocol designed for IoT, and it’s perfect for this use case. We’ll use an MQTT broker as a middleman: the Arduino publishes sensor data to a "topic", and all Observers subscribe to that topic to receive updates instantly.
How to Implement:
- Arduino Side:
- Use a library like
PubSubClientto connect to an MQTT broker (you can use a free public one like Eclipse Mosquitto, or host your own). - When sensor readings change, serialize the data to JSON and publish it to a specific topic (e.g.,
arduino/sensors/environment). This acts as yourNotify()method.
- Use a library like
- Observer Side:
- Web apps use MQTT over WebSocket (libraries like
paho-mqtt.js) to connect to the broker and subscribe to the topic. - Mobile apps use native MQTT libraries (e.g.,
paho.mqtt.androidfor Android) to do the same. - When a message is received, parse the JSON and trigger the Observer’s
Update()method.
- Web apps use MQTT over WebSocket (libraries like
Example Code Snippets:
Arduino (ESP32)
#include <WiFi.h> #include <PubSubClient.h> // Replace with your WiFi credentials const char* ssid = "YOUR_WIFI_SSID"; const char* password = "YOUR_WIFI_PASSWORD"; // Public MQTT broker const char* mqttBroker = "test.mosquitto.org"; const int mqttPort = 1883; const char* mqttTopic = "arduino/sensors/environment"; WiFiClient espClient; PubSubClient client(espClient); void setup() { Serial.begin(115200); // Connect to WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected to WiFi"); // Connect to MQTT broker client.setServer(mqttBroker, mqttPort); while (!client.connected()) { Serial.println("Connecting to MQTT..."); if (client.connect("ArduinoSensorNode")) { Serial.println("Connected to MQTT broker"); } else { Serial.print("Failed with state: "); Serial.println(client.state()); delay(2000); } } } void loop() { client.loop(); // Maintain MQTT connection // Simulate sensor reading change (replace with actual sensor code) float temperature = random(20, 30) + (random(0, 100) / 100.0); float humidity = random(50, 70) + (random(0, 100) / 100.0); // Serialize data to JSON (our "Update" payload) char payload[120]; snprintf(payload, sizeof(payload), "{\"temperature\":%.2f,\"humidity\":%.2f}", temperature, humidity); // Publish data (this is our network-based Notify()) client.publish(mqttTopic, payload); Serial.print("Published: "); Serial.println(payload); delay(5000); // Update every 5 seconds }
Web App (JavaScript)
// Using paho-mqtt.js (include via script tag or npm) const client = new Paho.MQTT.Client("test.mosquitto.org", 8080, "WebObserverClient"); // Callback when a message arrives (our Update() method) client.onMessageArrived = function(message) { const sensorData = JSON.parse(message.payloadString); updateDisplay(sensorData.temperature, sensorData.humidity); }; // Connect to MQTT broker client.connect({ onSuccess: () => { console.log("Connected to MQTT broker"); client.subscribe("arduino/sensors/environment"); }, onFailure: (error) => { console.log("Connection failed: ", error.errorMessage); } }); // Update UI (Observer's Update() implementation) function updateDisplay(temp, humidity) { document.getElementById("temp-display").textContent = `${temp}°C`; document.getElementById("humidity-display").textContent = `${humidity}%`; }
Pros & Cons:
- ✅ Low latency (updates pushed instantly when data changes)
- ✅ Bandwidth-efficient (only sends messages when needed)
- ✅ Scalable (supports hundreds/thousands of Observers)
- ❌ Requires an MQTT broker (but free public options are widely available)
3. WebSocket Long Connections (Direct Bidirectional Communication)
If you want direct communication between the Arduino and Observers without a middleman, WebSockets are a good choice. They maintain a persistent connection, allowing the Arduino to push updates directly to connected Observers.
How to Implement:
- Arduino Side: Use a library like
WebSocketsto run a WebSocket server, or connect to a WebSocket server hosted on your web app’s backend. - Observer Side: Use the browser’s native
WebSocketAPI (web) or platform-specific WebSocket libraries (mobile) to connect to the Arduino’s server. When the Arduino sends a message, triggerUpdate().
Pros & Cons:
- ✅ Ultra-low latency (direct connection)
- ✅ Bidirectional communication (Observers can send commands back to Arduino if needed)
- ❌ Less scalable for many Observers (you have to manage multiple connections on the Arduino)
- ❌ More complex to handle reconnections if the network drops
Key Considerations for All Approaches
- Data Serialization: Always use a standard format like JSON to package sensor data—this makes it easy for Observers to parse regardless of their platform.
- Error Handling & Reconnection: Network connections can drop! Implement reconnection logic (most MQTT/WebSocket libraries have built-in support) to ensure the Subject and Observers stay connected.
- Security: If your sensor data is sensitive, use encrypted connections:
- MQTT: Use MQTT over TLS (port 8883)
- HTTP/WebSocket: Use HTTPS/WSS instead of plain HTTP/WSS
内容的提问来源于stack exchange,提问作者Camilo Marraui

