ZigbeeElectricalMeasurement

About

The ZigbeeElectricalMeasurement class provides an endpoint for electrical measurement devices in Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for power monitoring and electrical measurement.

Features: * AC and DC electrical measurements * Voltage, current, and power monitoring * Power factor measurement * Multi-phase support * Configurable measurement ranges * Automatic reporting capabilities * Integration with common endpoint features (binding, OTA, etc.) * Zigbee HA standard compliance

Use Cases: * Smart power monitoring * Energy monitoring systems * Solar panel monitoring * Battery monitoring systems * Electrical load monitoring

Common API

Constructor

ZigbeeElectricalMeasurement

Creates a new Zigbee electrical measurement endpoint.

ZigbeeElectricalMeasurement(uint8_t endpoint);
  • endpoint - Endpoint number (1-254)

DC Electrical Measurement

addDCMeasurement

Adds a DC measurement type to the endpoint.

bool addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type);
  • measurement_type - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)

This function will return true if successful, false otherwise.

setDCMeasurement

Sets the DC measurement value for a specific measurement type.

bool setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, int16_t value);
  • measurement_type - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)

  • value - Measurement value

This function will return true if successful, false otherwise.

setDCMinMaxValue

Sets the minimum and maximum values for a DC measurement type.

bool setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, int16_t min, int16_t max);
  • measurement_type - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)

  • min - Minimum value

  • max - Maximum value

This function will return true if successful, false otherwise.

setDCMultiplierDivisor

Sets the multiplier and divisor for scaling DC measurements.

bool setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, uint16_t multiplier, uint16_t divisor);
  • measurement_type - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)

  • multiplier - Multiplier value

  • divisor - Divisor value

This function will return true if successful, false otherwise.

setDCReporting

Sets the reporting configuration for DC measurements.

bool setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type, uint16_t min_interval, uint16_t max_interval, int16_t delta);
  • measurement_type - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)

  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change required to trigger a report

This function will return true if successful, false otherwise.

reportDC

Manually reports a DC measurement value.

bool reportDC(ZIGBEE_DC_MEASUREMENT_TYPE measurement_type);
  • measurement_type - DC measurement type constant (ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_DC_MEASUREMENT_TYPE_POWER)

This function will return true if successful, false otherwise.

AC Electrical Measurement

addACMeasurement

Adds an AC measurement type for a specific phase.

bool addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type);
  • measurement_type - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)

  • phase_type - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)

This function will return true if successful, false otherwise.

setACMeasurement

Sets the AC measurement value for a specific measurement type and phase.

bool setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, int32_t value);
  • measurement_type - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)

  • phase_type - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)

  • value - Measurement value

This function will return true if successful, false otherwise.

setACMinMaxValue

Sets the minimum and maximum values for an AC measurement type and phase.

bool setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, int32_t min, int32_t max);
  • measurement_type - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)

  • phase_type - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)

  • min - Minimum value

  • max - Maximum value

This function will return true if successful, false otherwise.

setACMultiplierDivisor

Sets the multiplier and divisor for scaling AC measurements.

bool setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, uint16_t multiplier, uint16_t divisor);
  • measurement_type - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)

  • multiplier - Multiplier value

  • divisor - Divisor value

This function will return true if successful, false otherwise.

setACPowerFactor

Sets the power factor for a specific phase.

bool setACPowerFactor(ZIGBEE_AC_PHASE_TYPE phase_type, int8_t power_factor);
  • phase_type - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)

  • power_factor - Power factor value (-100 to 100)

This function will return true if successful, false otherwise.

setACReporting

Sets the reporting configuration for AC measurements.

bool setACReporting(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type, uint16_t min_interval, uint16_t max_interval, int32_t delta);
  • measurement_type - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)

  • phase_type - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)

  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change required to trigger a report

This function will return true if successful, false otherwise.

reportAC

Manually reports an AC measurement value.

bool reportAC(ZIGBEE_AC_MEASUREMENT_TYPE measurement_type, ZIGBEE_AC_PHASE_TYPE phase_type);
  • measurement_type - AC measurement type constant (ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_MEASUREMENT_TYPE_POWER_FACTOR, ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY)

  • phase_type - Phase type constant (ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, ZIGBEE_AC_PHASE_TYPE_A, ZIGBEE_AC_PHASE_TYPE_B, ZIGBEE_AC_PHASE_TYPE_C)

This function will return true if successful, false otherwise.

Example

DC Electrical Measurement

// Copyright 2025 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @brief This example demonstrates a Zigbee DC electrical measurement sensor.
 *
 * The example shows how to use the Zigbee library to create an end device that measures
 * DC voltage, current and power using the Electrical Measurement cluster.
 *
 * The device reports:
 * - DC voltage in millivolts (0-5000mV)
 * - DC current in milliamps (0-1000mA)
 * - DC power in milliwatts (0-5000mW)
 *
 * Proper Zigbee mode must be selected in Tools->Zigbee mode
 * and also the correct partition scheme must be selected in Tools->Partition Scheme.
 *
 * Please check the README.md for instructions and more detailed description.
 *
 * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
 */

#ifndef ZIGBEE_MODE_ED
#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
#endif

#include "Zigbee.h"

/* Zigbee DC measurement device configuration */
#define DC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER 1

uint8_t analogPin = A0;
uint8_t button = BOOT_PIN;

ZigbeeElectricalMeasurement zbElectricalMeasurement = ZigbeeElectricalMeasurement(DC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER);

void setup() {
  Serial.begin(115200);
  Serial.println("Starting...");

  // Init button switch
  pinMode(button, INPUT_PULLUP);

  // Set analog resolution to 10 bits
  analogReadResolution(10);

  // Optional: set Zigbee device name and model
  zbElectricalMeasurement.setManufacturerAndModel("Espressif", "ZigbeeElectricalMeasurementDC");

  // Add analog clusters to Zigbee Analog according your needs
  zbElectricalMeasurement.addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE);
  zbElectricalMeasurement.addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT);
  zbElectricalMeasurement.addDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_POWER);

  // // Optional: set Min/max values for the measurements
  zbElectricalMeasurement.setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, 0, 5000);  // 0-5.000V
  zbElectricalMeasurement.setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, 0, 1000);  // 0-1.000A
  zbElectricalMeasurement.setDCMinMaxValue(ZIGBEE_DC_MEASUREMENT_TYPE_POWER, 0, 5000);    // 0-5.000W

  // // Optional: set Multiplier/Divisor for the measurements
  zbElectricalMeasurement.setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, 1, 1000);  // 1/1000 = 0.001V (1 unit of measurement = 0.001V = 1mV)
  zbElectricalMeasurement.setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, 1, 1000);  // 1/1000 = 0.001A (1 unit of measurement = 0.001A = 1mA)
  zbElectricalMeasurement.setDCMultiplierDivisor(ZIGBEE_DC_MEASUREMENT_TYPE_POWER, 1, 1000);    // 1/1000 = 0.001W (1 unit of measurement = 0.001W = 1mW)

  // Add endpoints to Zigbee Core
  Zigbee.addEndpoint(&zbElectricalMeasurement);

  Serial.println("Starting Zigbee...");
  // When all EPs are registered, start Zigbee in End Device mode
  if (!Zigbee.begin()) {
    Serial.println("Zigbee failed to start!");
    Serial.println("Rebooting...");
    ESP.restart();
  } else {
    Serial.println("Zigbee started successfully!");
  }
  Serial.println("Connecting to network");
  while (!Zigbee.connected()) {
    Serial.print(".");
    delay(100);
  }
  Serial.println("Connected");

  // Optional: Add reporting for DC measurements (this is overridden by HomeAssistant ZHA if connected to its network)
  zbElectricalMeasurement.setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, 0, 30, 10);  // report every 30 seconds if value changes by 10 (0.1V)
  zbElectricalMeasurement.setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, 0, 30, 10);  // report every 30 seconds if value changes by 10 (0.1A)
  zbElectricalMeasurement.setDCReporting(ZIGBEE_DC_MEASUREMENT_TYPE_POWER, 0, 30, 10);    // report every 30 seconds if value changes by 10 (0.1W)
}

void loop() {
  static uint32_t timeCounter = 0;
  static uint8_t randomizer = 0;
  // Read ADC value and update the analog value every 2s
  if (!(timeCounter++ % 20)) {  // delaying for 100ms x 20 = 2s
    int16_t voltage_mv = (int16_t)(analogReadMilliVolts(analogPin));
    int16_t current_ma = randomizer;                    //0-255mA
    int16_t power_mw = voltage_mv * current_ma / 1000;  //calculate power in mW
    Serial.printf("Updating DC voltage to %d mV, current to %d mA, power to %d mW\r\n", voltage_mv, current_ma, power_mw);
    zbElectricalMeasurement.setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE, voltage_mv);
    zbElectricalMeasurement.setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT, current_ma);
    zbElectricalMeasurement.setDCMeasurement(ZIGBEE_DC_MEASUREMENT_TYPE_POWER, power_mw);
    // Analog input supports reporting
    zbElectricalMeasurement.reportDC(ZIGBEE_DC_MEASUREMENT_TYPE_VOLTAGE);
    zbElectricalMeasurement.reportDC(ZIGBEE_DC_MEASUREMENT_TYPE_CURRENT);
    zbElectricalMeasurement.reportDC(ZIGBEE_DC_MEASUREMENT_TYPE_POWER);

    randomizer += 10;
  }

  // Checking button for factory reset and reporting
  if (digitalRead(button) == LOW) {  // Push button pressed
    // Key debounce handling
    delay(100);
    int startTime = millis();
    while (digitalRead(button) == LOW) {
      delay(50);
      if ((millis() - startTime) > 3000) {
        // If key pressed for more than 3secs, factory reset Zigbee and reboot
        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
        delay(1000);
        Zigbee.factoryReset();
      }
    }
  }
  delay(100);
}

AC Electrical Measurement

// Copyright 2025 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @brief This example demonstrates Zigbee electrical AC measurement device with multi-phase support.
 *
 * The example demonstrates how to use Zigbee library to create a router device that measures
 * AC electrical parameters like voltage, current, power, power factor and frequency across
 * three phases (A, B, C). This allows monitoring of three-phase power systems commonly used
 * in industrial and commercial applications.
 *
 * The device measures:
 * - Per phase: voltage, current, power, power factor
 * - Shared: frequency (common across all phases)
 *
 * Proper Zigbee mode must be selected in Tools->Zigbee mode
 * and also the correct partition scheme must be selected in Tools->Partition Scheme.
 *
 * Please check the README.md for instructions and more detailed description.
 *
 * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
 */

// Recommended to use Router mode, as this type of device is expected to be mains powered.
#ifndef ZIGBEE_MODE_ZCZR
#error "Zigbee coordinator/router mode is not selected in Tools->Zigbee mode"
#endif

#include "Zigbee.h"

/* Zigbee AC measurement device configuration */
#define AC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER 1

uint8_t analogPin = A0;
uint8_t button = BOOT_PIN;

ZigbeeElectricalMeasurement zbElectricalMeasurement = ZigbeeElectricalMeasurement(AC_ELECTRICAL_MEASUREMENT_ENDPOINT_NUMBER);

void onAnalogOutputChange(float analog_output) {
  Serial.printf("Received analog output change: %.1f\r\n", analog_output);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting...");

  // Init button switch
  pinMode(button, INPUT_PULLUP);

  // Set analog resolution to 10 bits
  analogReadResolution(10);

  // Optional: set Zigbee device name and model
  zbElectricalMeasurement.setManufacturerAndModel("Espressif", "ZigbeeElectricalMeasurementAC");

  // Add analog clusters to Zigbee Analog according your needs
  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A);
  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A);
  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A);

  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_B);
  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_B);
  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_B);

  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_C);
  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_C);
  zbElectricalMeasurement.addACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_C);

  zbElectricalMeasurement.addACMeasurement(
    ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC
  );  // frequency is not phase specific (shared)

  // Recommended: set Multiplier/Divisor for the measurements (common for all phases)
  zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, 1, 100);     // 1/100 = 0.01V (1 unit of measurement = 0.01V = 10mV)
  zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, 1, 1000);    // 1/1000 = 0.001A (1 unit of measurement = 0.001A = 1mA)
  zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, 1, 10);        // 1/10 = 0.1W (1 unit of measurement = 0.1W = 100mW)
  zbElectricalMeasurement.setACMultiplierDivisor(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, 1, 1000);  // 1/1000 = 0.001Hz (1 unit of measurement = 0.001Hz = 1mHz)

  // Optional: set Min/max values for the measurements
  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A, 0, 30000);  // 0-300.00V
  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A, 0, 10000);  // 0-10.000A
  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A, 0, 32000);    // 0-3200.0W

  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_B, 0, 30000);  // 0-300.00V
  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_B, 0, 10000);  // 0-10.000A
  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_B, 0, 32000);    // 0-3200.0W

  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_C, 0, 30000);  // 0-300.00V
  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_C, 0, 10000);  // 0-10.000A
  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_C, 0, 32000);    // 0-3200.0W

  zbElectricalMeasurement.setACMinMaxValue(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, 0, 65000);  // 0-65.000Hz

  // Add endpoints to Zigbee Core
  Zigbee.addEndpoint(&zbElectricalMeasurement);

  Serial.println("Starting Zigbee...");
  // When all EPs are registered, start Zigbee in Router mode
  if (!Zigbee.begin(ZIGBEE_ROUTER)) {
    Serial.println("Zigbee failed to start!");
    Serial.println("Rebooting...");
    ESP.restart();
  } else {
    Serial.println("Zigbee started successfully!");
  }
  Serial.println("Connecting to network");
  while (!Zigbee.connected()) {
    Serial.print(".");
    delay(100);
  }
  Serial.println("Connected");
}

void loop() {
  static uint32_t timeCounter = 0;
  static uint8_t randomizer = 0;
  // Read ADC value and update the analog value every 2s
  if (!(timeCounter++ % 20)) {                                  // delaying for 100ms x 20 = 2s
    uint16_t voltage = 23000 + randomizer;                      // 230.00 V
    uint16_t current = analogReadMilliVolts(analogPin);         // demonstrates approx 0-3.3A
    int16_t power = ((voltage / 100) * (current / 1000) * 10);  //calculate power in W
    uint16_t frequency = 50135;                                 // 50.000 Hz
    Serial.printf("Updating AC voltage to %d (0.01V), current to %d (mA), power to %d (0.1W), frequency to %d (mHz)\r\n", voltage, current, power, frequency);
    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A, voltage);
    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A, current);
    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A, power);

    // Phase B demonstrates phase shift
    current += 500;
    voltage += 500;
    power = ((voltage / 100) * (current / 1000) * 10);  //calculate power in W

    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_B, voltage);
    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_B, current);
    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_B, power);

    // Phase C demonstrates phase shift
    current += 500;
    voltage += 500;
    power = ((voltage / 100) * (current / 1000) * 10);  //calculate power in W

    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_C, voltage);
    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_C, current);
    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_C, power);

    zbElectricalMeasurement.setACMeasurement(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC, frequency);

    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_A);
    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_A);
    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_A);

    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_B);
    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_B);
    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_B);

    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_VOLTAGE, ZIGBEE_AC_PHASE_TYPE_C);
    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_CURRENT, ZIGBEE_AC_PHASE_TYPE_C);
    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_POWER, ZIGBEE_AC_PHASE_TYPE_C);

    zbElectricalMeasurement.reportAC(ZIGBEE_AC_MEASUREMENT_TYPE_FREQUENCY, ZIGBEE_AC_PHASE_TYPE_NON_SPECIFIC);

    randomizer += 10;
  }

  // Checking button for factory reset and reporting
  if (digitalRead(button) == LOW) {  // Push button pressed
    // Key debounce handling
    delay(100);
    int startTime = millis();
    while (digitalRead(button) == LOW) {
      delay(50);
      if ((millis() - startTime) > 3000) {
        // If key pressed for more than 3secs, factory reset Zigbee and reboot
        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
        delay(1000);
        Zigbee.factoryReset();
      }
    }
  }
  delay(100);
}