Switched to Arduino update with
Added OTA updates and DHT22 temp sensors
This commit is contained in:
@ -1,11 +0,0 @@
|
|||||||
[env:esp32-c6-devkitc-1]
|
|
||||||
platform = espressif32
|
|
||||||
board = esp32-c6-devkitc-1
|
|
||||||
framework = arduino, espidf
|
|
||||||
monitor_speed = 115200
|
|
||||||
lib_deps =
|
|
||||||
adafruit/Adafruit PWM Servo Driver Library@2.4.1
|
|
||||||
|
|
||||||
build_flags =
|
|
||||||
-DARDUINO_USB_MODE=1
|
|
||||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
|
||||||
256
reptile_feeder.ino
Normal file
256
reptile_feeder.ino
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
#include <WiFi.h>
|
||||||
|
#include <WebServer.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_PWMServoDriver.h>
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <ArduinoOTA.h> // For Over-the-Air updates
|
||||||
|
#include <Adafruit_Sensor.h> // For DHT sensors
|
||||||
|
#include <DHT.h> // For DHT sensors
|
||||||
|
|
||||||
|
// --- Wi-Fi Configuration ---
|
||||||
|
const char* ssid = "Aussie Broadband 8729";
|
||||||
|
const char* password = "Ffdfmunfca";
|
||||||
|
|
||||||
|
// --- MQTT Configuration ---
|
||||||
|
const char* mqtt_server = "192.168.20.30";
|
||||||
|
const int mqtt_port = 1883;
|
||||||
|
const char* mqtt_user = "mqtt-user";
|
||||||
|
const char* mqtt_password = "sam4jo";
|
||||||
|
const char* mqtt_control_topic = "homeassistant/reptile_feeder/control";
|
||||||
|
const char* mqtt_state_topic = "homeassistant/reptile_feeder/state";
|
||||||
|
const char* ota_password = "sam4jo"; // Password for OTA updates
|
||||||
|
|
||||||
|
// --- Hardware Pins ---
|
||||||
|
#define I2C_SDA_PIN 10
|
||||||
|
#define I2C_SCL_PIN 11
|
||||||
|
#define DHTPIN_1 6 // Pin for the first DHT22 sensor
|
||||||
|
#define DHTPIN_2 7 // Pin for the second DHT22 sensor
|
||||||
|
#define DHTPIN_3 18 // Pin for the third DHT22 sensor
|
||||||
|
#define DHTTYPE DHT22
|
||||||
|
|
||||||
|
// --- Timing Configuration ---
|
||||||
|
#define SENSOR_READ_INTERVAL 30000 // Time in ms between sensor reads (N). 30 seconds.
|
||||||
|
|
||||||
|
// --- Servo Configuration ---
|
||||||
|
#define SERVO_COUNT 16
|
||||||
|
#define SERVO_FREQ 50
|
||||||
|
#define SERVOMIN 150
|
||||||
|
#define SERVOMAX 600
|
||||||
|
|
||||||
|
// --- Global Objects ---
|
||||||
|
WebServer server(80);
|
||||||
|
Adafruit_PWMServoDriver pca = Adafruit_PWMServoDriver();
|
||||||
|
WiFiClient espClient;
|
||||||
|
PubSubClient mqttClient(espClient);
|
||||||
|
DHT dht_sensors[] = { DHT(DHTPIN_1, DHTTYPE), DHT(DHTPIN_2, DHTTYPE), DHT(DHTPIN_3, DHTTYPE) };
|
||||||
|
const int num_sensors = sizeof(dht_sensors) / sizeof(dht_sensors[0]);
|
||||||
|
uint8_t current_angles[SERVO_COUNT];
|
||||||
|
unsigned long previousSensorMillis = 0;
|
||||||
|
|
||||||
|
// --- Function Declarations ---
|
||||||
|
void move_servo_smoothly(uint8_t servo_num, uint8_t target_angle, uint8_t speed);
|
||||||
|
void parse_serial_command(String cmd);
|
||||||
|
void handle_web_move();
|
||||||
|
void handle_root();
|
||||||
|
void reconnectMQTT();
|
||||||
|
void mqtt_callback(char* topic, byte* payload, unsigned int length);
|
||||||
|
void readAndPublishSensors();
|
||||||
|
void setupOTA();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
delay(1000);
|
||||||
|
Serial.println("\nReptile Feeder booting up...");
|
||||||
|
|
||||||
|
// Initialize Servos
|
||||||
|
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
|
||||||
|
pca.begin();
|
||||||
|
pca.setPWMFreq(SERVO_FREQ);
|
||||||
|
for (uint8_t i = 0; i < SERVO_COUNT; i++) {
|
||||||
|
current_angles[i] = 0;
|
||||||
|
uint16_t pulselen = map(0, 0, 180, SERVOMIN, SERVOMAX);
|
||||||
|
pca.setPWM(i, 0, pulselen);
|
||||||
|
}
|
||||||
|
Serial.println("Servos initialized.");
|
||||||
|
|
||||||
|
// Initialize DHT Sensors
|
||||||
|
for (int i = 0; i < num_sensors; i++) {
|
||||||
|
dht_sensors[i].begin();
|
||||||
|
}
|
||||||
|
Serial.println("DHT sensors initialized.");
|
||||||
|
|
||||||
|
// Connect to Wi-Fi
|
||||||
|
Serial.printf("Connecting to %s ", ssid);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println(" Connected!");
|
||||||
|
Serial.print("IP Address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
// Setup MQTT
|
||||||
|
mqttClient.setServer(mqtt_server, mqtt_port);
|
||||||
|
mqttClient.setCallback(mqtt_callback);
|
||||||
|
|
||||||
|
// Setup Web Server
|
||||||
|
server.on("/", handle_root);
|
||||||
|
server.on("/move", handle_web_move);
|
||||||
|
server.begin();
|
||||||
|
Serial.println("Web server started.");
|
||||||
|
|
||||||
|
// Setup OTA Updates
|
||||||
|
setupOTA();
|
||||||
|
Serial.println("OTA ready. Hostname: reptile-feeder");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
ArduinoOTA.handle(); // Handle OTA update requests
|
||||||
|
|
||||||
|
if (!mqttClient.connected()) {
|
||||||
|
reconnectMQTT();
|
||||||
|
}
|
||||||
|
mqttClient.loop();
|
||||||
|
|
||||||
|
server.handleClient();
|
||||||
|
|
||||||
|
if (Serial.available() > 0) {
|
||||||
|
String command = Serial.readStringUntil('\n');
|
||||||
|
command.trim();
|
||||||
|
parse_serial_command(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-blocking sensor read timer
|
||||||
|
unsigned long currentMillis = millis();
|
||||||
|
if (currentMillis - previousSensorMillis >= SENSOR_READ_INTERVAL) {
|
||||||
|
previousSensorMillis = currentMillis;
|
||||||
|
readAndPublishSensors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- MQTT Functions ---
|
||||||
|
void reconnectMQTT() {
|
||||||
|
while (!mqttClient.connected()) {
|
||||||
|
Serial.print("Attempting MQTT connection...");
|
||||||
|
String clientId = "ReptileFeeder-"; clientId += String(random(0xffff), HEX);
|
||||||
|
if (mqttClient.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
|
||||||
|
Serial.println("connected");
|
||||||
|
mqttClient.subscribe(mqtt_control_topic);
|
||||||
|
mqttClient.publish(mqtt_state_topic, "online");
|
||||||
|
} else {
|
||||||
|
Serial.print("failed, rc="); Serial.print(mqttClient.state());
|
||||||
|
Serial.println(" try again in 5 seconds");
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mqtt_callback(char* topic, byte* payload, unsigned int length) {
|
||||||
|
Serial.print("Message arrived on topic: "); Serial.println(topic);
|
||||||
|
JsonDocument doc;
|
||||||
|
DeserializationError error = deserializeJson(doc, payload, length);
|
||||||
|
if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.c_str()); return; }
|
||||||
|
if (!doc.containsKey("servo") || !doc.containsKey("angle")) { Serial.println("Error: JSON must contain 'servo' and 'angle'"); return; }
|
||||||
|
int servo_num = doc["servo"];
|
||||||
|
int angle = doc["angle"];
|
||||||
|
int speed = doc.containsKey("speed") ? doc["speed"].as<int>() : 10;
|
||||||
|
move_servo_smoothly((uint8_t)servo_num, (uint8_t)angle, (uint8_t)speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Sensor Reading Function ---
|
||||||
|
void readAndPublishSensors() {
|
||||||
|
for (int i = 0; i < num_sensors; i++) {
|
||||||
|
float h = dht_sensors[i].readHumidity();
|
||||||
|
float t = dht_sensors[i].readTemperature();
|
||||||
|
|
||||||
|
if (isnan(h) || isnan(t)) {
|
||||||
|
Serial.printf("Failed to read from DHT sensor #%d\n", i + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonDocument doc;
|
||||||
|
doc["temperature"] = t;
|
||||||
|
doc["humidity"] = h;
|
||||||
|
|
||||||
|
char buffer[128];
|
||||||
|
serializeJson(doc, buffer);
|
||||||
|
|
||||||
|
String topic = String(mqtt_state_topic) + "/sensor" + String(i + 1);
|
||||||
|
if (mqttClient.publish(topic.c_str(), buffer)) {
|
||||||
|
Serial.printf("Published to %s: %s\n", topic.c_str(), buffer);
|
||||||
|
} else {
|
||||||
|
Serial.printf("Failed to publish to %s\n", topic.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- OTA Setup Function ---
|
||||||
|
void setupOTA() {
|
||||||
|
ArduinoOTA.setHostname("reptile-feeder");
|
||||||
|
ArduinoOTA.setPassword(ota_password);
|
||||||
|
ArduinoOTA
|
||||||
|
.onStart([]() {
|
||||||
|
String type;
|
||||||
|
if (ArduinoOTA.getCommand() == U_FLASH)
|
||||||
|
type = "sketch";
|
||||||
|
else // U_SPIFFS
|
||||||
|
type = "filesystem";
|
||||||
|
Serial.println("Start updating " + type);
|
||||||
|
})
|
||||||
|
.onEnd([]() {
|
||||||
|
Serial.println("\nEnd");
|
||||||
|
})
|
||||||
|
.onProgress([](unsigned int progress, unsigned int total) {
|
||||||
|
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||||
|
})
|
||||||
|
.onError([](ota_error_t error) {
|
||||||
|
Serial.printf("Error[%u]: ", error);
|
||||||
|
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||||
|
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||||
|
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||||
|
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||||
|
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||||
|
});
|
||||||
|
ArduinoOTA.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- Web, Serial, and Servo Functions (Unchanged) ---
|
||||||
|
void handle_root() { server.send(200, "text/html", "<h1>Reptile Feeder</h1>"); }
|
||||||
|
void handle_web_move() {
|
||||||
|
int s = server.arg("servo").toInt();
|
||||||
|
int a = server.arg("angle").toInt();
|
||||||
|
int v = server.arg("speed").toInt();
|
||||||
|
move_servo_smoothly(s, a, v);
|
||||||
|
server.send(200, "text/plain", "OK");
|
||||||
|
}
|
||||||
|
void parse_serial_command(String cmd) {
|
||||||
|
char buf[50];
|
||||||
|
cmd.toCharArray(buf, 50);
|
||||||
|
int s, a, v;
|
||||||
|
if (sscanf(buf, "move %d %d %d", &s, &a, &v) == 3) {
|
||||||
|
move_servo_smoothly(s, a, v);
|
||||||
|
} else {
|
||||||
|
Serial.println("Invalid format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void move_servo_smoothly(uint8_t servo_num, uint8_t target_angle, uint8_t speed) {
|
||||||
|
if (servo_num >= SERVO_COUNT || target_angle > 180 || speed < 1 || speed > 10) {
|
||||||
|
Serial.println("Error: Move parameters out of range.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t start_angle = current_angles[servo_num];
|
||||||
|
if (target_angle == start_angle) return;
|
||||||
|
uint8_t step_delay = (11 - speed) * 5;
|
||||||
|
Serial.printf("Moving servo %d from %d to %d at speed %d\n", servo_num, start_angle, target_angle, speed);
|
||||||
|
int step = (target_angle > start_angle) ? 1 : -1;
|
||||||
|
for (int i = start_angle; i != (int)target_angle + step; i += step) {
|
||||||
|
uint16_t pulselen = map(i, 0, 180, SERVOMIN, SERVOMAX);
|
||||||
|
pca.setPWM(servo_num, 0, pulselen);
|
||||||
|
delay(step_delay);
|
||||||
|
}
|
||||||
|
current_angles[servo_num] = target_angle;
|
||||||
|
Serial.println("Move complete.");
|
||||||
|
}
|
||||||
180
src/main.cpp
180
src/main.cpp
@ -1,180 +0,0 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <Adafruit_PWMServoDriver.h>
|
|
||||||
#include "esp_zigbee_core.h"
|
|
||||||
|
|
||||||
// --- Configuration ---
|
|
||||||
#define CHANNEL_COUNT 16 // 16 servos
|
|
||||||
#define ZIGBEE_ENDPOINT_START 1
|
|
||||||
|
|
||||||
// PCA9685 Settings
|
|
||||||
Adafruit_PWMServoDriver pca9685 = Adafruit_PWMServoDriver();
|
|
||||||
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz
|
|
||||||
#define SERVO_MIN_PULSE 150 // Corresponds to 0 degrees
|
|
||||||
#define SERVO_MAX_PULSE 600 // Corresponds to 180 degrees
|
|
||||||
#define SERVO_OPEN_ANGLE 90 // Angle in degrees for "open" state
|
|
||||||
#define SERVO_CLOSED_ANGLE 0 // Angle in degrees for "closed" state
|
|
||||||
|
|
||||||
// --- Zigbee Device Setup ---
|
|
||||||
// Basic Zigbee device configuration
|
|
||||||
#define ESP_ZB_PRIMARY_CHANNEL_MASK (1l << 15) // Use Zigbee channel 15
|
|
||||||
#define ESP_ZB_MANUFACTURER_NAME "T3-Labs"
|
|
||||||
#define ESP_ZB_MODEL_NAME "ReptileFeeder.16x"
|
|
||||||
|
|
||||||
// --- Function Declarations ---
|
|
||||||
void move_servo(uint8_t servo_num, uint8_t angle);
|
|
||||||
static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask);
|
|
||||||
static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *message);
|
|
||||||
static esp_err_t zb_action_handler(esp_zb_core_action_signal_t *signal_struct);
|
|
||||||
void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct);
|
|
||||||
|
|
||||||
// --- Main Application ---
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(115200);
|
|
||||||
Wire.begin(); // Default I2C pins for ESP32-C6 are typically GPIO8/GPIO9
|
|
||||||
|
|
||||||
// Initialize PCA9685
|
|
||||||
pca9685.begin();
|
|
||||||
pca9685.setPWMFreq(SERVO_FREQ);
|
|
||||||
Serial.println("PCA9685 Initialized. Setting all servos to closed position.");
|
|
||||||
for (int i = 0; i < CHANNEL_COUNT; i++) {
|
|
||||||
move_servo(i, SERVO_CLOSED_ANGLE);
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
Serial.println("Servos initialized.");
|
|
||||||
|
|
||||||
// Initialize Zigbee stack
|
|
||||||
esp_zb_cfg_t zb_cfg = ESP_ZB_DEFAULT_CFG();
|
|
||||||
zb_cfg.esp_zb_role = ESP_ZB_DEVICE_TYPE_ROUTER;
|
|
||||||
zb_cfg.install_code_policy = false;
|
|
||||||
zb_cfg.nwk_cfg.max_children = 0; // Router doesn't need to manage children
|
|
||||||
esp_zb_init(&zb_cfg);
|
|
||||||
|
|
||||||
// Create On/Off clusters for each servo
|
|
||||||
for (int i = 0; i < CHANNEL_COUNT; ++i) {
|
|
||||||
esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create();
|
|
||||||
|
|
||||||
// On/Off cluster
|
|
||||||
esp_zb_on_off_cluster_cfg_t on_off_cfg;
|
|
||||||
on_off_cfg.on_off = false; // Default to off
|
|
||||||
esp_zb_attribute_list_t *on_off_cluster = esp_zb_on_off_cluster_create(&on_off_cfg);
|
|
||||||
esp_zb_cluster_list_add_cluster(cluster_list, on_off_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
|
|
||||||
|
|
||||||
// Basic cluster
|
|
||||||
esp_zb_basic_cluster_cfg_t basic_cfg;
|
|
||||||
basic_cfg.zcl_version = ESP_ZB_ZCL_VERSION_DEFAULT;
|
|
||||||
basic_cfg.power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_UNKNOWN;
|
|
||||||
esp_zb_attribute_list_t *basic_cluster = esp_zb_basic_cluster_create(&basic_cfg);
|
|
||||||
esp_zb_cluster_list_add_cluster(cluster_list, basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
|
|
||||||
|
|
||||||
// Create an endpoint for the servo
|
|
||||||
esp_zb_endpoint_config_t endpoint_cfg = {
|
|
||||||
.endpoint = (uint8_t)(ZIGBEE_ENDPOINT_START + i),
|
|
||||||
.app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
|
|
||||||
.app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID,
|
|
||||||
.app_device_version = 0
|
|
||||||
};
|
|
||||||
esp_zb_ep_list_add_ep(esp_zb_get_ep_list(), cluster_list, endpoint_cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set Zigbee stack signal handler
|
|
||||||
esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK);
|
|
||||||
ESP_ERROR_CHECK(esp_zb_start(false));
|
|
||||||
esp_zb_set_app_signal_handler(esp_zb_app_signal_handler);
|
|
||||||
|
|
||||||
Serial.println("Zigbee Initialized and Started.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
// The Zigbee stack runs in its own task.
|
|
||||||
// The loop can be used for other non-blocking tasks if needed.
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Function Definitions ---
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Moves a servo to a specific angle.
|
|
||||||
* @param servo_num The servo channel (0-15).
|
|
||||||
* @param angle The target angle (0-180).
|
|
||||||
*/
|
|
||||||
void move_servo(uint8_t servo_num, uint8_t angle)
|
|
||||||
{
|
|
||||||
if (servo_num >= CHANNEL_COUNT || angle > 180) {
|
|
||||||
return; // Invalid input
|
|
||||||
}
|
|
||||||
uint16_t pulselen = map(angle, 0, 180, SERVO_MIN_PULSE, SERVO_MAX_PULSE);
|
|
||||||
pca9685.setPWM(servo_num, 0, pulselen);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Zigbee application signal handler.
|
|
||||||
*/
|
|
||||||
void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct)
|
|
||||||
{
|
|
||||||
uint32_t *p_sg_p = signal_struct->p_app_signal;
|
|
||||||
esp_err_t err_status = signal_struct->esp_err_status;
|
|
||||||
|
|
||||||
switch (signal_struct->signal_type) {
|
|
||||||
case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP:
|
|
||||||
Serial.println("Zigbee stack initialized");
|
|
||||||
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION);
|
|
||||||
break;
|
|
||||||
case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START:
|
|
||||||
case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT:
|
|
||||||
if (err_status == ESP_OK) {
|
|
||||||
Serial.println("Device started, commissioning.");
|
|
||||||
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
|
|
||||||
} else {
|
|
||||||
Serial.println("Failed to initialize Zigbee stack");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ESP_ZB_BDB_SIGNAL_STEERING_COMPLETE:
|
|
||||||
if (err_status == ESP_OK) {
|
|
||||||
esp_zb_ieee_addr_t extended_pan_id;
|
|
||||||
esp_zb_get_extended_pan_id(extended_pan_id);
|
|
||||||
Serial.printf("Successfully joined network. PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
||||||
extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4],
|
|
||||||
extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0]);
|
|
||||||
} else {
|
|
||||||
Serial.printf("Network steering failed, status: %d\n", err_status);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ESP_ZB_ZCL_SIGNAL_SET_ATTR_VALUE:
|
|
||||||
zb_attribute_handler((esp_zb_zcl_set_attr_value_message_t *)p_sg_p);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Serial.printf("Received Zigbee signal: %d\n", signal_struct->signal_type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handles incoming Zigbee attribute changes (e.g., On/Off commands).
|
|
||||||
*/
|
|
||||||
static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *message)
|
|
||||||
{
|
|
||||||
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t endpoint = message->info.dst_endpoint;
|
|
||||||
uint16_t cluster_id = message->info.cluster;
|
|
||||||
uint16_t attr_id = message->attribute.id;
|
|
||||||
bool is_on = false;
|
|
||||||
|
|
||||||
if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF && attr_id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID) {
|
|
||||||
is_on = *(bool *)message->attribute.data.value;
|
|
||||||
uint8_t servo_num = endpoint - ZIGBEE_ENDPOINT_START;
|
|
||||||
|
|
||||||
Serial.printf("Endpoint %d (Servo %d) command: %s\n", endpoint, servo_num, is_on ? "ON" : "OFF");
|
|
||||||
|
|
||||||
if (servo_num < CHANNEL_COUNT) {
|
|
||||||
move_servo(servo_num, is_on ? SERVO_OPEN_ANGLE : SERVO_CLOSED_ANGLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user