Illuminance regulator interface

This module defines an interface for implementation and interaction with an abstract illuminance regulator.

Using the regulator

As this defines an interface for an abstract illuminance regulator, it cannot be used on its own. For an example of regulator usage, see Light Lightness Control Server.

A regulator implementation will provide a bt_mesh_light_ctrl_reg instance, and this is used as the interface to the regulator. Field bt_mesh_light_ctrl_reg.user_data of this struct can be used to store a user context.

Before using the regulator, it needs to be initialized through the bt_mesh_light_ctrl_reg.init function. Functions bt_mesh_light_ctrl_reg.start and bt_mesh_light_ctrl_reg.stop are used to start and stop the regulator.

Regulator inputs

The regulator has two inputs:

  • Target value

  • Measured value

The illuminance regulator takes the specified target value as the reference level and compares it to the reported measured value. The inputs are compared to establish an error for the regulator, which the regulator tries to minimize.

The measured value is passed through the bt_mesh_light_ctrl_reg.measured variable. The passed value is to be used in the next regulator step. The regulator depends on measurement frequency to provide a stable output. The measurement frequency should be as close as possible to the update interval of the regulator. If the measurement frequency is too low, the regulator might oscillate as it attempts to compensate for outdated feedback.

The desired target value is passed through the bt_mesh_light_ctrl_reg_target_set() function. If the transition time is greater than zero, the target value will be interpolated linearly over the transition time from the previously set value to the new one.

Regulator output

The regulator contains a proportional (P) and an integral (I) component whose outputs are summarized to a regulator output value. To get output from the regulator, set the bt_mesh_light_ctrl_reg.updated callback. When the regulator is running, it will repeatedly call this callback.

Tuning the regulator

Regulator tuning is complex and depends on a lot of internal and external parameters. Varying sensor delay, light output and light change rate may significantly affect the regulator performance and accuracy. To compensate for the external parameters, each regulator component provides user controllable coefficients that change their impact on the output value:

  • Kp - for the proportional component

  • Ki - for the integral component

These coefficients can have individual values for positive and negative errors, referenced as follows in the API:

  • Kpu - proportional up; used when target is higher.

  • Kpd - proportional down; used when target is lower.

  • Kiu - integral up; used when target is higher.

  • Kid - integral down; used when target is lower

Regulators are tuned to fit their environment by changing the coefficients. The coefficient adjustments are typically done by analyzing the system’s step response. The step response is the overall system response to a change in reference value, for instance in a state change in the light level state machine.


The transition time between states in the Light LC Server makes the feedback loop more forgiving. A larger transition time can compensate for poor regulator response.

The illuminance regulator is a PI regulator, which uses the following components to compensate for a mismatch between the reference and the measured level:

  • Instantaneous error - The proportional component that is typically the main source of correction for a PI regulator. It compares the reference value to the most recent feedback value, and attempts to correct the error by eliminating the difference.

  • Accumulated error - The integral component that compensates for errors by adding up the sum of the error over time. Its main contribution is to eliminate system bias and accelerate the system step response.

Changing different coefficients will affect the step response differently. Increasing the two coefficients will have the following effect on the step response:


Rise time


Settling time

Steady-state error











The value of the coefficients is typically a trade-off between fast response time and system instability:

  • If the value is too high, the system might become unstable, potentially leading to oscillation and loss of control.

  • If the value is too low, the step response might be too slow or unable to reach the target value altogether.

Implementing a new regulator

To implement a new regulator using this generic interface, declare a bt_mesh_light_ctrl_reg struct, and set the bt_mesh_light_ctrl_reg.init, bt_mesh_light_ctrl_reg.start, and bt_mesh_light_ctrl_reg.stop fields to implementations of these functions. Use bt_mesh_light_ctrl_reg_input_get() to get the current target value for the regulator supplied by the regulator user. The value returned is interpolated linearly over the transition time, if a transition time is requested by the regulator user.

The bt_mesh_light_ctrl_reg.init function must perform the necessary steps to initialize the implementation, such as initializing interrupt handlers or timers, but not start the regulator.

Use the bt_mesh_light_ctrl_reg.start and bt_mesh_light_ctrl_reg.stop functions to start and stop the regulator after it has been initialized by a call to init.

On every regulator step, the regulator must call bt_mesh_light_ctrl_reg.updated callback supplied by the user.

For an example of regulator implementation, see Specification-defined illuminance regulator.

API documentation

Header file: include/bluetooth/mesh/light_ctrl_reg.h
Source file: subsys/bluetooth/mesh/light_ctrl_reg.c
group bt_mesh_light_ctrl_reg

Illuminance regulator API.


void bt_mesh_light_ctrl_reg_target_set(struct bt_mesh_light_ctrl_reg *reg, float target, int32_t transition_time)

Set the target lightness for the regulator.

Sets the target lightness, also known as the setpoint, for the regulator. Transition time is optional.

  • reg[in] Illuminance regulator instance.

  • target[in] Target lightness (setpoint).

  • transition_time[in] Transition time until the target lightness should reach the specified value. Pass 0 to change immediately.

float bt_mesh_light_ctrl_reg_target_get(struct bt_mesh_light_ctrl_reg *reg)

Get the target lightness for the regulator.

Returns the target lightness, taking the requested transition time into account, for use in regulator implementations.

  • reg[in] Illuminance regulator instance.


The current target lightness, interpolated during transition time.

struct bt_mesh_light_ctrl_reg_coeff
#include <light_ctrl_reg.h>

Public Members

float up

Upwards coefficient.

float down

Downwards coefficient.

struct bt_mesh_light_ctrl_reg_cfg
#include <light_ctrl_reg.h>

Illuminance regulator configuration.

Public Members

struct bt_mesh_light_ctrl_reg_coeff ki

Regulator integral coefficient.

struct bt_mesh_light_ctrl_reg_coeff kp

Regulator proportional coefficient.

float accuracy

Regulator dead zone (in percentage).

struct bt_mesh_light_ctrl_reg
#include <light_ctrl_reg.h>

Common regulator context

Public Members

void (*init)(struct bt_mesh_light_ctrl_reg *reg)

Initialize the regulator.

Param reg:

[in] Illuminance regulator instance.

void (*start)(struct bt_mesh_light_ctrl_reg *reg, uint16_t lightness)

Start the regulator.

Param reg:

[in] Illuminance regulator instance.

Param lightness:

[in] Current lightness level value equal to lightness.

void (*stop)(struct bt_mesh_light_ctrl_reg *reg)

Stop the regulator.

Param reg:

[in] Illuminance regulator instance.

struct bt_mesh_light_ctrl_reg_cfg cfg

Regulator configuration.

float measured

Measured value.

void (*updated)(struct bt_mesh_light_ctrl_reg *reg, float output)

Regulator output update callback.

void *user_data

User data, available in update callback.