main.cpp
// Sparrow Zigbee nodes: switch (end device) and light (router)
 
#include <Arduino.h>
#include "Zigbee.h"
 
constexpr uint8_t SWITCH_PIN = 9;
constexpr uint32_t FACTORY_RESET_HOLD_MS = 3000;
constexpr uint32_t BUTTON_DEBOUNCE_MS = 50;
 
#if defined(SPARROW_SWITCH)
 
#include "ep/ZigbeeSwitch.h"
 
constexpr uint8_t SWITCH_ENDPOINT = 1;
 
ZigbeeSwitch switchEp(SWITCH_ENDPOINT);
 
static bool lastButtonLevel = HIGH;
static uint32_t lastButtonChangeMs = 0;
static uint32_t pressStartMs = 0;
static bool longPressHandled = false;
 
void setup() {
  Serial.begin(115200);
  pinMode(SWITCH_PIN, INPUT_PULLUP);
 
  switchEp.setManufacturerAndModel("Sparrow", "Switch");
  switchEp.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100);
 
  Zigbee.addEndpoint(&switchEp);
  Serial.println("Starting Zigbee (switch)...");
  if (!Zigbee.begin()) {
    Serial.println("Zigbee failed to start, restarting…");
    delay(1000);
    ESP.restart();
  }
 
  Serial.print("Joining network");
  while (!Zigbee.connected()) {
    Serial.print(".");
    delay(200);
  }
  Serial.println("\nJoined!");
}
 
void loop() {
  uint32_t now = millis();
  bool reading = digitalRead(SWITCH_PIN);
 
  if (reading != lastButtonLevel && (now - lastButtonChangeMs) >= BUTTON_DEBOUNCE_MS) {
    lastButtonChangeMs = now;
    lastButtonLevel = reading;
    if (reading == LOW) {
      pressStartMs = now;
      longPressHandled = false;
    } else {
      if (pressStartMs != 0 && !longPressHandled) {
        Serial.println("Switch pressed → toggling bound light");
        switchEp.lightToggle();
      }
      pressStartMs = 0;
    }
  }
 
  if (lastButtonLevel == LOW && pressStartMs != 0 && !longPressHandled && (now - pressStartMs) >= FACTORY_RESET_HOLD_MS) {
    longPressHandled = true;
    Serial.println("Factory reset Zigbee (switch)...");
    Zigbee.factoryReset(true);
  }
 
  delay(10);
}
 
#elif defined(SPARROW_LIGHT)
 
#include <Adafruit_NeoPixel.h>
#include "ep/ZigbeeLight.h"
 
constexpr uint8_t LIGHT_ENDPOINT = 1;
constexpr uint8_t NEOPIXEL_PIN = 3;
constexpr uint8_t NEOPIXEL_COUNT = 1;
constexpr uint8_t NEOPIXEL_BRIGHTNESS = 48;
constexpr uint32_t IDENTIFY_BLINK_INTERVAL_MS = 250;
constexpr uint32_t IDENTIFY_DEFAULT_DURATION_MS = 5000;
 
ZigbeeLight lightEp(LIGHT_ENDPOINT);
Adafruit_NeoPixel statusPixel(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
 
static bool lightState = false;
static bool lastButtonLevel = HIGH;
static uint32_t lastButtonChangeMs = 0;
static uint32_t pressStartMs = 0;
static bool longPressHandled = false;
 
static bool identifyActive = false;
static bool identifyBlinkOn = false;
static bool identifyReset = false;
static uint32_t identifyDeadlineMs = 0;
static uint32_t identifyLastToggleMs = 0;
 
static void refreshNeoPixel() {
  if (identifyActive) {
    if (identifyBlinkOn) {
      statusPixel.setPixelColor(0, statusPixel.Color(0, 0, 255));  // blue during identify
    } else {
      statusPixel.clear();
    }
  } else {
    if (lightState) {
      statusPixel.setPixelColor(0, statusPixel.Color(255, 200, 80));  // warm white
    } else {
      statusPixel.clear();
    }
  }
  statusPixel.show();
}
 
static void handleLightChange(bool on) {
  lightState = on;
  if (!identifyActive) {
    refreshNeoPixel();
  }
}
 
static void handleIdentify(uint16_t seconds) {
  if (seconds == 0) {
    identifyActive = false;
    identifyReset = true;
    return;
  }
 
  uint32_t durationMs = seconds > 0 ? static_cast<uint32_t>(seconds) * 1000UL : IDENTIFY_DEFAULT_DURATION_MS;
  if (durationMs == 0) {
    durationMs = IDENTIFY_DEFAULT_DURATION_MS;
  }
 
  identifyDeadlineMs = millis() + durationMs;
  identifyLastToggleMs = 0;
  identifyBlinkOn = false;
  identifyActive = true;
  identifyReset = true;
}
 
void setup() {
  Serial.begin(115200);
  pinMode(SWITCH_PIN, INPUT_PULLUP);
 
  statusPixel.begin();
  statusPixel.setBrightness(NEOPIXEL_BRIGHTNESS);
  statusPixel.clear();
  statusPixel.show();
 
  lightEp.setManufacturerAndModel("Sparrow", "Light");
  lightEp.onLightChange(handleLightChange);
  lightEp.onIdentify(handleIdentify);
 
  Zigbee.addEndpoint(&lightEp);
  Serial.println("Starting Zigbee (light)...");
  if (!Zigbee.begin()) {
    Serial.println("Zigbee failed to start, restarting…");
    delay(1000);
    ESP.restart();
  }
 
  Serial.print("Joining network");
  while (!Zigbee.connected()) {
    Serial.print(".");
    delay(200);
  }
  Serial.println("\nJoined!");
 
  lightEp.setLight(false);
}
 
void loop() {
  uint32_t now = millis();
 
  if (identifyReset) {
    identifyReset = false;
    refreshNeoPixel();
  }
 
  if (identifyActive) {
    if ((int32_t)(identifyDeadlineMs - now) <= 0) {
      identifyActive = false;
      refreshNeoPixel();
    } else if (identifyLastToggleMs == 0 || (now - identifyLastToggleMs) >= IDENTIFY_BLINK_INTERVAL_MS) {
      identifyLastToggleMs = now;
      identifyBlinkOn = !identifyBlinkOn;
      refreshNeoPixel();
    }
  }
 
  bool reading = digitalRead(SWITCH_PIN);
  if (reading != lastButtonLevel && (now - lastButtonChangeMs) >= BUTTON_DEBOUNCE_MS) {
    lastButtonChangeMs = now;
    lastButtonLevel = reading;
    if (reading == LOW) {
      pressStartMs = now;
      longPressHandled = false;
    } else {
      if (pressStartMs != 0 && !longPressHandled) {
        bool newState = !lightState;
        Serial.printf("Local light toggle → %s\n", newState ? "ON" : "OFF");
        lightEp.setLight(newState);
      }
      pressStartMs = 0;
    }
  }
 
  if (lastButtonLevel == LOW && pressStartMs != 0 && !longPressHandled && (now - pressStartMs) >= FACTORY_RESET_HOLD_MS) {
    longPressHandled = true;
    identifyActive = false;
    identifyReset = true;
    Serial.println("Factory reset Zigbee (light)...");
    Zigbee.factoryReset(true);
  }
 
  delay(10);
}
 
#else
 
#error "Define SPARROW_SWITCH or SPARROW_LIGHT for this firmware."
 
#endif
iothings/laboratoare/2025_code/lab5_2.txt · Last modified: 2025/10/22 11:34 by dan.tudose
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0