Skip to Content

Basic Example

Explanation and detailing of the basic example. Understanding sensor functions. Understanding and purpose of units, special units.




Key Concepts. Difference Between Sensor and Unit

Before starting work with the RBgrid library, it's important to understand the fundamental difference between sensors and units.


Sensor

Sensor - is a physical device connected to an ESP32 GPIO pin that converts electrical parameters into a measurable signal.

Sensor characteristics:

  • Bound to a specific GPIO pin
  • Has physical characteristics
  • Performs one function - measurement
  • Has no data context

Sensor examples:

c
// Zero-crossing detector - for grid synchronization
rbgrid_config_add_zc_sensor(config_handle, (gpio_num_t)ZC_CROSS_PIN);

// Voltage sensor on GPIO35, sensor type for grid voltage measurement RBSENSOR_TYPE_VOLTAGE_ZMPT107_1
rbgrid_config_add_adc_sensor(config_handle, GPIO_NUM_35, RBSENSOR_TYPE_VOLTAGE_ZMPT107_1);

// Current sensor on GPIO34, sensor type for current measurement RBSENSOR_TYPE_CURRENT_SCT013_10A
rbgrid_config_add_adc_sensor(config_handle, GPIO_NUM_34, RBSENSOR_TYPE_CURRENT_SCT013_10A);

Voltage Sensors

Type Model Range Application
RBSENSOR_TYPE_VOLTAGE_ZMPT107_1 ZMPT107-1 0-250V AC Home grids
RBSENSOR_TYPE_VOLTAGE_ZMPT101B ZMPT101B 0-250V AC Industrial
RBSENSOR_TYPE_VOLTAGE_DIVIDER Resistive divider Configurable Universal

Current Sensors

Type Model Range Application
RBSENSOR_TYPE_CURRENT_SCT013_5A SCT-013-005 0-5A Household appliances
RBSENSOR_TYPE_CURRENT_SCT013_10A SCT-013-010 0-10A Household appliances
RBSENSOR_TYPE_CURRENT_SCT013_30A SCT-013-030 0-30A Apartment input
RBSENSOR_TYPE_CURRENT_SCT013_50A SCT-013-050 0-50A House input
RBSENSOR_TYPE_CURRENT_SCT013_100A SCT-013-100 0-100A Industrial
RBSENSOR_TYPE_CURRENT_ACS712_5A ACS712-05B ±5A Household appliances
RBSENSOR_TYPE_CURRENT_ACS712_20A ACS712-20A ±20A Household appliances
RBSENSOR_TYPE_CURRENT_ACS712_30A ACS712-30A ±30A Apartment input
RBSENSOR_TYPE_CURRENT_ACS712_50A ACS712-50A ±50A House input
Required sensors
For system operation, mandatory connection and initialization of Zero-Cross and Voltage Bus sensors is required. The system will not start without these sensors.


Unit

Unit - is a logical abstraction representing a measurement point in an electrical grid with economic and functional context.

Special units
The system mandatorily includes a Voltage Bus unit for measuring current voltage, it has no statistics and data accumulation. Main Supply - for monitoring energy consumption from external power grid and business logic (tariffication, energy accounting) of statistical accumulation, as well as reverse sale accounting to the power grid. Alternative Supply - for monitoring energy consumption from internal generation (solar panels, wind generator, batteries), energy accounting of battery charging.

Unit characteristics:

  • Uses data from one or more sensors
  • Has business logic (tariffication, energy accounting)
  • Accumulates statistics
  • Can represent virtual or aggregated measurements

Unit examples:

c
// Create Voltage Bus
rbgrid_config_set_voltage_bus(config_handle, voltage_sensor_uid, "Main Voltage Bus");

// Main Supply - main electricity input
rbgrid_config_set_main_supply(config_handle, current_sensor_uid, "Main Supply Current", RBPOWER_STAT_PERIOD_1YEAR);

// Configure Alternative Supply
rbgrid_config_set_alternative_supply(config_handle, alt_sensor_uid, "Alternative Supply", RBPOWER_STAT_PERIOD_1YEAR);

// Regular unit - specific device
rbgrid_config_add_unit(config_handle, heater_sensor_uid, "Heater 10A", RBPOWER_STAT_PERIOD_1MONTH);
System data flows
Physical level (Hardware)

[GPIO Pin] → [ADC Channel] → [Sensor]

[Sensor UID] → [Unit] → [Statistics]

[Tariffication] → [Energy accounting] → [Reports]



Unit Types


Special Units

1. Voltage Bus

Purpose: Central voltage bus for measuring current grid voltage.

c
// Mandatory unit - must be created first
rbgrid_config_set_voltage_bus(config_handle, voltage_sensor_uid, "Main Voltage Bus");

Features:

  • Only one per system
  • Mandatory for operation
  • Provides reference voltage for power calculation
  • Additionally: Measures power quality (THD)

2. Main Supply

Purpose: Main power input from utility provider.

c
rbgrid_config_set_main_supply(config_handle, current_sensor_uid, "Main Supply Current", RBPOWER_STAT_PERIOD_1YEAR);

Features:
- Accounts for consumption from power provider
- Supports bidirectional metering (net metering)
- Applies main tariffication
- Generates electricity bills


3. Alternative Supply

Purpose: Alternative energy source (solar panels, generator, batteries).

c
rbgrid_config_set_alternative_supply(config_handle, alt_sensor_uid, "Alternative Supply", RBPOWER_STAT_PERIOD_1HOUR);

Features:
- Accounts for energy generation
- Accounts for electricity consumption for battery charging
- Calculates conversion efficiency
- Supports separate tariffication (feed-in tariff)
- Included in consumption balance business logic together with Main Supply



Regular Units

Represent specific consumers or consumer groups.

c
// Regular unit examples
rbgrid_config_add_unit(config_handle, heater_sensor_uid, "Water Heater", RBPOWER_STAT_PERIOD_1HOUR);
rbgrid_config_add_unit(config_handle, livingroom_uid, "Living Room", RBPOWER_STAT_PERIOD_1MONTH);
rbgrid_config_add_unit(config_handle, kitchen_uid, "Kitchen", RBPOWER_STAT_PERIOD_1MONTH);
rbgrid_config_add_unit(config_handle, garage_uid, "Garage equipment", RBPOWER_STAT_PERIOD_1DAY);
rbgrid_config_add_unit(config_handle, air_uid, "Air Heater", RBPOWER_STAT_PERIOD_1HOUR);


Statistics Periods

Each unit accumulates statistics with a specified period, by specifying a period, accumulation will also be conducted for all shorter periods:

Period Value Application
RBPOWER_STAT_PERIOD_15MIN 15 min Variable loads
RBPOWER_STAT_PERIOD_30MIN 30 min Standard devices
RBPOWER_STAT_PERIOD_1HOUR 1 hour Constant loads
RBPOWER_STAT_PERIOD_1DAY 24 hours Daily reports
RBPOWER_STAT_PERIOD_1WEEK week Weekly reports
RBPOWER_STAT_PERIOD_1MONTH month Monthly reports
RBPOWER_STAT_PERIOD_1YEAR year Annual reports


Sensor and Unit Relationship

One sensor - one unit (typical case)

Sensor initialization functions return a unique UID, a 2-byte number containing source and channel.
The obtained UID is passed to the unit initialization function.

c
// Air conditioner current sensor
uid_ac = rbgrid_config_add_adc_sensor(config_handle, GPIO_NUM_34, RBSENSOR_TYPE_CURRENT_SCT013_10A);

// Air conditioner unit uses this sensor
rbgrid_config_add_unit(config, uid_ac, "Air Conditioner", RBPOWER_STAT_PERIOD_1MONTH);

Virtual units (without physical sensor)

c
// Virtual unit - sum of multiple sensors
// Implemented through callback functions
rbgrid_config_add_virtual_unit(config, "Total Consumption", calculate_total_callback, RBPOWER_STAT_PERIOD_1HOUR);

--


Initialization Lifecycle

Let's proceed to the initialization order, configuration and startup of the RBgrid system.


1. Create Configuration

c
rbgrid_config_handle_t config_handle = rbgrid_config_create("Test House", "HongKong");


2. Network Setup, Populate Basic Settings

c
// Configure network
config_err = rbgrid_config_set_network(config_handle);


3. Add Sensors

c
    // Add Zero-Cross sensor on GPIO18
    config_err = rbgrid_config_add_zc_sensor(config_handle, (gpio_num_t)ZC_CROSS_PIN);
    if (config_err != RBGRID_CONFIG_OK) {
        ESP_LOGE(TAG, "Failed to add ZC sensor: %d", config_err);
    } else {
        ESP_LOGI(TAG, "✅ Zero-Cross sensor configured on GPIO%d", ZC_CROSS_PIN);
        rbpower_err_t zc_err = rbpower_init_zc(&zc_config);
        if (zc_err != RBPOWER_OK) {
            ESP_LOGE("APP", "ZC init failed: %d", (int)zc_err);
        } else {
            delay(200);  // Allow time for stabilization
            uint16_t measured_freq = rbpower_get_network_frequency();
            ESP_LOGI("APP", "ZC initialized, measured frequency: %dHz", (int)measured_freq);
            // Update frequency in configuration
            base_hardware_config->network.nominal_frequency = measured_freq;
        }
    }

    // Configure ADC sensors through new API function
    // Add ZMPT107-1 voltage sensor on GPIO35 (ADC1_CH7)
    rbgrid_unit_uid_t voltage_sensor_uid = rbgrid_config_add_adc_sensor(config_handle, GPIO_NUM_35, RBSENSOR_TYPE_VOLTAGE_ZMPT107_1);
    if (voltage_sensor_uid == RBGRID_INVALID_UNIT_UID) {
        ESP_LOGE(TAG, "Failed to add voltage sensor");
    } else {
        ESP_LOGI(TAG, "Voltage sensor added with unit_UID: 0x%04X", voltage_sensor_uid);
    }

    // Add SCT013-10A current sensor on GPIO34 (ADC1_CH6)
    rbgrid_unit_uid_t current_sensor_uid = rbgrid_config_add_adc_sensor(config_handle, GPIO_NUM_34, RBSENSOR_TYPE_CURRENT_SCT013_10A);
    if (current_sensor_uid == RBGRID_INVALID_UNIT_UID) {
        ESP_LOGE(TAG, "Failed to add main current sensor");
    } else {
        ESP_LOGI(TAG, "Main current sensor added with unit_UID: 0x%04X", current_sensor_uid);
    }

    // Add SCT013-50A current sensor on GPIO33 (ADC1_CH5)
    rbgrid_unit_uid_t alt_sensor_uid = rbgrid_config_add_adc_sensor(config_handle, GPIO_NUM_33, RBSENSOR_TYPE_CURRENT_SCT013_50A);
    if (alt_sensor_uid == RBGRID_INVALID_UNIT_UID) {
        ESP_LOGE(TAG, "Failed to add alternative current sensor");
    } else {
        ESP_LOGI(TAG, "Alternative current sensor added with unit_UID: 0x%04X", alt_sensor_uid);
    }

    // Add SCT013-10A current sensor on GPIO32 (ADC1_CH4)
    heater_sensor_uid = rbgrid_config_add_adc_sensor(config_handle, GPIO_NUM_32, RBSENSOR_TYPE_CURRENT_SCT013_10A);
    if (heater_sensor_uid == RBGRID_INVALID_UNIT_UID) {
        ESP_LOGE(TAG, "Failed to add heater current sensor");
    } else {
        ESP_LOGI(TAG, "Heater current sensor added with unit_UID: 0x%04X", heater_sensor_uid);
    }


4. Create Units

c
// Mandatory order for creating special units:
    // 1. Create Voltage Bus using voltage sensor unit_UID
    if (voltage_sensor_uid != RBGRID_INVALID_UNIT_UID) {
        config_err = rbgrid_config_set_voltage_bus(config_handle, voltage_sensor_uid, "Main Voltage Bus");
        if (config_err != RBGRID_CONFIG_OK) {
            ESP_LOGE(TAG, "Failed to configure voltage bus: %d", config_err);
        } else {
            ESP_LOGI(TAG, "✅ Voltage bus configured successfully with unit_UID: 0x%04X", voltage_sensor_uid);
        }
    }

    // 2. Create Main Supply using current sensor unit_UID
    if (current_sensor_uid != RBGRID_INVALID_UNIT_UID) {
        config_err = rbgrid_config_set_main_supply(config_handle, current_sensor_uid, "Main Supply Current", RBPOWER_STAT_PERIOD_1HOUR);
        if (config_err != RBGRID_CONFIG_OK) {
            ESP_LOGE(TAG, "Failed to configure main supply: %d", config_err);
        } else {
            ESP_LOGI(TAG, "✅ Main supply configured successfully with unit_UID: 0x%04X", current_sensor_uid);
        }
    }

    // Configure Alternative Supply with third sensor
    config_err = rbgrid_config_set_alternative_supply(config_handle, alt_sensor_uid, "Alternative Supply", RBPOWER_STAT_PERIOD_1HOUR);
    if (config_err != RBGRID_CONFIG_OK) {
        ESP_LOGE(TAG, "Failed to set alternative supply: %d", config_err);
    } else {
        ESP_LOGI(TAG, "✅ Alternative supply configured");
    }

    // Configure heater with 4th sensor
    config_err = rbgrid_config_add_unit(config_handle, heater_sensor_uid, "Heater 10A", RBPOWER_STAT_PERIOD_1HOUR);
    if (config_err != RBGRID_CONFIG_OK) {
        ESP_LOGE(TAG, "Failed to set Heater: %d", config_err);
    } else {
        ESP_LOGI(TAG, "✅ Heater configured");
    }


5. Initialization and Time Setup

For tariff application, the system must know real time. Real time is obtained at system startup from SNTP servers. WiFi connection must be established beforehand. In case of no connection to SNTP server, the system will apply fallback time settings.

Optional
Time initialization is optional if statistics and economics system is not required.
c
    // Time setup through API functions
    config_err = rbgrid_config_set_sntp_time(config_handle, 
                                             "pool.ntp.org", 
                                             "time.nist.gov", 
                                             "UTC+0");
    if (config_err != RBGRID_CONFIG_OK) {
        ESP_LOGW(TAG, "Failed to configure SNTP time: %d", config_err);
    } else {
        ESP_LOGI(TAG, "✅ SNTP time configuration completed");
    }

    // Configure time fallback
    config_err = rbgrid_config_set_time_fallback(config_handle, 
                                                 true,   // enable RTC fallback
                                                 true,   // enable manual fallback
                                                 1704067200); // January 1, 2024, 00:00:00 UTC
    if (config_err != RBGRID_CONFIG_OK) {
        ESP_LOGW(TAG, "Failed to configure time fallback: %d", config_err);
    }

    // Advanced time settings
    config_err = rbgrid_config_set_time_advanced(config_handle,
                                                 3600,   // sync every hour
                                                 10000,  // 10 second timeout
                                                 3,      // 3 retry attempts
                                                 true);  // enable DST
    if (config_err != RBGRID_CONFIG_OK) {
        ESP_LOGW(TAG, "Failed to configure advanced time settings: %d", config_err);
    }


6. Tariff Configuration

Example of simplest tariff configuration.

c
    // === TARIFF CONFIGURATION USING BUILDER ===
    ESP_LOGI(TAG, "=== Configuring tariff plan ===");

    // Create tariff builder for Germany. Set currency.
    rbgrid_tariff_builder_t tariff_builder = rbgrid_tariff_builder_create("EUR", "DE"); 
    if (!tariff_builder) {
        ESP_LOGE(TAG, "Failed to create tariff builder");
    } else {
        // Basic tariff zones (EUR/kWh)
        rbgrid_tariff_builder_add_time_zone(tariff_builder, "Night", 0.08f, "23:00-07:00");
        rbgrid_tariff_builder_add_time_zone(tariff_builder, "Day", 0.15f, "07:00-18:00");
        rbgrid_tariff_builder_add_time_zone(tariff_builder, "Peak", 0.25f, "18:00-23:00");

        // Weekends (Saturday=0x40, Sunday=0x01)
        rbgrid_tariff_builder_add_weekday_zone(tariff_builder, "Weekend", 0.09f, 0x41);

        // German holidays
        rbgrid_tariff_builder_set_country_holidays(tariff_builder, "DE", 0.085f);

        // Subscription and grid fees
        rbgrid_tariff_builder_set_monthly_fee(tariff_builder, 15.0f);
        rbgrid_tariff_builder_add_custom_fee(tariff_builder, "Grid Fee", 8.5f, RBPOWER_TARIFF_FIXED_MONTHLY);

        // Net metering for solar panels
        rbgrid_tariff_builder_set_net_metering(tariff_builder, 0.12f, 0.7f);

        // Apply tariff plan
        config_err = rbgrid_config_apply_tariff_plan(config_handle, tariff_builder);
        if (config_err != RBGRID_CONFIG_OK) {
            ESP_LOGE(TAG, "Failed to apply tariff plan: %d", config_err);
        } else {
            ESP_LOGI(TAG, "✅ Tariff plan applied successfully");
        }

        // Clean up builder
        rbgrid_tariff_builder_destroy(tariff_builder);
    }


7. Apply Configuration. Initialize and Start

Validation of preliminary settings occurs.
rbgrid_init_system() - checks ESP32 hardware functionality, initializes and starts I/O system, checks memory, starts interrupts, timers.
rbgrid_init_extended() - starts data flow system, unit system, statistics system, economics system, initializes telemetry.

c
// Initialize system
rbgrid_init_system();

// Initialize RBgrid with configuration
rbgrid_init_extended(extended_config);



Configuration Validation

Mandatory requirements

  1. At least one Voltage Bus and Zero-Cross - system won't start without them
  2. Unique GPIO pins - each sensor on its own pin
  3. Correct UIDs - all UID assignments must be unique. Don't reassign UIDs.


Configuration Check

c
// Automatic validation during initialization
RBgrid_err_t err = RBgrid_init_extended(config);

if (err == RBPOWER_ERR_NO_VOLTAGE_BUS) {
    ESP_LOGE(TAG, "Voltage Bus not configured!");
} else if (err == RBPOWER_ERR_INVALID_CONFIG) {
    ESP_LOGE(TAG, "Invalid configuration!");
} else if (err == RBPOWER_OK) {
    ESP_LOGI(TAG, "System initialized successfully");
}



Conclusion

Info
Proper understanding of the differences between sensors and units is critically important for building an effective monitoring system. Sensors provide raw measurement data, while units add business logic, economic context and statistics accumulation. This two-tier architecture provides flexibility and scalability of the system.