You will make the wings react whenever the visitor counter publishes. The example gives you one restrained gesture. Its angles, speed, and character are starting points you must change.
Power matters. Connect servo red to 5V/VIN, brown to GND, and signal to GPIO 18. Keep a common ground. Do not power the servo from the ESP32 3V3 pin.
Four names control the example. SERVO_PIN says where the signal wire goes. The two angles say where the wings rest and open. GESTURE_MS says how long they stay open.
Make one non-blocking gesture
Install the ESP32Servo library. Disconnect USB power before wiring the servo.
Test the safe angle range. Start with
25°and70°. Hold the servo loose before attaching the wings.done when: the horn reaches both positions without buzzing or pushing against the enclosure.
Add movement to the arrival function. The helper calls it only for the topic you subscribed to.
done when: a visitor message opens the wings.
Return without blocking. Record when the wings should fold. Let
loop()return them later instead of usingdelay().done when: climate readings continue publishing during repeated gestures.
Change the choreography. Adjust angle, hold time, easing, or the number of motions. Keep the mechanism within its safe endpoints.
done when: your movement is recognisably different from the reference twitch.
Add these declarations above showVisitorMessage():
// Load the servo tool.
#include <ESP32Servo.h>
// CHANGE THESE to fit your safe movement.
const int SERVO_PIN = 18; // signal wire
const int REST_ANGLE = 25; // wings folded
const int VISITOR_ANGLE = 70; // wings open
const unsigned long GESTURE_MS = 700; // open time
Servo wings;
unsigned long foldAt = 0;
Add this to setup():
// Attach the servo and move to the safe resting angle.
wings.attach(SERVO_PIN);
wings.write(REST_ANGLE);
Extend showVisitorMessage() from tutorial 03. Keep its Serial output, then add these three lines before its closing brace:
// Open now and remember when to fold.
wings.write(VISITOR_ANGLE);
foldAt = millis() + GESTURE_MS;
Serial.println("gesture: visitor wings open");
Use a loop that services MQTT, the gesture timer, and your one-minute climate timer:
void loop() {
// Keep Garden Spine receiving and sending.
spine.loop();
// Fold the wings when their open time is over.
bool timeToFold =
foldAt != 0 && millis() >= foldAt;
if (timeToFold) {
wings.write(REST_ANGLE);
foldAt = 0;
Serial.println("gesture: wings at rest");
}
// Publish climate data on your chosen interval.
bool timeToPublish =
millis() - lastReading > SAMPLE_MS;
if (timeToPublish) {
lastReading = millis();
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
spine.publish(
"temperature",
temperature,
"celsius"
);
spine.publish(
"humidity",
humidity,
"percent-rh"
);
}
}
received garden/entrance/counter/gk-01/count
payload {"device_id":"gk-01","ts":null,"value":185,"unit":"events","fw":"0.4.0"}
gesture: visitor wings open
gesture: wings at restThe wings open when a new visitor-count message arrives, then return after roughly 700 milliseconds. Climate messages continue to appear on the developer view.
If it did not work
- The board resets when the servo moves: disconnect the servo, confirm its power rail, and use a suitable external 5 V supply with a common ground if the board supply is insufficient.
- The servo buzzes at an endpoint: reduce the angle range immediately. The mechanism is pushing beyond its free movement.
- The servo moves at startup only: check that
spine.loop()runs continuously andspine.subscribe()usesshowVisitorMessage. - Climate readings freeze during movement: remove every long
delay(). The return timer above is deliberately non-blocking. - The motion is backward: swap the meanings of
REST_ANGLEandVISITOR_ANGLE, then retest the safe range.