Просмотр исходного кода

ble_mesh: add Generic/Sensor/Time and Scenes/Lighting Server models

lly 6 лет назад
Родитель
Сommit
a32c72a1b2
45 измененных файлов с 17969 добавлено и 546 удалено
  1. 10 1
      components/bt/CMakeLists.txt
  2. 4 0
      components/bt/common/btc/core/btc_task.c
  3. 4 0
      components/bt/common/btc/include/btc/btc_task.h
  4. 8 6
      components/bt/component.mk
  5. 38 13
      components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c
  6. 19 0
      components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h
  7. 696 514
      components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h
  8. 7 0
      components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c
  9. 6 0
      components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c
  10. 8 0
      components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c
  11. 7 0
      components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c
  12. 769 0
      components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h
  13. 1091 0
      components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h
  14. 366 0
      components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h
  15. 594 0
      components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h
  16. 224 0
      components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c
  17. 194 0
      components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c
  18. 302 5
      components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c
  19. 273 0
      components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c
  20. 96 0
      components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c
  21. 14 0
      components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h
  22. 15 0
      components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h
  23. 6 0
      components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h
  24. 14 0
      components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h
  25. 15 0
      components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h
  26. 42 2
      components/bt/esp_ble_mesh/mesh_core/access.c
  27. 2 0
      components/bt/esp_ble_mesh/mesh_core/include/mesh_kernel.h
  28. 18 2
      components/bt/esp_ble_mesh/mesh_core/mesh_kernel.c
  29. 3 3
      components/bt/esp_ble_mesh/mesh_models/client/include/client_common.h
  30. 150 0
      components/bt/esp_ble_mesh/mesh_models/server/device_property.c
  31. 2629 0
      components/bt/esp_ble_mesh/mesh_models/server/generic_server.c
  32. 1045 0
      components/bt/esp_ble_mesh/mesh_models/server/include/device_property.h
  33. 374 0
      components/bt/esp_ble_mesh/mesh_models/server/include/generic_server.h
  34. 516 0
      components/bt/esp_ble_mesh/mesh_models/server/include/lighting_server.h
  35. 249 0
      components/bt/esp_ble_mesh/mesh_models/server/include/sensor_server.h
  36. 127 0
      components/bt/esp_ble_mesh/mesh_models/server/include/server_common.h
  37. 92 0
      components/bt/esp_ble_mesh/mesh_models/server/include/state_binding.h
  38. 91 0
      components/bt/esp_ble_mesh/mesh_models/server/include/state_transition.h
  39. 393 0
      components/bt/esp_ble_mesh/mesh_models/server/include/time_scene_server.h
  40. 3333 0
      components/bt/esp_ble_mesh/mesh_models/server/lighting_server.c
  41. 1088 0
      components/bt/esp_ble_mesh/mesh_models/server/sensor_server.c
  42. 237 0
      components/bt/esp_ble_mesh/mesh_models/server/server_common.c
  43. 342 0
      components/bt/esp_ble_mesh/mesh_models/server/state_binding.c
  44. 1034 0
      components/bt/esp_ble_mesh/mesh_models/server/state_transition.c
  45. 1424 0
      components/bt/esp_ble_mesh/mesh_models/server/time_scene_server.c

+ 10 - 1
components/bt/CMakeLists.txt

@@ -304,6 +304,7 @@ if(CONFIG_BT_ENABLED)
                     "esp_ble_mesh/btc/include"
                     "esp_ble_mesh/mesh_models/common/include"
                     "esp_ble_mesh/mesh_models/client/include"
+                    "esp_ble_mesh/mesh_models/server/include"
                     "esp_ble_mesh/api/core/include"
                     "esp_ble_mesh/api/models/include"
                     "esp_ble_mesh/api")
@@ -359,7 +360,15 @@ if(CONFIG_BT_ENABLED)
                     "esp_ble_mesh/mesh_models/client/generic_client.c"
                     "esp_ble_mesh/mesh_models/client/lighting_client.c"
                     "esp_ble_mesh/mesh_models/client/sensor_client.c"
-                    "esp_ble_mesh/mesh_models/client/time_scene_client.c")
+                    "esp_ble_mesh/mesh_models/client/time_scene_client.c"
+                    "esp_ble_mesh/mesh_models/server/device_property.c"
+                    "esp_ble_mesh/mesh_models/server/generic_server.c"
+                    "esp_ble_mesh/mesh_models/server/lighting_server.c"
+                    "esp_ble_mesh/mesh_models/server/sensor_server.c"
+                    "esp_ble_mesh/mesh_models/server/server_common.c"
+                    "esp_ble_mesh/mesh_models/server/state_binding.c"
+                    "esp_ble_mesh/mesh_models/server/state_transition.c"
+                    "esp_ble_mesh/mesh_models/server/time_scene_server.c")
     endif()
 
     if(CONFIG_BT_NIMBLE_ENABLED)

+ 4 - 0
components/bt/common/btc/core/btc_task.c

@@ -126,6 +126,10 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = {
     [BTC_PID_LIGHTING_CLIENT]   = {btc_ble_mesh_lighting_client_call_handler,   btc_ble_mesh_lighting_client_cb_handler  },
     [BTC_PID_SENSOR_CLIENT]     = {btc_ble_mesh_sensor_client_call_handler,     btc_ble_mesh_sensor_client_cb_handler    },
     [BTC_PID_TIME_SCENE_CLIENT] = {btc_ble_mesh_time_scene_client_call_handler, btc_ble_mesh_time_scene_client_cb_handler},
+    [BTC_PID_GENERIC_SERVER]    = {NULL,                                        btc_ble_mesh_generic_server_cb_handler   },
+    [BTC_PID_LIGHTING_SERVER]   = {NULL,                                        btc_ble_mesh_lighting_server_cb_handler  },
+    [BTC_PID_SENSOR_SERVER]     = {NULL,                                        btc_ble_mesh_sensor_server_cb_handler    },
+    [BTC_PID_TIME_SCENE_SERVER] = {NULL,                                        btc_ble_mesh_time_scene_server_cb_handler},
 #endif /* #if CONFIG_BLE_MESH */
 };
 

+ 4 - 0
components/bt/common/btc/include/btc/btc_task.h

@@ -78,6 +78,10 @@ typedef enum {
     BTC_PID_LIGHTING_CLIENT,
     BTC_PID_SENSOR_CLIENT,
     BTC_PID_TIME_SCENE_CLIENT,
+    BTC_PID_GENERIC_SERVER,
+    BTC_PID_LIGHTING_SERVER,
+    BTC_PID_SENSOR_SERVER,
+    BTC_PID_TIME_SCENE_SERVER,
 #endif /* CONFIG_BLE_MESH */
     BTC_PID_NUM,
 } btc_pid_t; //btc profile id

+ 8 - 6
components/bt/component.mk

@@ -143,16 +143,18 @@ COMPONENT_ADD_INCLUDEDIRS += esp_ble_mesh/mesh_core                     \
                              esp_ble_mesh/btc/include                   \
                              esp_ble_mesh/mesh_models/common/include    \
                              esp_ble_mesh/mesh_models/client/include    \
+                             esp_ble_mesh/mesh_models/server/include    \
                              esp_ble_mesh/api/core/include              \
                              esp_ble_mesh/api/models/include            \
                              esp_ble_mesh/api
 
-COMPONENT_SRCDIRS += esp_ble_mesh/mesh_core               	\
-                     esp_ble_mesh/mesh_core/settings      	\
-                     esp_ble_mesh/btc                     	\
-                     esp_ble_mesh/mesh_models/common      	\
-                     esp_ble_mesh/mesh_models/client      	\
-                     esp_ble_mesh/api/core                	\
+COMPONENT_SRCDIRS += esp_ble_mesh/mesh_core                 \
+                     esp_ble_mesh/mesh_core/settings        \
+                     esp_ble_mesh/btc                       \
+                     esp_ble_mesh/mesh_models/common        \
+                     esp_ble_mesh/mesh_models/client        \
+                     esp_ble_mesh/mesh_models/server        \
+                     esp_ble_mesh/api/core                  \
                      esp_ble_mesh/api/models
 endif
 

+ 38 - 13
components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c

@@ -25,13 +25,13 @@
 
 #define ESP_BLE_MESH_TX_SDU_MAX ((CONFIG_BLE_MESH_ADV_BUF_COUNT - 3) * 12)
 
-static esp_err_t ble_mesh_send_msg(esp_ble_mesh_model_t *model,
-                                   esp_ble_mesh_msg_ctx_t *ctx,
-                                   uint32_t opcode,
-                                   btc_ble_mesh_model_act_t act,
-                                   uint16_t length, uint8_t *data,
-                                   int32_t msg_timeout, bool need_rsp,
-                                   esp_ble_mesh_dev_role_t device_role)
+static esp_err_t ble_mesh_model_send_msg(esp_ble_mesh_model_t *model,
+                                         esp_ble_mesh_msg_ctx_t *ctx,
+                                         uint32_t opcode,
+                                         btc_ble_mesh_model_act_t act,
+                                         uint16_t length, uint8_t *data,
+                                         int32_t msg_timeout, bool need_rsp,
+                                         esp_ble_mesh_dev_role_t device_role)
 {
     btc_ble_mesh_model_args_t arg = {0};
     uint8_t op_len = 0, mic_len = 0;
@@ -165,8 +165,8 @@ esp_err_t esp_ble_mesh_server_model_send_msg(esp_ble_mesh_model_t *model,
     if (!model || !ctx) {
         return ESP_ERR_INVALID_ARG;
     }
-    return ble_mesh_send_msg(model, ctx, opcode, BTC_BLE_MESH_ACT_SERVER_MODEL_SEND,
-                             length, data, 0, false, ROLE_NODE);
+    return ble_mesh_model_send_msg(model, ctx, opcode, BTC_BLE_MESH_ACT_SERVER_MODEL_SEND,
+                                   length, data, 0, false, ROLE_NODE);
 }
 
 esp_err_t esp_ble_mesh_client_model_send_msg(esp_ble_mesh_model_t *model,
@@ -177,8 +177,8 @@ esp_err_t esp_ble_mesh_client_model_send_msg(esp_ble_mesh_model_t *model,
     if (!model || !ctx) {
         return ESP_ERR_INVALID_ARG;
     }
-    return ble_mesh_send_msg(model, ctx, opcode, BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND,
-                             length, data, msg_timeout, need_rsp, device_role);
+    return ble_mesh_model_send_msg(model, ctx, opcode, BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND,
+                                   length, data, msg_timeout, need_rsp, device_role);
 }
 
 esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcode,
@@ -188,8 +188,33 @@ esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcod
     if (!model || !model->pub || !model->pub->msg) {
         return ESP_ERR_INVALID_ARG;
     }
-    return ble_mesh_send_msg(model, NULL, opcode, BTC_BLE_MESH_ACT_MODEL_PUBLISH,
-                             length, data, 0, false, device_role);
+    return ble_mesh_model_send_msg(model, NULL, opcode, BTC_BLE_MESH_ACT_MODEL_PUBLISH,
+                                   length, data, 0, false, device_role);
+}
+
+esp_err_t esp_ble_mesh_server_model_update_state(esp_ble_mesh_model_t *model,
+        esp_ble_mesh_server_state_type_t type,
+        esp_ble_mesh_server_state_value_t *value)
+{
+    btc_ble_mesh_model_args_t arg = {0};
+    btc_msg_t msg = {0};
+
+    if (!model || !value || type >= ESP_BLE_MESH_SERVER_MODEL_STATE_MAX) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    arg.model_update_state.model = model;
+    arg.model_update_state.type = type;
+    arg.model_update_state.value = value;
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_MODEL;
+    msg.act = BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_model_args_t), btc_ble_mesh_model_arg_deep_copy)
+              == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
 }
 
 esp_err_t esp_ble_mesh_node_local_reset(void)

+ 19 - 0
components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h

@@ -134,6 +134,25 @@ esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcod
                                      uint16_t length, uint8_t *data,
                                      esp_ble_mesh_dev_role_t device_role);
 
+/**
+ * @brief        Update a server model state value. If the model publication
+ *               state is set properly (e.g. publish address is set to a valid
+ *               address), it will publish corresponding status message.
+ * 
+ * @note         Currently this API is used to update bound state value, not
+ *               for all server model states.
+ *
+ * @param[in]    model: Server model which is going to update the state.
+ * @param[in]    type:  Server model state type.
+ * @param[in]    value: Server model state value.
+ *
+ * @return       ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_server_model_update_state(esp_ble_mesh_model_t *model,
+        esp_ble_mesh_server_state_type_t type,
+        esp_ble_mesh_server_state_value_t *value);
+
 /**
  * @brief         Reset the provisioning procedure of the local BLE Mesh node.
  *

Разница между файлами не показана из-за своего большого размера
+ 696 - 514
components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h


+ 7 - 0
components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c

@@ -70,3 +70,10 @@ esp_err_t esp_ble_mesh_generic_client_set_state(esp_ble_mesh_client_common_param
     return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_generic_client_args_t), btc_ble_mesh_generic_client_arg_deep_copy)
             == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
 }
+
+esp_err_t esp_ble_mesh_register_generic_server_callback(esp_ble_mesh_generic_server_cb_t callback)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    return (btc_profile_cb_set(BTC_PID_GENERIC_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL);
+}

+ 6 - 0
components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c

@@ -71,3 +71,9 @@ esp_err_t esp_ble_mesh_light_client_set_state(esp_ble_mesh_client_common_param_t
             == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
 }
 
+esp_err_t esp_ble_mesh_register_lighting_server_callback(esp_ble_mesh_lighting_server_cb_t callback)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    return (btc_profile_cb_set(BTC_PID_LIGHTING_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL);
+}

+ 8 - 0
components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c

@@ -71,3 +71,11 @@ esp_err_t esp_ble_mesh_sensor_client_set_state(esp_ble_mesh_client_common_param_
             == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
 }
 
+esp_err_t esp_ble_mesh_register_sensor_server_callback(esp_ble_mesh_sensor_server_cb_t callback)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    return (btc_profile_cb_set(BTC_PID_SENSOR_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL);
+}
+
+

+ 7 - 0
components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c

@@ -71,3 +71,10 @@ esp_err_t esp_ble_mesh_time_scene_client_set_state(esp_ble_mesh_client_common_pa
             == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
 }
 
+esp_err_t esp_ble_mesh_register_time_scene_server_callback(esp_ble_mesh_time_scene_server_cb_t callback)
+{
+    ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
+
+    return (btc_profile_cb_set(BTC_PID_TIME_SCENE_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL);
+}
+

+ 769 - 0
components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h

@@ -523,6 +523,775 @@ esp_err_t esp_ble_mesh_generic_client_get_state(esp_ble_mesh_client_common_param
 esp_err_t esp_ble_mesh_generic_client_set_state(esp_ble_mesh_client_common_param_t *params,
         esp_ble_mesh_generic_client_set_state_t *set_state);
 
+/**
+ * @brief Generic Server Models related context.
+ */
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV
+ *
+ *  @brief  Define a new Generic OnOff Server Model.
+ *
+ *  @note   1. The Generic OnOff Server Model is a root model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_onoff_srv_t.
+ *
+ *  @return New Generic OnOff Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_LEVEL_SRV
+ *
+ *  @brief  Define a new Generic Level Server Model.
+ *
+ *  @note   1. The Generic Level Server Model is a root model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_level_srv_t.
+ *
+ *  @return New Generic Level Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_LEVEL_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_LEVEL_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_SRV
+ *
+ *  @brief  Define a new Generic Default Transition Time Server Model.
+ *
+ *  @note   1. The Generic Default Transition Time Server Model is a root model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_def_trans_time_srv_t.
+ *
+ *  @return New Generic Default Transition Time Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_DEF_TRANS_TIME_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_POWER_ONOFF_SRV
+ *
+ *  @brief  Define a new Generic Power OnOff Server Model.
+ *
+ *  @note   1. The Generic Power OnOff Server model extends the Generic OnOff Server
+ *             model. When this model is present on an element, the corresponding
+ *             Generic Power OnOff Setup Server model shall also be present.
+ *          2. This model may be used to represent a variety of devices that do not
+ *             fit any of the model descriptions that have been defined but support
+ *             the generic properties of On/Off.
+ *          3. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_power_onoff_srv_t.
+ *
+ *  @return New Generic Power OnOff Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_POWER_ONOFF_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_POWER_ONOFF_SETUP_SRV
+ *
+ *  @brief  Define a new Generic Power OnOff Setup Server Model.
+ *
+ *  @note   1. The Generic Power OnOff Setup Server model extends the Generic Power
+ *             OnOff Server model and the Generic Default Transition Time Server model.
+ *          2. This model shall support model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_power_onoff_setup_srv_t.
+ *
+ *  @return New Generic Power OnOff Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_POWER_ONOFF_SETUP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_POWER_LEVEL_SRV
+ *
+ *  @brief  Define a new Generic Power Level Server Model.
+ *
+ *  @note   1. The Generic Power Level Server model extends the Generic Power OnOff
+ *             Server model and the Generic Level Server model. When this model is
+ *             present on an Element, the corresponding Generic Power Level Setup
+ *             Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_power_level_srv_t.
+ *
+ *  @return New Generic Power Level Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_POWER_LEVEL_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_POWER_LEVEL_SETUP_SRV
+ *
+ *  @brief  Define a new Generic Power Level Setup Server Model.
+ *
+ *  @note   1. The Generic Power Level Setup Server model extends the Generic Power
+ *             Level Server model and the Generic Power OnOff Setup Server model.
+ *          2. This model shall support model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_power_level_setup_srv_t.
+ *
+ *  @return New Generic Power Level Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_POWER_LEVEL_SETUP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_BATTERY_SRV
+ *
+ *  @brief  Define a new Generic Battery Server Model.
+ *
+ *  @note   1. The Generic Battery Server Model is a root model.
+ *          2. This model shall support model publication and model subscription.
+ *          3. The model may be used to represent an element that is powered by a battery.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_battery_srv_t.
+ *
+ *  @return New Generic Battery Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_BATTERY_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_BATTERY_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_LOCATION_SRV
+ *
+ *  @brief  Define a new Generic Location Server Model.
+ *
+ *  @note   1. The Generic Location Server model is a root model. When this model
+ *             is present on an Element, the corresponding Generic Location Setup
+ *             Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *          3. The model may be used to represent an element that knows its
+ *             location (global or local).
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_location_srv_t.
+ *
+ *  @return New Generic Location Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_LOCATION_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_LOCATION_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_LOCATION_SETUP_SRV
+ *
+ *  @brief  Define a new Generic Location Setup Server Model.
+ *
+ *  @note   1. The Generic Location Setup Server model extends the Generic Location
+ *             Server model.
+ *          2. This model shall support model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_location_setup_srv_t.
+ *
+ *  @return New Generic Location Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_LOCATION_SETUP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_USER_PROP_SRV
+ *
+ *  @brief  Define a new Generic User Property Server Model.
+ *
+ *  @note   1. The Generic User Property Server model is a root model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_user_prop_srv_t.
+ *
+ *  @return New Generic User Property Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_USER_PROP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_ADMIN_PROP_SRV
+ *
+ *  @brief  Define a new Generic Admin Property Server Model.
+ *
+ *  @note   1. The Generic Admin Property Server model extends the Generic User
+ *             Property Server model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_admin_prop_srv_t.
+ *
+ *  @return New Generic Admin Property Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_ADMIN_PROP_SRV(srv_pub, srv_data)            \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV,    \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_MANUFACTURER_PROP_SRV
+ *
+ *  @brief  Define a new Generic Manufacturer Property Server Model.
+ *
+ *  @note   1. The Generic Manufacturer Property Server model extends the Generic
+ *             User Property Server model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_manu_prop_srv_t.
+ *
+ *  @return New Generic Manufacturer Property Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_MANUFACTURER_PROP_SRV(srv_pub, srv_data)            \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV,    \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_GEN_CLIENT_PROP_SRV
+ *
+ *  @brief  Define a new Generic User Property Server Model.
+ *
+ *  @note   1. The Generic Client Property Server model is a root model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_gen_client_prop_srv_t.
+ *
+ *  @return New Generic Client Property Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_GEN_CLIENT_PROP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** Parameters of Generic OnOff state */
+typedef struct {
+    uint8_t onoff;          /*!< The present value of the Generic OnOff state */
+    uint8_t target_onoff;   /*!< The target value of the Generic OnOff state */
+} esp_ble_mesh_gen_onoff_state_t;
+
+/** User data of Generic OnOff Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Generic OnOff Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_onoff_state_t state;       /*!< Parameters of the Generic OnOff state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+} esp_ble_mesh_gen_onoff_srv_t;
+
+/** Parameters of Generic Level state */
+typedef struct {
+    int16_t level;          /*!< The present value of the Generic Level state */
+    int16_t target_level;   /*!< The target value of the Generic Level state */
+
+    /**
+     * When a new transaction starts, level should be set to last_last, and use
+     * "level + incoming delta" to calculate the target level. In another word,
+     * "last_level" is used to record "level" of the last transaction, and
+     * "last_delta" is used to record the previously received delta_level value.
+     */
+    int16_t last_level; /*!< The last value of the Generic Level state */
+    int32_t last_delta; /*!< The last delta change of the Generic Level state */
+
+    bool move_start;    /*!< Indicate if the transition of the Generic Level state has been started */
+    bool positive;      /*!< Indicate if the transition is positive or negative */
+} esp_ble_mesh_gen_level_state_t;
+
+/** User data of Generic Level Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Generic Level Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_level_state_t state;       /*!< Parameters of the Generic Level state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+    int32_t tt_delta_level;                     /*!< Delta change value of level state transition */
+} esp_ble_mesh_gen_level_srv_t;
+
+/** Parameter of Generic Default Transition Time state */
+typedef struct {
+    uint8_t trans_time;     /*!< The value of the Generic Default Transition Time state */
+} esp_ble_mesh_gen_def_trans_time_state_t;
+
+/** User data of Generic Default Transition Time Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                    /*!< Pointer to the Generic Default Transition Time Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;        /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_def_trans_time_state_t state;  /*!< Parameters of the Generic Default Transition Time state */
+} esp_ble_mesh_gen_def_trans_time_srv_t;
+
+/** Parameter of Generic OnPowerUp state */
+typedef struct {
+    uint8_t onpowerup;      /*!< The value of the Generic OnPowerUp state */
+} esp_ble_mesh_gen_onpowerup_state_t;
+
+/** User data of Generic Power OnOff Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Generic Power OnOff Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_onpowerup_state_t *state;  /*!< Parameters of the Generic OnPowerUp state */
+} esp_ble_mesh_gen_power_onoff_srv_t;
+
+/** User data of Generic Power OnOff Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Generic Power OnOff Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_onpowerup_state_t *state;  /*!< Parameters of the Generic OnPowerUp state */
+} esp_ble_mesh_gen_power_onoff_setup_srv_t;
+
+/** Parameters of Generic Power Level state */
+typedef struct {
+    uint16_t power_actual;          /*!< The present value of the Generic Power Actual state */
+    uint16_t target_power_actual;   /*!< The target value of the Generic Power Actual state */
+
+    uint16_t power_last;            /*!< The value of the Generic Power Last state */
+    uint16_t power_default;         /*!< The value of the Generic Power Default state */
+
+    uint8_t  status_code;           /*!< The status code of setting Generic Power Range state */
+    uint16_t power_range_min;       /*!< The minimum value of the Generic Power Range state */
+    uint16_t power_range_max;       /*!< The maximum value of the Generic Power Range state */
+} esp_ble_mesh_gen_power_level_state_t;
+
+/** User data of Generic Power Level Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                    /*!< Pointer to the Generic Power Level Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;        /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_power_level_state_t *state;    /*!< Parameters of the Generic Power Level state */
+    esp_ble_mesh_last_msg_info_t last;              /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition;     /*!< Parameters of state transition */
+    int32_t tt_delta_level;                         /*!< Delta change value of level state transition */
+} esp_ble_mesh_gen_power_level_srv_t;
+
+/** User data of Generic Power Level Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                    /*!< Pointer to the Generic Power Level Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;        /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_power_level_state_t *state;    /*!< Parameters of the Generic Power Level state */
+} esp_ble_mesh_gen_power_level_setup_srv_t;
+
+/** Parameters of Generic Battery state */
+typedef struct {
+    uint32_t battery_level : 8,         /*!< The value of the Generic Battery Level state */
+             time_to_discharge : 24;    /*!< The value of the Generic Battery Time to Discharge state */
+    uint32_t time_to_charge : 24,       /*!< The value of the Generic Battery Time to Charge state */
+             battery_flags : 8;         /*!< The value of the Generic Battery Flags state */
+} esp_ble_mesh_gen_battery_state_t;
+
+/** User data of Generic Battery Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Generic Battery Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_battery_state_t state;     /*!< Parameters of the Generic Battery state */
+} esp_ble_mesh_gen_battery_srv_t;
+
+/** Parameters of Generic Location state */
+typedef struct {
+    int32_t  global_latitude;   /*!< The value of the Global Latitude field */
+    int32_t  global_longitude;  /*!< The value of the Global Longtitude field */
+    int16_t  global_altitude;   /*!< The value of the Global Altitude field */
+    int16_t  local_north;       /*!< The value of the Local North field */
+    int16_t  local_east;        /*!< The value of the Local East field */
+    int16_t  local_altitude;    /*!< The value of the Local Altitude field */
+    uint8_t  floor_number;      /*!< The value of the Floor Number field */
+    uint16_t uncertainty;       /*!< The value of the Uncertainty field */
+} esp_ble_mesh_gen_location_state_t;
+
+/** User data of Generic Location Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Generic Location Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_location_state_t *state;   /*!< Parameters of the Generic Location state */
+} esp_ble_mesh_gen_location_srv_t;
+
+/** User data of Generic Location Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Generic Location Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_gen_location_state_t *state;   /*!< Parameters of the Generic Location state */
+} esp_ble_mesh_gen_location_setup_srv_t;
+
+/** This enum value is the access vlue of Generic User Property */
+typedef enum {
+    ESP_BLE_MESH_GEN_USER_ACCESS_PROHIBIT,
+    ESP_BLE_MESH_GEN_USER_ACCESS_READ,
+    ESP_BLE_MESH_GEN_USER_ACCESS_WRITE,
+    ESP_BLE_MESH_GEN_USER_ACCESS_READ_WRITE,
+} esp_ble_mesh_gen_user_prop_access_t;
+
+/** This enum value is the access value of Generic Admin Property */
+typedef enum {
+    ESP_BLE_MESH_GEN_ADMIN_NOT_USER_PROP,
+    ESP_BLE_MESH_GEN_ADMIN_ACCESS_READ,
+    ESP_BLE_MESH_GEN_ADMIN_ACCESS_WRITE,
+    ESP_BLE_MESH_GEN_ADMIN_ACCESS_READ_WRITE,
+} esp_ble_mesh_gen_admin_prop_access_t;
+
+/** This enum value is the access value of Generic Manufacturer Property */
+typedef enum {
+    ESP_BLE_MESH_GEN_MANU_NOT_USER_PROP,
+    ESP_BLE_MESH_GEN_MANU_ACCESS_READ,
+} esp_ble_mesh_gen_manu_prop_access_t;
+
+/** Parameters of Generic Property states */
+typedef struct {
+    uint16_t id;            /*!< The value of User/Admin/Manufacturer Property ID */
+    uint8_t  user_access;   /*!< The value of User Access field */
+    uint8_t  admin_access;  /*!< The value of Admin Access field */
+    uint8_t  manu_access;   /*!< The value of Manufacturer Access field */
+    struct net_buf_simple *val; /*!< The value of User/Admin/Manufacturer Property */
+} esp_ble_mesh_generic_property_t;
+
+/** User data of Generic User Property Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                    /*!< Pointer to the Generic User Property Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;        /*!< Response control of the server model received messages */
+    uint8_t property_count;                         /*!< Generic User Property count */
+    esp_ble_mesh_generic_property_t *properties;    /*!< Parameters of the Generic User Property state */
+} esp_ble_mesh_gen_user_prop_srv_t;
+
+/** User data of Generic Admin Property Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                    /*!< Pointer to the Generic Admin Property Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;        /*!< Response control of the server model received messages */
+    uint8_t property_count;                         /*!< Generic Admin Property count */
+    esp_ble_mesh_generic_property_t *properties;    /*!< Parameters of the Generic Admin Property state */
+} esp_ble_mesh_gen_admin_prop_srv_t;
+
+/** User data of Generic Manufacturer Property Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                    /*!< Pointer to the Generic Manufacturer Property Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;        /*!< Response control of the server model received messages */
+    uint8_t property_count;                         /*!< Generic Manufacturer Property count */
+    esp_ble_mesh_generic_property_t *properties;    /*!< Parameters of the Generic Manufacturer Property state */
+} esp_ble_mesh_gen_manu_prop_srv_t;
+
+/** User data of Generic Client Property Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Generic Client Property Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    uint8_t id_count;                           /*!< Generic Client Property ID count */
+    uint16_t *property_ids;                     /*!< Parameters of the Generic Client Property state */
+} esp_ble_mesh_gen_client_prop_srv_t;
+
+/** Parameter of Generic OnOff Set state change event */
+typedef struct {
+    uint8_t onoff;          /*!< The value of Generic OnOff state */
+} esp_ble_mesh_state_change_gen_onoff_set_t;
+
+/** Parameter of Generic Level Set state change event */
+typedef struct {
+    int16_t level;          /*!< The value of Generic Level state */
+} esp_ble_mesh_state_change_gen_level_set_t;
+
+/** Parameter of Generic Delta Set state change event */
+typedef struct {
+    int16_t level;          /*!< The value of Generic Level state */
+} esp_ble_mesh_state_change_gen_delta_set_t;
+
+/** Parameter of Generic Move Set state change event */
+typedef struct {
+    int16_t level;          /*!< The value of Generic Level state */
+} esp_ble_mesh_state_change_gen_move_set_t;
+
+/** Parameter of Generic Default Transition Time Set state change event */
+typedef struct {
+    uint8_t trans_time;     /*!< The value of Generic Default Transition Time state */
+} esp_ble_mesh_state_change_gen_def_trans_time_set_t;
+
+/** Parameter of Generic OnPowerUp Set state change event */
+typedef struct {
+    uint8_t onpowerup;      /*!< The value of Generic OnPowerUp state */
+} esp_ble_mesh_state_change_gen_onpowerup_set_t;
+
+/** Parameter of Generic Power Level Set state change event */
+typedef struct {
+    uint16_t power;         /*!< The value of Generic Power Actual state */
+} esp_ble_mesh_state_change_gen_power_level_set_t;
+
+/** Parameter of Generic Power Default Set state change event */
+typedef struct {
+    uint16_t power;         /*!< The value of Generic Power Default state */
+} esp_ble_mesh_state_change_gen_power_default_set_t;
+
+/** Parameters of Generic Power Range Set state change event */
+typedef struct {
+    uint16_t range_min;     /*!< The minimum value of Generic Power Range state */
+    uint16_t range_max;     /*!< The maximum value of Generic Power Range state */
+} esp_ble_mesh_state_change_gen_power_range_set_t;
+
+/** Parameters of Generic Location Global Set state change event */
+typedef struct {
+    int32_t latitude;       /*!< The Global Latitude value of Generic Location state */
+    int32_t longitude;      /*!< The Global Longitude value of Generic Location state */
+    int16_t altitude;       /*!< The Global Altitude value of Generic Location state */
+} esp_ble_mesh_state_change_gen_loc_global_set_t;
+
+/** Parameters of Generic Location Local Set state change event */
+typedef struct {
+    int16_t  north;         /*!< The Local North value of Generic Location state */
+    int16_t  east;          /*!< The Local East value of Generic Location state */
+    int16_t  altitude;      /*!< The Local Altitude value of Generic Location state */
+    uint8_t  floor_number;  /*!< The Floor Number value of Generic Location state */
+    uint16_t uncertainty;   /*!< The Uncertainty value of Generic Location state */
+} esp_ble_mesh_state_change_gen_loc_local_set_t;
+
+/** Parameters of Generic User Property Set state change event */
+typedef struct {
+    uint16_t id;    /*!< The property id of Generic User Property state */
+    struct net_buf_simple *value;   /*!< The property value of Generic User Property state */
+} esp_ble_mesh_state_change_gen_user_property_set_t;
+
+/** Parameters of Generic Admin Property Set state change event */
+typedef struct {
+    uint16_t id;        /*!< The property id of Generic Admin Property state */
+    uint8_t  access;    /*!< The property access of Generic Admin Property state */
+    struct net_buf_simple *value;   /*!< The property value of Generic Admin Property state */
+} esp_ble_mesh_state_change_gen_admin_property_set_t;
+
+/** Parameters of Generic Manufacturer Property Set state change event */
+typedef struct {
+    uint16_t id;        /*!< The property id of Generic Manufacturer Property state */
+    uint8_t  access;    /*!< The property value of Generic Manufacturer Property state */
+} esp_ble_mesh_state_change_gen_manu_property_set_t;
+
+/**
+ * @brief Generic Server Model state change value union
+ */
+typedef union {
+    /**
+     * The recv_op in ctx can be used to decide which state is changed.
+     */
+    esp_ble_mesh_state_change_gen_onoff_set_t          onoff_set;           /*!< Generic OnOff Set */
+    esp_ble_mesh_state_change_gen_level_set_t          level_set;           /*!< Generic Level Set */
+    esp_ble_mesh_state_change_gen_delta_set_t          delta_set;           /*!< Generic Delta Set */
+    esp_ble_mesh_state_change_gen_move_set_t           move_set;            /*!< Generic Move Set */
+    esp_ble_mesh_state_change_gen_def_trans_time_set_t def_trans_time_set;  /*!< Generic Default Transition Time Set */
+    esp_ble_mesh_state_change_gen_onpowerup_set_t      onpowerup_set;       /*!< Generic OnPowerUp Set */
+    esp_ble_mesh_state_change_gen_power_level_set_t    power_level_set;     /*!< Generic Power Level Set */
+    esp_ble_mesh_state_change_gen_power_default_set_t  power_default_set;   /*!< Generic Power Default Set */
+    esp_ble_mesh_state_change_gen_power_range_set_t    power_range_set;     /*!< Generic Power Range Set */
+    esp_ble_mesh_state_change_gen_loc_global_set_t     loc_global_set;      /*!< Generic Location Global Set */
+    esp_ble_mesh_state_change_gen_loc_local_set_t      loc_local_set;       /*!< Generic Location Local Set */
+    esp_ble_mesh_state_change_gen_user_property_set_t  user_property_set;   /*!< Generic User Property Set */
+    esp_ble_mesh_state_change_gen_admin_property_set_t admin_property_set;  /*!< Generic Admin Property Set */
+    esp_ble_mesh_state_change_gen_manu_property_set_t  manu_property_set;   /*!< Generic Manufactuer Property Set */
+} esp_ble_mesh_generic_server_state_change_t;
+
+/** Context of the received Generic User Property Get message */
+typedef struct {
+    uint16_t property_id;       /*!< Property ID identifying a Generic User Property */
+} esp_ble_mesh_server_recv_gen_user_property_get_t;
+
+/** Context of the received Generic Admin Property Get message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID identifying a Generic Admin Property */
+} esp_ble_mesh_server_recv_gen_admin_property_get_t;
+
+/** Context of the received Generic Manufacturer Property message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID identifying a Generic Manufacturer Property */
+} esp_ble_mesh_server_recv_gen_manufacturer_property_get_t;
+
+/** Context of the received Generic Client Properties Get message */
+typedef struct {
+    uint16_t property_id;   /*!< A starting Client Property ID present within an element */
+} esp_ble_mesh_server_recv_gen_client_properties_get_t;
+
+/**
+ * @brief Generic Server Model received get message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_gen_user_property_get_t         user_property;     /*!< Generic User Property Get */
+    esp_ble_mesh_server_recv_gen_admin_property_get_t        admin_property;    /*!< Generic Admin Property Get */
+    esp_ble_mesh_server_recv_gen_manufacturer_property_get_t manu_property;     /*!< Generic Manufacturer Property Get */
+    esp_ble_mesh_server_recv_gen_client_properties_get_t     client_properties; /*!< Generic Client Properties Get */
+} esp_ble_mesh_generic_server_recv_get_msg_t;
+
+/** Context of the received Generic OnOff Set message */
+typedef struct {
+    bool    op_en;          /*!< Indicate if optional parameters are included */
+    uint8_t onoff;          /*!< Target value of Generic OnOff state */
+    uint8_t tid;            /*!< Transaction ID */
+    uint8_t trans_time;     /*!< Time to complete state transition (optional) */
+    uint8_t delay;          /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_gen_onoff_set_t;
+
+/** Context of the received Generic Level Set message */
+typedef struct {
+    bool    op_en;          /*!< Indicate if optional parameters are included */
+    int16_t level;          /*!< Target value of Generic Level state */
+    uint8_t tid;            /*!< Transaction ID */
+    uint8_t trans_time;     /*!< Time to complete state transition (optional) */
+    uint8_t delay;          /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_gen_level_set_t;
+
+/** Context of the received Generic Delta Set message */
+typedef struct {
+    bool    op_en;          /*!< Indicate if optional parameters are included */
+    int32_t delta_level;    /*!< Delta change of Generic Level state */
+    uint8_t tid;            /*!< Transaction ID */
+    uint8_t trans_time;     /*!< Time to complete state transition (optional) */
+    uint8_t delay;          /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_gen_delta_set_t;
+
+/** Context of the received Generic Move Set message */
+typedef struct {
+    bool    op_en;          /*!< Indicate if optional parameters are included */
+    int16_t delta_level;    /*!< Delta Level step to calculate Move speed for Generic Level state */
+    uint8_t tid;            /*!< Transaction ID */
+    uint8_t trans_time;     /*!< Time to complete state transition (optional) */
+    uint8_t delay;          /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_gen_move_set_t;
+
+/** Context of the received Generic Default Transition Time Set message */
+typedef struct {
+    uint8_t trans_time;     /*!< The value of the Generic Default Transition Time state */
+} esp_ble_mesh_server_recv_gen_def_trans_time_set_t;
+
+/** Context of the received Generic OnPowerUp Set message */
+typedef struct {
+    uint8_t onpowerup;      /*!< The value of the Generic OnPowerUp state */
+} esp_ble_mesh_server_recv_gen_onpowerup_set_t;
+
+/** Context of the received Generic Power Level Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t power;         /*!< Target value of Generic Power Actual state */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_gen_power_level_set_t;
+
+/** Context of the received Generic Power Default Set message */
+typedef struct {
+    uint16_t power;         /*!< The value of the Generic Power Default state */
+} esp_ble_mesh_server_recv_gen_power_default_set_t;
+
+/** Context of the received Generic Power Range Set message */
+typedef struct {
+    uint16_t range_min;     /*!< Value of Range Min field of Generic Power Range state */
+    uint16_t range_max;     /*!< Value of Range Max field of Generic Power Range state */
+} esp_ble_mesh_server_recv_gen_power_range_set_t;
+
+/** Context of the received Generic Location Global Set message */
+typedef struct {
+    int32_t global_latitude;    /*!< Global Coordinates (Latitude) */
+    int32_t global_longitude;   /*!< Global Coordinates (Longitude) */
+    int16_t global_altitude;    /*!< Global Altitude */
+} esp_ble_mesh_server_recv_gen_loc_global_set_t;
+
+/** Context of the received Generic Location Local Set message */
+typedef struct {
+    int16_t  local_north;       /*!< Local Coordinates (North) */
+    int16_t  local_east;        /*!< Local Coordinates (East) */
+    int16_t  local_altitude;    /*!< Local Altitude */
+    uint8_t  floor_number;      /*!< Floor Number */
+    uint16_t uncertainty;       /*!< Uncertainty */
+} esp_ble_mesh_server_recv_gen_loc_local_set_t;
+
+/** Context of the received Generic User Property Set message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID identifying a Generic User Property */
+    struct net_buf_simple *property_value;  /*!< Raw value for the User Property */
+} esp_ble_mesh_server_recv_gen_user_property_set_t;
+
+/** Context of the received Generic Admin Property Set message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID identifying a Generic Admin Property */
+    uint8_t  user_access;   /*!< Enumeration indicating user accessn */
+    struct net_buf_simple *property_value;  /*!< Raw value for the Admin Property */
+} esp_ble_mesh_server_recv_gen_admin_property_set_t;
+
+/** Context of the received Generic Manufacturer Property Set message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID identifying a Generic Manufacturer Property */
+    uint8_t  user_access;   /*!< Enumeration indicating user access */
+} esp_ble_mesh_server_recv_gen_manufacturer_property_set_t;
+
+/**
+ * @brief Generic Server Model received set message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_gen_onoff_set_t                 onoff;             /*!< Generic OnOff Set/Generic OnOff Set Unack */
+    esp_ble_mesh_server_recv_gen_level_set_t                 level;             /*!< Generic Level Set/Generic Level Set Unack */
+    esp_ble_mesh_server_recv_gen_delta_set_t                 delta;             /*!< Generic Delta Set/Generic Delta Set Unack */
+    esp_ble_mesh_server_recv_gen_move_set_t                  move;              /*!< Generic Move Set/Generic Move Set Unack */
+    esp_ble_mesh_server_recv_gen_def_trans_time_set_t        def_trans_time;    /*!< Generic Default Transition Time Set/Generic Default Transition Time Set Unack */
+    esp_ble_mesh_server_recv_gen_onpowerup_set_t             onpowerup;         /*!< Generic OnPowerUp Set/Generic OnPowerUp Set Unack */
+    esp_ble_mesh_server_recv_gen_power_level_set_t           power_level;       /*!< Generic Power Level Set/Generic Power Level Set Unack */
+    esp_ble_mesh_server_recv_gen_power_default_set_t         power_default;     /*!< Generic Power Default Set/Generic Power Default Set Unack */
+    esp_ble_mesh_server_recv_gen_power_range_set_t           power_range;       /*!< Generic Power Range Set/Generic Power Range Set Unack */
+    esp_ble_mesh_server_recv_gen_loc_global_set_t            location_global;   /*!< Generic Location Global Set/Generic Location Global Set Unack */
+    esp_ble_mesh_server_recv_gen_loc_local_set_t             location_local;    /*!< Generic Location Local Set/Generic Location Local Set Unack */
+    esp_ble_mesh_server_recv_gen_user_property_set_t         user_property;     /*!< Generic User Property Set/Generic User Property Set Unack */
+    esp_ble_mesh_server_recv_gen_admin_property_set_t        admin_property;    /*!< Generic Admin Property Set/Generic Admin Property Set Unack */
+    esp_ble_mesh_server_recv_gen_manufacturer_property_set_t manu_property;     /*!< Generic Manufacturer Property Set/Generic Manufacturer Property Set Unack */
+} esp_ble_mesh_generic_server_recv_set_msg_t;
+
+/**
+ * @brief Generic Server Model callback value union
+ */
+typedef union {
+    esp_ble_mesh_generic_server_state_change_t state_change;    /*!< ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT */
+    esp_ble_mesh_generic_server_recv_get_msg_t get;     /*!< ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT */
+    esp_ble_mesh_generic_server_recv_set_msg_t set;     /*!< ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT */
+} esp_ble_mesh_generic_server_cb_value_t;
+
+/** Generic Server Model callback parameters */
+typedef struct {
+    esp_ble_mesh_model_t  *model;   /*!< Pointer to Generic Server Models */
+    esp_ble_mesh_msg_ctx_t ctx;     /*!< Context of the received messages */
+    esp_ble_mesh_generic_server_cb_value_t value;   /*!< Value of the received Generic Messages */
+} esp_ble_mesh_generic_server_cb_param_t;
+
+/** This enum value is the event of Generic Server Model */
+typedef enum {
+    /**
+     * 1. When get_auto_rsp is set to ESP_BLE_MESH_SERVER_AUTO_RSP, no event will be
+     *    callback to the application layer when Generic Get messages are received.
+     * 2. When set_auto_rsp is set to ESP_BLE_MESH_SERVER_AUTO_RSP, this event will
+     *    be callback to the application layer when Generic Set/Set Unack messages
+     *    are received.
+     */
+    ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT,
+    /**
+     * When get_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will be
+     * callback to the application layer when Generic Get messages are received.
+     */
+    ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT,
+    /**
+     * When set_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will be
+     * callback to the application layer when Generic Set/Set Unack messages are received.
+     */
+    ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT,
+    ESP_BLE_MESH_GENERIC_SERVER_EVT_MAX,
+} esp_ble_mesh_generic_server_cb_event_t;
+
+/**
+ *  @brief Bluetooth Mesh Generic Server Model function.
+ */
+
+/**
+ * @brief   Generic Server Model callback function type
+ * @param   event: Event type
+ * @param   param: Pointer to callback parameter
+ */
+typedef void (* esp_ble_mesh_generic_server_cb_t)(esp_ble_mesh_generic_server_cb_event_t event,
+            esp_ble_mesh_generic_server_cb_param_t *param);
+
+/**
+ * @brief       Register BLE Mesh Generic Server Model callback.
+ *
+ * @param[in]   callback: Pointer to the callback function.
+ *
+ * @return      ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_register_generic_server_callback(esp_ble_mesh_generic_server_cb_t callback);
 
 #endif /* _ESP_BLE_MESH_GENERIC_MODEL_API_H_ */
 

+ 1091 - 0
components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h

@@ -579,6 +579,1097 @@ esp_err_t esp_ble_mesh_light_client_get_state(esp_ble_mesh_client_common_param_t
 esp_err_t esp_ble_mesh_light_client_set_state(esp_ble_mesh_client_common_param_t *params,
         esp_ble_mesh_light_client_set_state_t *set_state);
 
+/**
+ * @brief Lighting Server Models related context.
+ */
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_LIGHTNESS_SRV
+ *
+ *  @brief  Define a new Light Lightness Server Model.
+ *
+ *  @note   1. The Light Lightness Server model extends the Generic Power OnOff
+ *             Server model and the Generic Level Server model. When this model
+ *             is present on an Element, the corresponding Light Lightness Setup
+ *             Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_lightness_srv_t.
+ *
+ *  @return New Light Lightness Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_LIGHTNESS_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_LIGHTNESS_SETUP_SRV
+ *
+ *  @brief  Define a new Light Lightness Setup Server Model.
+ *
+ *  @note   1. The Light Lightness Setup Server model extends the Light Lightness
+ *             Server model and the Generic Power OnOff Setup Server model.
+ *          2. This model shall support model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_lightness_setup_srv_t.
+ *
+ *  @return New Light Lightness Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_LIGHTNESS_SETUP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_CTL_SRV
+ *
+ *  @brief  Define a new Light CTL Server Model.
+ *
+ *  @note   1. The Light CTL Server model extends the Light Lightness Server model.
+ *             When this model is present on an Element, the corresponding Light
+ *             CTL Temperature Server model and the corresponding Light CTL Setup
+ *             Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *          3. The model requires two elements: the main element and the Temperature
+ *             element. The Temperature element contains the corresponding Light CTL
+ *             Temperature Server model and an instance of a Generic Level state
+ *             bound to the Light CTL Temperature state on the Temperature element.
+ *             The Light CTL Temperature state on the Temperature element is bound to
+ *             the Light CTL state on the main element.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_ctl_srv_t.
+ *
+ *  @return New Light CTL Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_CTL_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_CTL_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_CTL_SETUP_SRV
+ *
+ *  @brief  Define a new Light CTL Setup Server Model.
+ *
+ *  @note   1. The Light CTL Setup Server model extends the Light CTL Server and
+ *             the Light Lightness Setup Server.
+ *          2. This model shall support model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_ctl_setup_srv_t.
+ *
+ *  @return New Light CTL Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_CTL_SETUP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_CTL_TEMP_SRV
+ *
+ *  @brief  Define a new Light CTL Temperature Server Model.
+ *
+ *  @note   1. The Light CTL Temperature Server model extends the Generic Level
+ *             Server model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_ctl_temp_srv_t.
+ *
+ *  @return New Light CTL Temperature Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_CTL_TEMP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_HSL_SRV
+ *
+ *  @brief  Define a new Light HSL Server Model.
+ *
+ *  @note   1. The Light HSL Server model extends the Light Lightness Server model. When
+ *             this model is present on an Element, the corresponding Light HSL Hue
+ *             Server model and the corresponding Light HSL Saturation Server model and
+ *             the corresponding Light HSL Setup Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *          3. The model requires three elements: the main element and the Hue element
+ *             and the Saturation element. The Hue element contains the corresponding
+ *             Light HSL Hue Server model and an instance of a Generic Level state bound
+ *             to the Light HSL Hue state on the Hue element. The Saturation element
+ *             contains the corresponding Light HSL Saturation Server model and an
+ *             instance of a Generic Level state bound to the Light HSL Saturation state
+ *             on the Saturation element. The Light HSL Hue state on the Hue element is
+ *             bound to the Light HSL state on the main element and the Light HSL
+ *             Saturation state on the Saturation element is bound to the Light HSL state
+ *             on the main element.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_hsl_srv_t.
+ *
+ *  @return New Light HSL Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_HSL_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_HSL_SETUP_SRV
+ *
+ *  @brief  Define a new Light HSL Setup Server Model.
+ *
+ *  @note   1. The Light HSL Setup Server model extends the Light HSL Server and
+ *             the Light Lightness Setup Server.
+ *          2. This model shall support model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_hsl_setup_srv_t.
+ *
+ *  @return New Light HSL Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_HSL_SETUP_SRV(srv_pub, srv_data)           \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV,   \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_HSL_HUE_SRV
+ *
+ *  @brief  Define a new Light HSL Hue Server Model.
+ *
+ *  @note   1. The Light HSL Hue Server model extends the Generic Level Server model.
+ *             This model is associated with the Light HSL Server model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_hsl_hue_srv_t.
+ *
+ *  @return New Light HSL Hue Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_HSL_HUE_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_HSL_SAT_SRV
+ *
+ *  @brief  Define a new Light HSL Saturation Server Model.
+ *
+ *  @note   1. The Light HSL Saturation Server model extends the Generic Level Server
+ *             model. This model is associated with the Light HSL Server model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_hsl_sat_srv_t.
+ *
+ *  @return New Light HSL Saturation Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_HSL_SAT_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_XYL_SRV
+ *
+ *  @brief  Define a new Light xyL Server Model.
+ *
+ *  @note   1. The Light xyL Server model extends the Light Lightness Server model.
+ *             When this model is present on an Element, the corresponding Light xyL
+ *             Setup Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_xyl_srv_t.
+ *
+ *  @return New Light xyL Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_XYL_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_XYL_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_XYL_SETUP_SRV
+ *
+ *  @brief  Define a new Light xyL Setup Server Model.
+ *
+ *  @note   1. The Light xyL Setup Server model extends the Light xyL Server and
+ *             the Light Lightness Setup Server.
+ *          2. This model shall support model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_xyl_setup_srv_t.
+ *
+ *  @return New Light xyL Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_XYL_SETUP_SRV(srv_pub, srv_data)           \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV,   \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_LC_SRV
+ *
+ *  @brief  Define a new Light LC Server Model.
+ *
+ *  @note   1. The Light LC (Lightness Control) Server model extends the Light
+ *             Lightness Server model and the Generic OnOff Server model. When
+ *             this model is present on an Element, the corresponding Light LC
+ *             Setup Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *          3. This model may be used to represent an element that is a client to
+ *             a Sensor Server model and controls the Light Lightness Actual state
+ *             via defined state bindings.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_lc_srv_t.
+ *
+ *  @return New Light LC Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_LC_SRV(srv_pub, srv_data)           \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SRV,   \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_LIGHT_LC_SETUP_SRV
+ *
+ *  @brief  Define a new Light LC Setup Server Model.
+ *
+ *  @note   1. The Light LC (Lightness Control) Setup model extends the Light LC
+ *             Server model.
+ *          2. This model shall support model publication and model subscription.
+ *          3. This model may be used to configure setup parameters for the Light
+ *             LC Server model.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_light_lc_setup_srv_t.
+ *
+ *  @return New Light LC Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_LIGHT_LC_SETUP_SRV(srv_pub, srv_data)           \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV,   \
+                    NULL, srv_pub, srv_data)
+
+/** Parameters of Light Lightness state */
+typedef struct {
+    uint16_t lightness_linear;          /*!< The present value of Light Lightness Linear state */
+    uint16_t target_lightness_linear;   /*!< The target value of Light Lightness Linear state */
+
+    uint16_t lightness_actual;          /*!< The present value of Light Lightness Actual state */
+    uint16_t target_lightness_actual;   /*!< The target value of Light Lightness Actual state */
+
+    uint16_t lightness_last;            /*!< The value of Light Lightness Last state */
+    uint16_t lightness_default;         /*!< The value of Light Lightness Default state */
+
+    uint8_t  status_code;               /*!< The status code of setting Light Lightness Range state */
+    uint16_t lightness_range_min;       /*!< The minimum value of Light Lightness Range state */
+    uint16_t lightness_range_max;       /*!< The maximum value of Light Lightness Range state */
+} esp_ble_mesh_light_lightness_state_t;
+
+/** User data of Light Lightness Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                    /*!< Pointer to the Lighting Lightness Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;        /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_lightness_state_t *state;    /*!< Parameters of the Light Lightness state */
+    esp_ble_mesh_last_msg_info_t last;              /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t actual_transition;  /*!< Parameters of state transition */
+    esp_ble_mesh_state_transition_t linear_transition;  /*!< Parameters of state transition */
+    int32_t tt_delta_lightness_actual;      /*!< Delta change value of lightness actual state transition */
+    int32_t tt_delta_lightness_linear;      /*!< Delta change value of lightness linear state transition */
+} esp_ble_mesh_light_lightness_srv_t;
+
+/** User data of Light Lightness Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                    /*!< Pointer to the Lighting Lightness Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;        /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_lightness_state_t *state;    /*!< Parameters of the Light Lightness state */
+} esp_ble_mesh_light_lightness_setup_srv_t;
+
+/** Parameters of Light CTL state */
+typedef struct {
+    uint16_t lightness;             /*!< The present value of Light CTL Lightness state */
+    uint16_t target_lightness;      /*!< The target value of Light CTL Lightness state */
+
+    uint16_t temperature;           /*!< The present value of Light CTL Temperature state */
+    uint16_t target_temperature;    /*!< The target value of Light CTL Temperature state */
+
+    int16_t  delta_uv;              /*!< The present value of Light CTL Delta UV state */
+    int16_t  target_delta_uv;       /*!< The target value of Light CTL Delta UV state */
+
+    uint8_t  status_code;           /*!< The statue code of setting Light CTL Temperature Range state */
+    uint16_t temperature_range_min; /*!< The minimum value of Light CTL Temperature Range state */
+    uint16_t temperature_range_max; /*!< The maximum value of Light CTL Temperature Range state */
+
+    uint16_t lightness_default;     /*!< The value of Light Lightness Default state */
+    uint16_t temperature_default;   /*!< The value of Light CTL Temperature Default state */
+    int16_t  delta_uv_default;      /*!< The value of Light CTL Delta UV Default state */
+} esp_ble_mesh_light_ctl_state_t;
+
+/** User data of Light CTL Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting CTL Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_ctl_state_t *state;      /*!< Parameters of the Light CTL state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+    int32_t tt_delta_lightness;     /*!< Delta change value of lightness state transition */
+    int32_t tt_delta_temperature;   /*!< Delta change value of temperature state transition */
+    int32_t tt_delta_delta_uv;      /*!< Delta change value of delta uv state transition */
+} esp_ble_mesh_light_ctl_srv_t;
+
+/** User data of Light CTL Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting CTL Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_ctl_state_t *state;      /*!< Parameters of the Light CTL state */
+} esp_ble_mesh_light_ctl_setup_srv_t;
+
+/** User data of Light CTL Temperature Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting CTL Temperature Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_ctl_state_t *state;      /*!< Parameters of the Light CTL state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+    int32_t tt_delta_temperature;   /*!< Delta change value of temperature state transition */
+    int32_t tt_delta_delta_uv;      /*!< Delta change value of delta uv state transition */
+} esp_ble_mesh_light_ctl_temp_srv_t;
+
+/** Parameters of Light HSL state */
+typedef struct {
+    uint16_t lightness;             /*!< The present value of Light HSL Lightness state */
+    uint16_t target_lightness;      /*!< The target value of Light HSL Lightness state */
+
+    uint16_t hue;                   /*!< The present value of Light HSL Hue state */
+    uint16_t target_hue;            /*!< The target value of Light HSL Hue state */
+
+    uint16_t saturation;            /*!< The present value of Light HSL Saturation state */
+    uint16_t target_saturation;     /*!< The target value of Light HSL Saturation state */
+
+    uint16_t lightness_default;     /*!< The value of Light Lightness Default state */
+    uint16_t hue_default;           /*!< The value of Light HSL Hue Default state */
+    uint16_t saturation_default;    /*!< The value of Light HSL Saturation Default state */
+
+    uint8_t  status_code;           /*!< The status code of setting Light HSL Hue & Saturation Range state */
+    uint16_t hue_range_min;         /*!< The minimum value of Light HSL Hue Range state */
+    uint16_t hue_range_max;         /*!< The maximum value of Light HSL Hue Range state */
+    uint16_t saturation_range_min;  /*!< The minimum value of Light HSL Saturation state */
+    uint16_t saturation_range_max;  /*!< The maximum value of Light HSL Saturation state */
+} esp_ble_mesh_light_hsl_state_t;
+
+/** User data of Light HSL Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting HSL Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_hsl_state_t *state;      /*!< Parameters of the Light HSL state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+    int32_t tt_delta_lightness;     /*!< Delta change value of lightness state transition */
+    int32_t tt_delta_hue;           /*!< Delta change value of hue state transition */
+    int32_t tt_delta_saturation;    /*!< Delta change value of saturation state transition */
+} esp_ble_mesh_light_hsl_srv_t;
+
+/** User data of Light HSL Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting HSL Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_hsl_state_t *state;      /*!< Parameters of the Light HSL state */
+} esp_ble_mesh_light_hsl_setup_srv_t;
+
+/** User data of Light HSL Hue Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting HSL Hue Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_hsl_state_t *state;      /*!< Parameters of the Light HSL state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+    int32_t tt_delta_hue;   /*!< Delta change value of hue state transition */
+} esp_ble_mesh_light_hsl_hue_srv_t;
+
+/** User data of Light HSL Saturation Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;    /*!< Pointer to the Lighting HSL Saturation Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_hsl_state_t *state;      /*!< Parameters of the Light HSL state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+    int32_t tt_delta_saturation;    /*!< Delta change value of saturation state transition */
+} esp_ble_mesh_light_hsl_sat_srv_t;
+
+/** Parameters of Light xyL state */
+typedef struct {
+    uint16_t lightness;         /*!< The present value of Light xyL Lightness state */
+    uint16_t target_lightness;  /*!< The target value of Light xyL Lightness state */
+
+    uint16_t x;                 /*!< The present value of Light xyL x state */
+    uint16_t target_x;          /*!< The target value of Light xyL x state */
+
+    uint16_t y;                 /*!< The present value of Light xyL y state */
+    uint16_t target_y;          /*!< The target value of Light xyL y state */
+
+    uint16_t lightness_default; /*!< The value of Light Lightness Default state */
+    uint16_t x_default;         /*!< The value of Light xyL x Default state */
+    uint16_t y_default;         /*!< The value of Light xyL y Default state */
+
+    uint8_t  status_code;       /*!< The status code of setting Light xyL x & y Range state */
+    uint16_t x_range_min;       /*!< The minimum value of Light xyL x Range state */
+    uint16_t x_range_max;       /*!< The maximum value of Light xyL x Range state */
+    uint16_t y_range_min;       /*!< The minimum value of Light xyL y Range state */
+    uint16_t y_range_max;       /*!< The maximum value of Light xyL y Range state */
+} esp_ble_mesh_light_xyl_state_t;
+
+/** User data of Light xyL Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting xyL Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_xyl_state_t *state;      /*!< Parameters of the Light xyL state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+    int32_t tt_delta_lightness; /*!< Delta change value of lightness state transition */
+    int32_t tt_delta_x;         /*!< Delta change value of x state transition */
+    int32_t tt_delta_y;         /*!< Delta change value of y state transition */
+} esp_ble_mesh_light_xyl_srv_t;
+
+/** User data of Light xyL Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting xyL Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_xyl_state_t *state;      /*!< Parameters of the Light xyL state */
+} esp_ble_mesh_light_xyl_setup_srv_t;
+
+/** Parameters of Light LC states */
+typedef struct {
+    /**
+     * 0b0 The controller is turned off.
+     * - The binding with the Light Lightness state is disabled.
+     * 0b1 The controller is turned on.
+     * - The binding with the Light Lightness state is enabled.
+     */
+    uint32_t mode : 1,                  /*!< The value of Light LC Mode state */
+             occupancy_mode : 1,        /*!< The value of Light LC Occupancy Mode state */
+             light_onoff : 1,           /*!< The present value of Light LC Light OnOff state */
+             target_light_onoff : 1,    /*!< The target value of Light LC Light OnOff state */
+             occupancy : 1,             /*!< The value of Light LC Occupancy state */
+             ambient_luxlevel : 24;     /*!< The value of Light LC Ambient LuxLevel state */
+
+    /**
+     * 1. Light LC Linear Output = max((Lightness Out)^2/65535, Regulator Output)
+     * 2. If the Light LC Mode state is set to 0b1, the binding is enabled and upon
+     *    a change of the Light LC Linear Output state, the following operation
+     *    shall be performed:
+     *    Light Lightness Linear = Light LC Linear Output
+     * 3. If the Light LC Mode state is set to 0b0, the binding is disabled (i.e.,
+     *    upon a change of the Light LC Linear Output state, no operation on the
+     *    Light Lightness Linear state is performed).
+     */
+    uint16_t linear_output;     /*!< The value of Light LC Linear Output state */
+} esp_ble_mesh_light_lc_state_t;
+
+/**
+ * Parameters of Light Property states.
+ * The Light LC Property states are read / write states that determine the
+ * configuration of a Light Lightness Controller. Each state is represented
+ * by a device property and is controlled by Light LC Property messages.
+ */
+typedef struct {
+    /**
+     * A timing state that determines the delay for changing the Light LC
+     * Occupancy state upon receiving a Sensor Status message from an
+     * occupancy sensor.
+     */
+    uint32_t time_occupancy_delay;  /*!< The value of Light LC Time Occupany Delay state */
+    /**
+     * A timing state that determines the time the controlled lights fade
+     * to the level determined by the Light LC Lightness On state.
+     */
+    uint32_t time_fade_on;      /*!< The value of Light LC Time Fade On state */
+    /**
+     * A timing state that determines the time the controlled lights stay
+     * at the level determined by the Light LC Lightness On state.
+     */
+    uint32_t time_run_on;       /*!< The value of Light LC Time Run On state */
+    /**
+     * A timing state that determines the time the controlled lights fade
+     * from the level determined by the Light LC Lightness On state to the
+     * level determined by the Light Lightness Prolong state.
+     */
+    uint32_t time_fade;         /*!< The value of Light LC Time Fade state */
+    /**
+     * A timing state that determines the time the controlled lights stay at
+     * the level determined by the Light LC Lightness Prolong state.
+     */
+    uint32_t time_prolong;      /*!< The value of Light LC Time Prolong state */
+    /**
+     * A timing state that determines the time the controlled lights fade from
+     * the level determined by the Light LC Lightness Prolong state to the level
+     * determined by the Light LC Lightness Standby state when the transition is
+     * automatic.
+     */
+    uint32_t time_fade_standby_auto;    /*!< The value of Light LC Time Fade Standby Auto state */
+    /**
+     * A timing state that determines the time the controlled lights fade from
+     * the level determined by the Light LC Lightness Prolong state to the level
+     * determined by the Light LC Lightness Standby state when the transition is
+     * triggered by a change in the Light LC Light OnOff state.
+     */
+    uint32_t time_fade_standby_manual;  /*!< The value of Light LC Time Fade Standby Manual state */
+
+    /**
+     * A lightness state that determines the perceptive light lightness at the
+     * Occupancy and Run internal controller states.
+     */
+    uint16_t lightness_on;          /*!< The value of Light LC Lightness On state */
+    /**
+     * A lightness state that determines the light lightness at the Prolong
+     * internal controller state.
+     */
+    uint16_t lightness_prolong;     /*!< The value of Light LC Lightness Prolong state */
+    /**
+     * A lightness state that determines the light lightness at the Standby
+     * internal controller state.
+     */
+    uint16_t lightness_standby;     /*!< The value of Light LC Lightness Standby state */
+
+    /**
+     * A uint16 state representing the Ambient LuxLevel level that determines
+     * if the controller transitions from the Light Control Standby state.
+     */
+    uint16_t ambient_luxlevel_on;       /*!< The value of Light LC Ambient LuxLevel On state */
+    /**
+     * A uint16 state representing the required Ambient LuxLevel level in the
+     * Prolong state.
+     */
+    uint16_t ambient_luxlevel_prolong;  /*!< The value of Light LC Ambient LuxLevel Prolong state */
+    /**
+     * A uint16 state representing the required Ambient LuxLevel level in the
+     * Standby state.
+     */
+    uint16_t ambient_luxlevel_standby;  /*!< The value of Light LC Ambient LuxLevel Standby state */
+
+    /**
+     * A float32 state representing the integral coefficient that determines the
+     * integral part of the equation defining the output of the Light LC PI
+     * Feedback Regulator, when Light LC Ambient LuxLevel is less than LuxLevel
+     * Out. Valid range: 0.0 ~ 1000.0. The default value is 250.0.
+     */
+    float regulator_kiu;    /*!< The value of Light LC Regulator Kiu state */
+    /**
+     * A float32 state representing the integral coefficient that determines the
+     * integral part of the equation defining the output of the Light LC PI
+     * Feedback Regulator, when Light LC Ambient LuxLevel is greater than or equal
+     * to the value of the LuxLevel Out state. Valid range: 0.0 ~ 1000.0. The
+     * default value is 25.0.
+     */
+    float regulator_kid;    /*!< The value of Light LC Regulator Kid state */
+    /**
+     * A float32 state representing the proportional coefficient that determines
+     * the proportional part of the equation defining the output of the Light LC
+     * PI Feedback Regulator, when Light LC Ambient LuxLevel is less than the value
+     * of the LuxLevel Out state. Valid range: 0.0 ~ 1000.0. The default value is 80.0.
+     */
+    float regulator_kpu;    /*!< The value of Light LC Regulator Kpu state */
+    /**
+     * A float32 state representing the proportional coefficient that determines
+     * the proportional part of the equation defining the output of the Light LC PI
+     * Feedback Regulator, when Light LC Ambient LuxLevel is greater than or equal
+     * to the value of the LuxLevel Out state. Valid range: 0.0 ~ 1000.0. The default
+     * value is 80.0.
+     */
+    float regulator_kpd;    /*!< The value of Light LC Regulator Kpd state */
+    /**
+     * A int8 state representing the percentage accuracy of the Light LC PI Feedback
+     * Regulator. Valid range: 0.0 ~ 100.0. The default value is 2.0.
+     */
+    int8_t regulator_accuracy;  /*!< The value of Light LC Regulator Accuracy state */
+
+    /**
+     * If the message Raw field contains a Raw Value for the Time Since Motion
+     * Sensed device property, which represents a value less than or equal to
+     * the value of the Light LC Occupancy Delay state, it shall delay setting
+     * the Light LC Occupancy state to 0b1 by the difference between the value
+     * of the Light LC Occupancy Delay state and the received Time Since Motion
+     * value.
+     */
+    uint32_t set_occupancy_to_1_delay;  /*!< The value of the difference between value of the
+                                            Light LC Occupancy Delay state and the received
+                                            Time Since Motion value */
+} esp_ble_mesh_light_lc_property_state_t;
+
+/** This enum value is the Light LC State Machine states */
+typedef enum {
+    ESP_BLE_MESH_LC_OFF,
+    ESP_BLE_MESH_LC_STANDBY,
+    ESP_BLE_MESH_LC_FADE_ON,
+    ESP_BLE_MESH_LC_RUN,
+    ESP_BLE_MESH_LC_FADE,
+    ESP_BLE_MESH_LC_PROLONG,
+    ESP_BLE_MESH_LC_FADE_STANDBY_AUTO,
+    ESP_BLE_MESH_LC_FADE_STANDBY_MANUAL,
+} esp_ble_mesh_lc_state_t;
+
+/** Parameters of Light LC state machine */
+typedef struct {
+    /**
+     * The Fade On, Fade, Fade Standby Auto, and Fade Standby Manual states are
+     * transition states that define the transition of the Lightness Out and
+     * LuxLevel Out states. This transition can be started as a result of the
+     * Light LC State Machine change or as a result of receiving the Light LC
+     * Light OnOff Set or Light LC Light Set Unacknowledged message.
+     */
+    struct {
+        uint8_t fade_on;                /*!< The value of transition time of Light LC Time Fade On */
+        uint8_t fade;                   /*!< The value of transition time of Light LC Time Fade */
+        uint8_t fade_standby_auto;      /*!< The value of transition time of Light LC Time Fade Standby Auto */
+        uint8_t fade_standby_manual;    /*!< The value of transition time of Light LC Time Fade Standby Manual */
+    } trans_time;                       /*!< The value of transition time */
+    esp_ble_mesh_lc_state_t state;      /*!< The value of Light LC state machine state */
+    struct k_delayed_work timer;        /*!< Timer of Light LC state machine */
+} esp_ble_mesh_light_lc_state_machine_t;
+
+/** Parameters of Light Lightness controller */
+typedef struct {
+    esp_ble_mesh_light_lc_state_t          state;           /*!< Parameters of Light LC state */
+    esp_ble_mesh_light_lc_property_state_t prop_state;      /*!< Parameters of Light LC Property state */
+    esp_ble_mesh_light_lc_state_machine_t  state_machine;   /*!< Parameters of Light LC state machine */
+} esp_ble_mesh_light_control_t;
+
+/** User data of Light LC Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting LC Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_control_t *lc;           /*!< Parameters of the Light controller */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+} esp_ble_mesh_light_lc_srv_t;
+
+/** User data of Light LC Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Lighting LC Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_light_control_t *lc;           /*!< Parameters of the Light controller */
+} esp_ble_mesh_light_lc_setup_srv_t;
+
+/** Parameter of Light Lightness Actual state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light Lightness Actual state */
+} esp_ble_mesh_state_change_light_lightness_set_t;
+
+/** Parameter of Light Lightness Linear state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light Lightness Linear state */
+} esp_ble_mesh_state_change_light_lightness_linear_set_t;
+
+/** Parameter of Light Lightness Default state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light Lightness Default state */
+} esp_ble_mesh_state_change_light_lightness_default_set_t;
+
+/** Parameters of Light Lightness Range state change event */
+typedef struct {
+    uint16_t range_min;     /*!< The minimum value of Light Lightness Range state */
+    uint16_t range_max;     /*!< The maximum value of Light Lightness Range state */
+} esp_ble_mesh_state_change_light_lightness_range_set_t;
+
+/** Parameters of Light CTL state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light CTL Lightness state */
+    uint16_t temperature;   /*!< The value of Light CTL Temperature state */
+    int16_t  delta_uv;      /*!< The value of Light CTL Delta UV state */
+} esp_ble_mesh_state_change_light_ctl_set_t;
+
+/** Parameters of Light CTL Temperature state change event */
+typedef struct {
+    uint16_t temperature;   /*!< The value of Light CTL Temperature state */
+    int16_t  delta_uv;      /*!< The value of Light CTL Delta UV state */
+} esp_ble_mesh_state_change_light_ctl_temperature_set_t;
+
+/** Parameters of Light CTL Temperature Range state change event */
+typedef struct {
+    uint16_t range_min;     /*!< The minimum value of Light CTL Temperature Range state */
+    uint16_t range_max;     /*!< The maximum value of Light CTL Temperature Range state */
+} esp_ble_mesh_state_change_light_ctl_temperature_range_set_t;
+
+/** Parameters of Light CTL Default state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light Lightness Default state */
+    uint16_t temperature;   /*!< The value of Light CTL Temperature Default state */
+    int16_t  delta_uv;      /*!< The value of Light CTL Delta UV Default state */
+} esp_ble_mesh_state_change_light_ctl_default_set_t;
+
+/** Parameters of Light HSL state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light HSL Lightness state */
+    uint16_t hue;           /*!< The value of Light HSL Hue state */
+    uint16_t saturation;    /*!< The value of Light HSL Saturation state */
+} esp_ble_mesh_state_change_light_hsl_set_t;
+
+/** Parameter of Light HSL Hue state change event */
+typedef struct {
+    uint16_t hue;           /*!< The value of Light HSL Hue state */
+} esp_ble_mesh_state_change_light_hsl_hue_set_t;
+
+/** Parameter of Light HSL Saturation state change event */
+typedef struct {
+    uint16_t saturation;    /*!< The value of Light HSL Saturation state */
+} esp_ble_mesh_state_change_light_hsl_saturation_set_t;
+
+/** Parameters of Light HSL Default state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light HSL Lightness Default state */
+    uint16_t hue;           /*!< The value of Light HSL Hue Default state */
+    uint16_t saturation;    /*!< The value of Light HSL Saturation Default state */
+} esp_ble_mesh_state_change_light_hsl_default_set_t;
+
+/** Parameters of Light HSL Range state change event */
+typedef struct {
+    uint16_t hue_range_min;         /*!< The minimum hue value of Light HSL Range state */
+    uint16_t hue_range_max;         /*!< The maximum hue value of Light HSL Range state */
+    uint16_t saturation_range_min;  /*!< The minimum saturation value of Light HSL Range state */
+    uint16_t saturation_range_max;  /*!< The maximum saturation value of Light HSL Range state */
+} esp_ble_mesh_state_change_light_hsl_range_set_t;
+
+/** Parameters of Light xyL state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light xyL Lightness state */
+    uint16_t x;             /*!< The value of Light xyL x state */
+    uint16_t y;             /*!< The value of Light xyL y state */
+} esp_ble_mesh_state_change_light_xyl_set_t;
+
+/** Parameters of Light xyL Default state change event */
+typedef struct {
+    uint16_t lightness;     /*!< The value of Light Lightness Default state */
+    uint16_t x;             /*!< The value of Light xyL x Default state */
+    uint16_t y;             /*!< The value of Light xyL y Default state */
+} esp_ble_mesh_state_change_light_xyl_default_set_t;
+
+/** Parameters of Light xyL Range state change event */
+typedef struct {
+    uint16_t x_range_min;   /*!< The minimum value of Light xyL x Range state */
+    uint16_t x_range_max;   /*!< The maximum value of Light xyL x Range state */
+    uint16_t y_range_min;   /*!< The minimum value of Light xyL y Range state */
+    uint16_t y_range_max;   /*!< The maximum value of Light xyL y Range state */
+} esp_ble_mesh_state_change_light_xyl_range_set_t;
+
+/** Parameter of Light LC Mode state change event */
+typedef struct {
+    uint8_t mode;       /*!< The value of Light LC Mode state */
+} esp_ble_mesh_state_change_light_lc_mode_set_t;
+
+/** Parameter of Light LC Occupancy Mode state change event */
+typedef struct {
+    uint8_t mode;       /*!< The value of Light LC Occupany Mode state */
+} esp_ble_mesh_state_change_light_lc_om_set_t;
+
+/** Parameter of Light LC Light OnOff state change event */
+typedef struct {
+    uint8_t onoff;      /*!< The value of Light LC Light OnOff state */
+} esp_ble_mesh_state_change_light_lc_light_onoff_set_t;
+
+/** Parameters of Light LC Property state change event */
+typedef struct {
+    uint16_t property_id;   /*!< The property id of Light LC Property state */
+    struct net_buf_simple *property_value;  /*!< The property value of Light LC Property state */
+} esp_ble_mesh_state_change_light_lc_property_set_t;
+
+/** Parameters of Sensor Status state change event */
+typedef struct {
+    uint16_t property_id;       /*!< The value of Sensor Property ID */
+    /** Parameters of Sensor Status related state */
+    union {
+        uint8_t  occupancy;                 /*!< The value of Light LC Occupancy state */
+        uint32_t set_occupancy_to_1_delay;  /*!< The value of Light LC Set Occupancy to 1 Delay state */
+        uint32_t ambient_luxlevel;          /*!< The value of Light LC Ambient Luxlevel state */
+    } state;
+} esp_ble_mesh_state_change_sensor_status_t;
+
+/**
+ * @brief Lighting Server Model state change value union
+ */
+typedef union {
+    /**
+     * The recv_op in ctx can be used to decide which state is changed.
+     */
+    esp_ble_mesh_state_change_light_lightness_set_t             lightness_set;          /*!< Light Lightness Set */
+    esp_ble_mesh_state_change_light_lightness_linear_set_t      lightness_linear_set;   /*!< Light Lightness Linear Set */
+    esp_ble_mesh_state_change_light_lightness_default_set_t     lightness_default_set;  /*!< Light Lightness Default Set */
+    esp_ble_mesh_state_change_light_lightness_range_set_t       lightness_range_set;    /*!< Light Lightness Range Set */
+    esp_ble_mesh_state_change_light_ctl_set_t                   ctl_set;                /*!< Light CTL Set */
+    esp_ble_mesh_state_change_light_ctl_temperature_set_t       ctl_temp_set;           /*!< Light CTL Temperature Set */
+    esp_ble_mesh_state_change_light_ctl_temperature_range_set_t ctl_temp_range_set;     /*!< Light CTL Temperature Range Set */
+    esp_ble_mesh_state_change_light_ctl_default_set_t           ctl_default_set;        /*!< Light CTL Default Set */
+    esp_ble_mesh_state_change_light_hsl_set_t                   hsl_set;                /*!< Light HSL Set */
+    esp_ble_mesh_state_change_light_hsl_hue_set_t               hsl_hue_set;            /*!< Light HSL Hue Set */
+    esp_ble_mesh_state_change_light_hsl_saturation_set_t        hsl_saturation_set;     /*!< Light HSL Saturation Set */
+    esp_ble_mesh_state_change_light_hsl_default_set_t           hsl_default_set;        /*!< Light HSL Default Set */
+    esp_ble_mesh_state_change_light_hsl_range_set_t             hsl_range_set;          /*!< Light HSL Range Set */
+    esp_ble_mesh_state_change_light_xyl_set_t                   xyl_set;                /*!< Light xyL Set */
+    esp_ble_mesh_state_change_light_xyl_default_set_t           xyl_default_set;        /*!< Light xyL Default Set */
+    esp_ble_mesh_state_change_light_xyl_range_set_t             xyl_range_set;          /*!< Light xyL Range Set */
+    esp_ble_mesh_state_change_light_lc_mode_set_t               lc_mode_set;            /*!< Light LC Mode Set */
+    esp_ble_mesh_state_change_light_lc_om_set_t                 lc_om_set;              /*!< Light LC Occupancy Mode Set */
+    esp_ble_mesh_state_change_light_lc_light_onoff_set_t        lc_light_onoff_set;     /*!< Light LC Light OnOff Set */
+    esp_ble_mesh_state_change_light_lc_property_set_t           lc_property_set;        /*!< Light LC Property Set */
+    esp_ble_mesh_state_change_sensor_status_t                   sensor_status;          /*!< Sensor Status */
+} esp_ble_mesh_lighting_server_state_change_t;
+
+/** Context of the received Light LC Property Get message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID identifying a Light LC Property */
+} esp_ble_mesh_server_recv_light_lc_property_get_t;
+
+/**
+ * @brief Lighting Server Model received get message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_light_lc_property_get_t lc_property;   /*!< Light LC Property Get */
+} esp_ble_mesh_lighting_server_recv_get_msg_t;
+
+/** Context of the received Light Lightness Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t lightness;     /*!< Target value of light lightness actual state */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_lightness_set_t;
+
+/** Context of the received Light Lightness Linear Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t lightness;     /*!< Target value of light lightness linear state */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_lightness_linear_set_t;
+
+/** Context of the received Light Lightness Default Set message */
+typedef struct {
+    uint16_t lightness;     /*!< The value of the Light Lightness Default state */
+} esp_ble_mesh_server_recv_light_lightness_default_set_t;
+
+/** Context of the received Light Lightness Range Set message */
+typedef struct {
+    uint16_t range_min;     /*!< Value of range min field of light lightness range state */
+    uint16_t range_max;     /*!< Value of range max field of light lightness range state */
+} esp_ble_mesh_server_recv_light_lightness_range_set_t;
+
+/** Context of the received Light CTL Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t lightness;     /*!< Target value of light ctl lightness state */
+    uint16_t temperature;   /*!< Target value of light ctl temperature state */
+    int16_t  delta_uv;      /*!< Target value of light ctl delta UV state */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_ctl_set_t;
+
+/** Context of the received Light CTL Temperature Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t temperature;   /*!< Target value of light ctl temperature state */
+    int16_t  delta_uv;      /*!< Target value of light ctl delta UV state */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_ctl_temperature_set_t;
+
+/** Context of the received Light CTL Temperature Range Set message */
+typedef struct {
+    uint16_t range_min;     /*!< Value of temperature range min field of light ctl temperature range state */
+    uint16_t range_max;     /*!< Value of temperature range max field of light ctl temperature range state */
+} esp_ble_mesh_server_recv_light_ctl_temperature_range_set_t;
+
+/** Context of the received Light CTL Default Set message */
+typedef struct {
+    uint16_t lightness;     /*!< Value of light lightness default state */
+    uint16_t temperature;   /*!< Value of light temperature default state */
+    int16_t  delta_uv;      /*!< Value of light delta UV default state */
+} esp_ble_mesh_server_recv_light_ctl_default_set_t;
+
+/** Context of the received Light HSL Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t lightness;     /*!< Target value of light hsl lightness state */
+    uint16_t hue;           /*!< Target value of light hsl hue state */
+    uint16_t saturation;    /*!< Target value of light hsl saturation state */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_hsl_set_t;
+
+/** Context of the received Light HSL Hue Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t hue;           /*!< Target value of light hsl hue state */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_hsl_hue_set_t;
+
+/** Context of the received Light HSL Saturation Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t saturation;    /*!< Target value of light hsl hue state */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_hsl_saturation_set_t;
+
+/** Context of the received Light HSL Default Set message */
+typedef struct {
+    uint16_t lightness;     /*!< Value of light lightness default state */
+    uint16_t hue;           /*!< Value of light hue default state */
+    uint16_t saturation;    /*!< Value of light saturation default state */
+} esp_ble_mesh_server_recv_light_hsl_default_set_t;
+
+/** Context of the received Light HSL Range Set message */
+typedef struct {
+    uint16_t hue_range_min;         /*!< Value of hue range min field of light hsl hue range state */
+    uint16_t hue_range_max;         /*!< Value of hue range max field of light hsl hue range state */
+    uint16_t saturation_range_min;  /*!< Value of saturation range min field of light hsl saturation range state */
+    uint16_t saturation_range_max;  /*!< Value of saturation range max field of light hsl saturation range state */
+} esp_ble_mesh_server_recv_light_hsl_range_set_t;
+
+/** Context of the received Light xyL Set message */
+typedef struct {
+    bool     op_en;         /*!< Indicate whether optional parameters included */
+    uint16_t lightness;     /*!< The target value of the Light xyL Lightness state */
+    uint16_t x;             /*!< The target value of the Light xyL x state */
+    uint16_t y;             /*!< The target value of the Light xyL y state */
+    uint8_t  tid;           /*!< Transaction Identifier */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_xyl_set_t;
+
+/** Context of the received Light xyL Default Set message */
+typedef struct {
+    uint16_t lightness;     /*!< The value of the Light Lightness Default state */
+    uint16_t x;             /*!< The value of the Light xyL x Default state */
+    uint16_t y;             /*!< The value of the Light xyL y Default state */
+} esp_ble_mesh_server_recv_light_xyl_default_set_t;
+
+/** Context of the received Light xyl Range Set message */
+typedef struct {
+    uint16_t x_range_min;   /*!< The value of the xyL x Range Min field of the Light xyL x Range state */
+    uint16_t x_range_max;   /*!< The value of the xyL x Range Max field of the Light xyL x Range state */
+    uint16_t y_range_min;   /*!< The value of the xyL y Range Min field of the Light xyL y Range state */
+    uint16_t y_range_max;   /*!< The value of the xyL y Range Max field of the Light xyL y Range state */
+} esp_ble_mesh_server_recv_light_xyl_range_set_t;
+
+/** Context of the received Light LC Mode Set message */
+typedef struct {
+    uint8_t mode;   /*!< The target value of the Light LC Mode state */
+} esp_ble_mesh_server_recv_light_lc_mode_set_t;
+
+/** Context of the received Light OM Set message */
+typedef struct {
+    uint8_t mode;   /*!< The target value of the Light LC Occupancy Mode state */
+} esp_ble_mesh_server_recv_light_lc_om_set_t;
+
+/** Context of the received Light LC Light OnOff Set message */
+typedef struct {
+    bool    op_en;          /*!< Indicate whether optional parameters included */
+    uint8_t light_onoff;    /*!< The target value of the Light LC Light OnOff state */
+    uint8_t tid;            /*!< Transaction Identifier */
+    uint8_t trans_time;     /*!< Time to complete state transition (optional) */
+    uint8_t delay;          /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_light_lc_light_onoff_set_t;
+
+/** Context of the received Light LC Property Set message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID identifying a Light LC Property */
+    struct net_buf_simple *property_value;  /*!< Raw value for the Light LC Property */
+} esp_ble_mesh_server_recv_light_lc_property_set_t;
+
+/**
+ * @brief Lighting Server Model received set message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_light_lightness_set_t             lightness;           /*!< Light Lightness Set/Light Lightness Set Unack */
+    esp_ble_mesh_server_recv_light_lightness_linear_set_t      lightness_linear;    /*!< Light Lightness Linear Set/Light Lightness Linear Set Unack */
+    esp_ble_mesh_server_recv_light_lightness_default_set_t     lightness_default;   /*!< Light Lightness Default Set/Light Lightness Default Set Unack */
+    esp_ble_mesh_server_recv_light_lightness_range_set_t       lightness_range;     /*!< Light Lightness Range Set/Light Lightness Range Set Unack */
+    esp_ble_mesh_server_recv_light_ctl_set_t                   ctl;                 /*!< Light CTL Set/Light CTL Set Unack */
+    esp_ble_mesh_server_recv_light_ctl_temperature_set_t       ctl_temp;            /*!< Light CTL Temperature Set/Light CTL Temperature Set Unack */
+    esp_ble_mesh_server_recv_light_ctl_temperature_range_set_t ctl_temp_range;      /*!< Light CTL Temperature Range Set/Light CTL Temperature Range Set Unack */
+    esp_ble_mesh_server_recv_light_ctl_default_set_t           ctl_default;         /*!< Light CTL Default Set/Light CTL Default Set Unack */
+    esp_ble_mesh_server_recv_light_hsl_set_t                   hsl;                 /*!< Light HSL Set/Light HSL Set Unack */
+    esp_ble_mesh_server_recv_light_hsl_hue_set_t               hsl_hue;             /*!< Light HSL Hue Set/Light HSL Hue Set Unack */
+    esp_ble_mesh_server_recv_light_hsl_saturation_set_t        hsl_saturation;      /*!< Light HSL Saturation Set/Light HSL Saturation Set Unack */
+    esp_ble_mesh_server_recv_light_hsl_default_set_t           hsl_default;         /*!< Light HSL Default Set/Light HSL Default Set Unack */
+    esp_ble_mesh_server_recv_light_hsl_range_set_t             hsl_range;           /*!< Light HSL Range Set/Light HSL Range Set Unack */
+    esp_ble_mesh_server_recv_light_xyl_set_t                   xyl;                 /*!< Light xyL Set/Light xyL Set Unack */
+    esp_ble_mesh_server_recv_light_xyl_default_set_t           xyl_default;         /*!< Light xyL Default Set/Light xyL Default Set Unack */
+    esp_ble_mesh_server_recv_light_xyl_range_set_t             xyl_range;           /*!< Light xyL Range Set/Light xyL Range Set Unack */
+    esp_ble_mesh_server_recv_light_lc_mode_set_t               lc_mode;             /*!< Light LC Mode Set/Light LC Mode Set Unack */
+    esp_ble_mesh_server_recv_light_lc_om_set_t                 lc_om;               /*!< Light LC OM Set/Light LC OM Set Unack */
+    esp_ble_mesh_server_recv_light_lc_light_onoff_set_t        lc_light_onoff;      /*!< Light LC Light OnOff Set/Light LC Light OnOff Set Unack */
+    esp_ble_mesh_server_recv_light_lc_property_set_t           lc_property;         /*!< Light LC Property Set/Light LC Property Set Unack */
+} esp_ble_mesh_lighting_server_recv_set_msg_t;
+
+/** Context of the received Sensor Status message */
+typedef struct {
+    struct net_buf_simple *data;    /*!< Value of sensor data state (optional) */
+} esp_ble_mesh_server_recv_sensor_status_t;
+
+/**
+ * @brief Lighting Server Model received status message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_sensor_status_t sensor_status;     /*!< Sensor Status */
+} esp_ble_mesh_lighting_server_recv_status_msg_t;
+
+/**
+ * @brief Lighting Server Model callback value union
+ */
+typedef union {
+    esp_ble_mesh_lighting_server_state_change_t state_change;   /*!< ESP_BLE_MESH_LIGHTING_SERVER_STATE_CHANGE_EVT */
+    esp_ble_mesh_lighting_server_recv_get_msg_t get;            /*!< ESP_BLE_MESH_LIGHTING_SERVER_RECV_GET_MSG_EVT */
+    esp_ble_mesh_lighting_server_recv_set_msg_t set;            /*!< ESP_BLE_MESH_LIGHTING_SERVER_RECV_SET_MSG_EVT */
+    esp_ble_mesh_lighting_server_recv_status_msg_t status;      /*!< ESP_BLE_MESH_LIGHTING_SERVER_RECV_STATUS_MSG_EVT */
+} esp_ble_mesh_lighting_server_cb_value_t;
+
+/** Lighting Server Model callback parameters */
+typedef struct {
+    esp_ble_mesh_model_t  *model;   /*!< Pointer to Lighting Server Models */
+    esp_ble_mesh_msg_ctx_t ctx;     /*!< Context of the received messages */
+    esp_ble_mesh_lighting_server_cb_value_t value;  /*!< Value of the received Lighting Messages */
+} esp_ble_mesh_lighting_server_cb_param_t;
+
+/** This enum value is the event of Lighting Server Model */
+typedef enum {
+    /**
+     * 1. When get_auto_rsp is set to ESP_BLE_MESH_SERVER_AUTO_RSP, no event will be
+     *    callback to the application layer when Lighting Get messages are received.
+     * 2. When set_auto_rsp is set to ESP_BLE_MESH_SERVER_AUTO_RSP, this event will
+     *    be callback to the application layer when Lighting Set/Set Unack messages
+     *    are received.
+     */
+    ESP_BLE_MESH_LIGHTING_SERVER_STATE_CHANGE_EVT,
+    /**
+     * When get_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will be
+     * callback to the application layer when Lighting Get messages are received.
+     */
+    ESP_BLE_MESH_LIGHTING_SERVER_RECV_GET_MSG_EVT,
+    /**
+     * When set_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will be
+     * callback to the application layer when Lighting Set/Set Unack messages are received.
+     */
+    ESP_BLE_MESH_LIGHTING_SERVER_RECV_SET_MSG_EVT,
+    /**
+     * When status_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will
+     * be callback to the application layer when Sensor Status message is received.
+     */
+    ESP_BLE_MESH_LIGHTING_SERVER_RECV_STATUS_MSG_EVT,
+    ESP_BLE_MESH_LIGHTING_SERVER_EVT_MAX,
+} esp_ble_mesh_lighting_server_cb_event_t;
+
+/**
+ *  @brief Bluetooth Mesh Lighting Server Model function.
+ */
+
+/**
+ * @brief   Lighting Server Model callback function type
+ * @param   event: Event type
+ * @param   param: Pointer to callback parameter
+ */
+typedef void (* esp_ble_mesh_lighting_server_cb_t)(esp_ble_mesh_lighting_server_cb_event_t event,
+            esp_ble_mesh_lighting_server_cb_param_t *param);
+
+/**
+ * @brief       Register BLE Mesh Lighting Server Model callback.
+ *
+ * @param[in]   callback: Pointer to the callback function.
+ *
+ * @return      ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_register_lighting_server_callback(esp_ble_mesh_lighting_server_cb_t callback);
 
 #endif /* _ESP_BLE_MESH_LIGHTING_MODEL_API_H_ */
 

+ 366 - 0
components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h

@@ -255,6 +255,372 @@ esp_err_t esp_ble_mesh_sensor_client_get_state(esp_ble_mesh_client_common_param_
 esp_err_t esp_ble_mesh_sensor_client_set_state(esp_ble_mesh_client_common_param_t *params,
         esp_ble_mesh_sensor_client_set_state_t *set_state);
 
+/**
+ * @brief Sensor Server Models related context.
+ */
+
+/** @def    ESP_BLE_MESH_MODEL_SENSOR_SRV
+ *
+ *  @brief  Define a new Sensor Server Model.
+ *
+ *  @note   1. The Sensor Server model is a root model. When this model is present
+ *             on an element, the corresponding Sensor Setup Server model shall
+ *             also be present.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_sensor_srv_t.
+ *
+ *  @return New Sensor Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_SENSOR_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SENSOR_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_SENSOR_SETUP_SRV
+ *
+ *  @brief  Define a new Sensor Setup Server Model.
+ *
+ *  @note   1. The Sensor Setup Server model extends the Sensor Server model.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_sensor_setup_srv_t.
+ *
+ *  @return New Sensor Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_SENSOR_SETUP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+#define ESP_BLE_MESH_INVALID_SENSOR_PROPERTY_ID 0x0000  /*!< Invalid Sensor Property ID */
+
+#define ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN     0x02    /*!< Length of Sensor Property ID */
+
+#define ESP_BLE_MESH_SENSOR_DESCRIPTOR_LEN      0x08    /*!< Length of Sensor Descriptor state */
+
+#define ESP_BLE_MESH_SENSOR_UNSPECIFIED_POS_TOLERANCE   0x000   /*!< Unspecified Sensor Positive Tolerance */
+#define ESP_BLE_MESH_SENSOR_UNSPECIFIED_NEG_TOLERANCE   0x000   /*!< Unspecified Sensor Negative Tolerance */
+
+#define ESP_BLE_MESH_SENSOR_NOT_APPL_MEASURE_PERIOD     0x00    /*!< Not applicable Sensor Measurement Period */
+
+#define ESP_BLE_MESH_SENSOR_NOT_APPL_UPDATE_INTERVAL    0x00    /*!< Not applicable Sensor Update Interval */
+
+#define ESP_BLE_MESH_INVALID_SENSOR_SETTING_PROPERTY_ID 0x0000  /*!< Invalid Sensor Setting Property ID */
+
+#define ESP_BLE_MESH_SENSOR_SETTING_PROPERTY_ID_LEN     0x02    /*!< Length of Sensor Setting Property ID */
+#define ESP_BLE_MESH_SENSOR_SETTING_ACCESS_LEN          0x01    /*!< Length of Sensor Setting Access */
+
+#define ESP_BLE_MESH_SENSOR_SETTING_ACCESS_READ         0x01    /*!< Sensor Setting Access - Read */
+#define ESP_BLE_MESH_SENSOR_SETTING_ACCESS_READ_WRITE   0x03    /*!< Sensor Setting Access - Read & Write */
+
+#define ESP_BLE_MESH_SENSOR_DIVISOR_TRIGGER_TYPE_LEN    0x01    /*!< Length of Sensor Divisor Trigger Type */
+#define ESP_BLE_MESH_SENSOR_STATUS_MIN_INTERVAL_LEN     0x01    /*!< Length of Sensor Status Min Interval */
+
+#define ESP_BLE_MESH_SENSOR_PERIOD_DIVISOR_MAX_VALUE    15  /*!< Maximum value of Sensor Period Divisor */
+
+#define ESP_BLE_MESH_SENSOR_STATUS_MIN_INTERVAL_MAX     26  /*!< Maximum value of Sensor Status Min Interval */
+
+/**
+ * Sensor Status Trigger Type - Format Type of the characteristic
+ * that the Sensor Property ID state references
+ */
+#define ESP_BLE_MESH_SENSOR_STATUS_TRIGGER_TYPE_CHAR    0
+/** Sensor Status Trigger Type - Format Type "uint16" */
+#define ESP_BLE_MESH_SENSOR_STATUS_TRIGGER_TYPE_UINT16  1
+
+#define ESP_BLE_MESH_SENSOR_DATA_FORMAT_A   0x00    /*!< Sensor Data Format A */
+#define ESP_BLE_MESH_SENSOR_DATA_FORMAT_B   0x01    /*!< Sensor Data Format B */
+
+#define ESP_BLE_MESH_SENSOR_DATA_FORMAT_A_MPID_LEN  0x02    /*!< MPID length of Sensor Data Format A */
+#define ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID_LEN  0x03    /*!< MPID length of Sensor Data Format B */
+
+/**
+ * Zero length of Sensor Data.
+ *
+ * Note:
+ * The Length field is a 1-based uint7 value (valid range 0x0–0x7F,
+ * representing range of 1–127). The value 0x7F represents a length
+ * of zero.
+ */
+#define ESP_BLE_MESH_SENSOR_DATA_ZERO_LEN   0x7F
+
+/** This enum value is value of Sensor Sampling Function */
+enum esp_ble_mesh_sensor_sample_func {
+    ESP_BLE_MESH_SAMPLE_FUNC_UNSPECIFIED,
+    ESP_BLE_MESH_SAMPLE_FUNC_INSTANTANEOUS,
+    ESP_BLE_MESH_SAMPLE_FUNC_ARITHMETIC_MEAN,
+    ESP_BLE_MESH_SAMPLE_FUNC_RMS,
+    ESP_BLE_MESH_SAMPLE_FUNC_MAXIMUM,
+    ESP_BLE_MESH_SAMPLE_FUNC_MINIMUM,
+    ESP_BLE_MESH_SAMPLE_FUNC_ACCUMULATED,
+    ESP_BLE_MESH_SAMPLE_FUNC_COUNT,
+};
+
+/** Parameters of Sensor Descriptor state */
+typedef struct {
+    uint32_t positive_tolerance : 12,   /*!< The value of Sensor Positive Tolerance field */
+             negative_tolerance : 12,   /*!< The value of Sensor Negative Tolerance field */
+             sampling_function : 8;     /*!< The value of Sensor Sampling Function field */
+    uint8_t  measure_period;            /*!< The value of Sensor Measurement Period field */
+    uint8_t  update_interval;           /*!< The value of Sensor Update Interval field */
+} esp_ble_mesh_sensor_descriptor_t;
+
+/** Parameters of Sensor Setting state */
+typedef struct {
+    uint16_t property_id;       /*!< The value of Sensor Setting Property ID field */
+    uint8_t  access;            /*!< The value of Sensor Setting Access field */
+    struct net_buf_simple *raw; /*!< The value of Sensor Setting Raw field */
+} esp_ble_mesh_sensor_setting_t;
+
+/** Parameters of Sensor Cadence state */
+typedef struct {
+    uint8_t period_divisor : 7, /*!< The value of Fast Cadence Period Divisor field */
+            trigger_type : 1;   /*!< The value of Status Trigger Type field */
+    /**
+     * Note:
+     * The parameter "size" in trigger_delta_down, trigger_delta_up, fast_cadence_low &
+     * fast_cadence_high indicates the exact length of these four parameters, and they
+     * are associated with the Sensor Property ID. Users need to initialize the "size"
+     * precisely.
+     */
+    struct net_buf_simple *trigger_delta_down;  /*!< The value of Status Trigger Delta Down field */
+    struct net_buf_simple *trigger_delta_up;    /*!< The value of Status Trigger Delta Up field */
+    uint8_t min_interval;                       /*!< The value of Status Min Interval field */
+    struct net_buf_simple *fast_cadence_low;    /*!< The value of Fast Cadence Low field */
+    struct net_buf_simple *fast_cadence_high;   /*!< The value of Fast Cadence High field */
+} esp_ble_mesh_sensor_cadence_t;
+
+/** Parameters of Sensor Data state */
+typedef struct {
+    /**
+     * Format A: The Length field is a 1-based uint4 value (valid range 0x0–0xF,
+     *           representing range of 1 – 16).
+     * Format B: The Length field is a 1-based uint7 value (valid range 0x0–0x7F,
+     *           representing range of 1 – 127). The value 0x7F represents a
+     *           length of zero.
+     */
+    uint8_t format : 1, /*!< The value of the Sensor Data format */
+            length : 7; /*!< The value of the Sensor Data length */
+    struct net_buf_simple *raw_value;   /*!< The value of Sensor Data raw value */
+} esp_ble_mesh_sensor_data_t;
+
+/** Parameters of Sensor Series Column state */
+typedef struct {
+    struct net_buf_simple *raw_value_x;     /*!< The value of Sensor Raw Value X field */
+    struct net_buf_simple *column_width;    /*!< The value of Sensor Column Width field */
+    struct net_buf_simple *raw_value_y;     /*!< The value of Sensor Raw Value Y field */
+} esp_ble_mesh_sensor_series_column_t;
+
+/** Parameters of Sensor states */
+typedef struct {
+    uint16_t sensor_property_id;    /*!< The value of Sensor Property ID field */
+
+    /* Constant throughout the lifetime of an element */
+    esp_ble_mesh_sensor_descriptor_t descriptor;    /*!< Parameters of the Sensor Descriptor state */
+
+    /**
+     * Multiple Sensor Setting states may be present for each sensor.
+     * The Sensor Setting Property ID values shall be unique for each
+     * Sensor Property ID that identifies a sensor within an element.
+     */
+    const uint8_t setting_count;                /*!<  */
+    esp_ble_mesh_sensor_setting_t *settings;    /*!< Parameters of the Sensor Setting state */
+
+    /**
+     * The Sensor Cadence state may be not supported by sensors based
+     * on device properties referencing "non-scalar characteristics"
+     * such as "histograms" or "composite characteristics".
+     */
+    esp_ble_mesh_sensor_cadence_t *cadence;     /*!< Parameters of the Sensor Cadence state */
+
+    esp_ble_mesh_sensor_data_t sensor_data;     /*!< Parameters of the Sensor Data state */
+
+    esp_ble_mesh_sensor_series_column_t series_column;  /*!< Parameters of the Sensor Series Column state */
+} esp_ble_mesh_sensor_state_t;
+
+/** User data of Sensor Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Sensor Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    const uint8_t state_count;                  /*!< Sensor state count */
+    esp_ble_mesh_sensor_state_t *states;        /*!< Parameters of the Sensor states */
+} esp_ble_mesh_sensor_srv_t;
+
+/** User data of Sensor Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Sensor Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    const uint8_t state_count;                  /*!< Sensor state count */
+    esp_ble_mesh_sensor_state_t *states;        /*!< Parameters of the Sensor states */
+} esp_ble_mesh_sensor_setup_srv_t;
+
+/** Parameters of Sensor Cadence Set state change event */
+typedef struct {
+    uint16_t property_id;           /*!< The value of Sensor Property ID state */
+    uint8_t  period_divisor : 7,    /*!< The value of Fast Cadence Period Divisor state */
+             trigger_type : 1;      /*!< The value of Status Trigger Type state */
+    struct net_buf_simple *trigger_delta_down;  /*!< The value of Status Trigger Delta Down state */
+    struct net_buf_simple *trigger_delta_up;    /*!< The value of Status Trigger Delta Up state */
+    uint8_t min_interval;                       /*!< The value of Status Min Interval state */
+    struct net_buf_simple *fast_cadence_low;    /*!< The value of Fast Cadence Low state */
+    struct net_buf_simple *fast_cadence_high;   /*!< The value of Fast Cadence High state */
+} esp_ble_mesh_state_change_sensor_cadence_set_t;
+
+/** Parameters of Sensor Setting Set state change event */
+typedef struct {
+    uint16_t property_id;           /*!< The value of Sensor Property ID state */
+    uint16_t setting_property_id;   /*!< The value of Sensor Setting Property ID state */
+    struct net_buf_simple *setting_value;   /*!< The value of Sensor Property Value state */
+} esp_ble_mesh_state_change_sensor_setting_set_t;
+
+/**
+ * @brief Sensor Server Model state change value union
+ */
+typedef union {
+    /**
+     * The recv_op in ctx can be used to decide which state is changed.
+     */
+    esp_ble_mesh_state_change_sensor_cadence_set_t sensor_cadence_set;  /*!< Sensor Cadence Set */
+    esp_ble_mesh_state_change_sensor_setting_set_t sensor_setting_set;  /*!< Sensor Setting Set */
+} esp_ble_mesh_sensor_server_state_change_t;
+
+/** Context of the received Sensor Descriptor Get message */
+typedef struct {
+    bool  op_en;    /*!< Indicate if optional parameters are included */
+    uint16_t property_id;   /*!< Property ID of a sensor (optional) */
+} esp_ble_mesh_server_recv_sensor_descriptor_get_t;
+
+/** Context of the received Sensor Cadence Get message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID of a sensor */
+} esp_ble_mesh_server_recv_sensor_cadence_get_t;
+
+/** Context of the received Sensor Settings Get message */
+typedef struct {
+    uint16_t property_id;   /*!< Property ID of a sensor */
+} esp_ble_mesh_server_recv_sensor_settings_get_t;
+
+/** Context of the received Sensor Setting Get message */
+typedef struct {
+    uint16_t property_id;           /*!< Property ID of a sensor */
+    uint16_t setting_property_id;   /*!< Setting ID identifying a setting within a sensor */
+} esp_ble_mesh_server_recv_sensor_setting_get_t;
+
+/** Context of the received Sensor Get message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included  */
+    uint16_t property_id;   /*!< Property ID for the sensor (optional) */
+} esp_ble_mesh_server_recv_sensor_get_t;
+
+/** Context of the received Sensor Column Get message */
+typedef struct {
+    uint16_t property_id;   /*!< Property identifying a sensor */
+    struct net_buf_simple *raw_value_x; /*!< Raw value identifying a column */
+} esp_ble_mesh_server_recv_sensor_column_get_t;
+
+/** Context of the received Sensor Series Get message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t property_id;   /*!< Property identifying a sensor */
+    struct net_buf_simple *raw_value;   /*!< Raw value containg X1 and X2 (optional) */
+} esp_ble_mesh_server_recv_sensor_series_get_t;
+
+/**
+ * @brief Sensor Server Model received get message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_sensor_descriptor_get_t sensor_descriptor; /*!< Sensor Descriptor Get */
+    esp_ble_mesh_server_recv_sensor_cadence_get_t    sensor_cadence;    /*!< Sensor Cadence Get */
+    esp_ble_mesh_server_recv_sensor_settings_get_t   sensor_settings;   /*!< Sensor Settings Get */
+    esp_ble_mesh_server_recv_sensor_setting_get_t    sensor_setting;    /*!< Sensor Setting Get */
+    esp_ble_mesh_server_recv_sensor_get_t            sensor_data;       /*!< Sensor Get */
+    esp_ble_mesh_server_recv_sensor_column_get_t     sensor_column;     /*!< Sensor Column Get */
+    esp_ble_mesh_server_recv_sensor_series_get_t     sensor_series;     /*!< Sensor Series Get */
+} esp_ble_mesh_sensor_server_recv_get_msg_t;
+
+/** Context of the received Sensor Cadence Set message */
+typedef struct {
+    uint16_t property_id;           /*!< Property ID for the sensor */
+    struct net_buf_simple *cadence; /*!< Value of Sensor Cadence state */
+} esp_ble_mesh_server_recv_sensor_cadence_set_t;
+
+/** Context of the received Sensor Setting Set message */
+typedef struct {
+    uint16_t property_id;           /*!< Property ID identifying a sensor */
+    uint16_t setting_property_id;   /*!< Setting ID identifying a setting within a sensor */
+    struct net_buf_simple *setting_raw; /*!< Raw value for the setting */
+} esp_ble_mesh_server_recv_sensor_setting_set_t;
+
+/**
+ * @brief Sensor Server Model received set message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_sensor_cadence_set_t sensor_cadence;   /*!< Sensor Cadence Set */
+    esp_ble_mesh_server_recv_sensor_setting_set_t sensor_setting;   /*!< Sensor Setting Set */
+} esp_ble_mesh_sensor_server_recv_set_msg_t;
+
+/**
+ * @brief Sensor Server Model callback value union
+ */
+typedef union {
+    esp_ble_mesh_sensor_server_state_change_t state_change; /*!< ESP_BLE_MESH_SENSOR_SERVER_STATE_CHANGE_EVT */
+    esp_ble_mesh_sensor_server_recv_get_msg_t get;  /*!< ESP_BLE_MESH_SENSOR_SERVER_RECV_GET_MSG_EVT */
+    esp_ble_mesh_sensor_server_recv_set_msg_t set;  /*!< ESP_BLE_MESH_SENSOR_SERVER_RECV_SET_MSG_EVT */
+} esp_ble_mesh_sensor_server_cb_value_t;
+
+/** Sensor Server Model callback parameters */
+typedef struct {
+    esp_ble_mesh_model_t  *model;   /*!< Pointer to Sensor Server Models */
+    esp_ble_mesh_msg_ctx_t ctx;     /*!< Context of the received messages */
+    esp_ble_mesh_sensor_server_cb_value_t value;    /*!< Value of the received Sensor Messages */
+} esp_ble_mesh_sensor_server_cb_param_t;
+
+/** This enum value is the event of Sensor Server Model */
+typedef enum {
+    /**
+     * 1. When get_auto_rsp is set to ESP_BLE_MESH_SERVER_AUTO_RSP, no event will be
+     *    callback to the application layer when Sensor Get messages are received.
+     * 2. When set_auto_rsp is set to ESP_BLE_MESH_SERVER_AUTO_RSP, this event will
+     *    be callback to the application layer when Sensor Set/Set Unack messages
+     *    are received.
+     */
+    ESP_BLE_MESH_SENSOR_SERVER_STATE_CHANGE_EVT,
+    /**
+     * When get_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will be
+     * callback to the application layer when Sensor Get messages are received.
+     */
+    ESP_BLE_MESH_SENSOR_SERVER_RECV_GET_MSG_EVT,
+    /**
+     * When set_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will be
+     * callback to the application layer when Sensor Set/Set Unack messages are received.
+     */
+    ESP_BLE_MESH_SENSOR_SERVER_RECV_SET_MSG_EVT,
+    ESP_BLE_MESH_SENSOR_SERVER_EVT_MAX,
+} esp_ble_mesh_sensor_server_cb_event_t;
+
+/**
+ *  @brief Bluetooth Mesh Sensor Server Model function.
+ */
+
+/**
+ * @brief   Sensor Server Model callback function type
+ * @param   event: Event type
+ * @param   param: Pointer to callback parameter
+ */
+typedef void (* esp_ble_mesh_sensor_server_cb_t)(esp_ble_mesh_sensor_server_cb_event_t event,
+            esp_ble_mesh_sensor_server_cb_param_t *param);
+
+/**
+ * @brief       Register BLE Mesh Sensor Server Model callback.
+ *
+ * @param[in]   callback: Pointer to the callback function.
+ *
+ * @return      ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_register_sensor_server_callback(esp_ble_mesh_sensor_server_cb_t callback);
+
 #endif /* _ESP_BLE_MESH_SENSOR_MODEL_API_H_ */
 
 

+ 594 - 0
components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h

@@ -314,5 +314,599 @@ esp_err_t esp_ble_mesh_time_scene_client_get_state(esp_ble_mesh_client_common_pa
 esp_err_t esp_ble_mesh_time_scene_client_set_state(esp_ble_mesh_client_common_param_t *params,
         esp_ble_mesh_time_scene_client_set_state_t *set_state);
 
+/**
+ * @brief Time Scene Server Models related context.
+ */
+
+/** @def    ESP_BLE_MESH_MODEL_TIME_SRV
+ *
+ *  @brief  Define a new Time Server Model.
+ *
+ *  @note   1. The Time Server model is a root model. When this model is present on an
+ *             Element, the corresponding Time Setup Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_time_srv_t.
+ *
+ *  @return New Time Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_TIME_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_TIME_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_TIME_SETUP_SRV
+ *
+ *  @brief  Define a new Time Setup Server Model.
+ *
+ *  @note   1. The Time Setup Server model extends the Time Server model. Time is
+ *             sensitive information that is propagated across a mesh network.
+ *          2. Only an authorized Time Client should be allowed to change the Time
+ *             and Time Role states. A dedicated application key Bluetooth SIG
+ *             Proprietary should be used on the Time Setup Server to restrict
+ *             access to the server to only authorized Time Clients.
+ *          3. This model does not support subscribing nor publishing.
+ *
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_time_setup_srv_t.
+ *
+ *  @return New Time Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_TIME_SETUP_SRV(srv_data)                     \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_TIME_SETUP_SRV,    \
+                    NULL, NULL, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_SCENE_SRV
+ *
+ *  @brief  Define a new Scene Server Model.
+ *
+ *  @note   1. The Scene Server model is a root model. When this model is present
+ *             on an Element, the corresponding Scene Setup Server model shall
+ *             also be present.
+ *          2. This model shall support model publication and model subscription.
+ *          3. The model may be present only on the Primary element of a node.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_scene_srv_t.
+ *
+ *  @return New Scene Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_SCENE_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SCENE_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_SCENE_SETUP_SRV
+ *
+ *  @brief  Define a new Scene Setup Server Model.
+ *
+ *  @note   1. The Scene Setup Server model extends the Scene Server model and
+ *             the Generic Default Transition Time Server model.
+ *          2. This model shall support model subscription.
+ *          3. The model may be present only on the Primary element of a node.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_scene_setup_srv_t.
+ *
+ *  @return New Scene Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_SCENE_SETUP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SCENE_SETUP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_SCHEDULER_SRV
+ *
+ *  @brief  Define a new Scheduler Server Model.
+ *
+ *  @note   1. The Scheduler Server model extends the Scene Server model. When
+ *             this model is present on an Element, the corresponding Scheduler
+ *             Setup Server model shall also be present.
+ *          2. This model shall support model publication and model subscription.
+ *          3. The model may be present only on the Primary element of a node.
+ *          4. The model requires the Time Server model shall be present on the element.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_scheduler_srv_t.
+ *
+ *  @return New Scheduler Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_SCHEDULER_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SCHEDULER_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+/** @def    ESP_BLE_MESH_MODEL_SCHEDULER_SETUP_SRV
+ *
+ *  @brief  Define a new Scheduler Setup Server Model.
+ *
+ *  @note   1. The Scheduler Setup Server model extends the Scheduler Server and
+ *             the Scene Setup Server models.
+ *          2. This model shall support model subscription.
+ *          3. The model may be present only on the Primary element of a node.
+ *
+ *  @param  srv_pub  Pointer to the unique struct esp_ble_mesh_model_pub_t.
+ *  @param  srv_data Pointer to the unique struct esp_ble_mesh_scheduler_setup_srv_t.
+ *
+ *  @return New Scheduler Setup Server Model instance.
+ */
+#define ESP_BLE_MESH_MODEL_SCHEDULER_SETUP_SRV(srv_pub, srv_data)             \
+        ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV,     \
+                    NULL, srv_pub, srv_data)
+
+#define ESP_BLE_MESH_UNKNOWN_TAI_SECONDS        0x0000000000    /*!< Unknown TAI Seconds */
+#define ESP_BLE_MESH_UNKNOWN_TAI_ZONE_CHANGE    0x0000000000    /*!< Unknown TAI of Zone Change */
+#define ESP_BLE_MESH_UNKNOWN_TAI_DELTA_CHANGE   0x0000000000    /*!< Unknown TAI of Delta Change */
+
+#define ESP_BLE_MESH_TAI_UTC_DELAT_MAX_VALUE    0x7FFF  /*!< Maximum TAI-UTC Delta value */
+
+#define ESP_BLE_MESH_TAI_SECONDS_LEN            0x05    /*!< Length of TAI Seconds */
+#define ESP_BLE_MESH_TAI_OF_ZONE_CHANGE_LEN     0x05    /*!< Length of TAI of Zone Change */
+#define ESP_BLE_MESH_TAI_OF_DELAT_CHANGE_LEN    0x05    /*!< Length of TAI of Delta Change */
+
+#define ESP_BLE_MESH_INVALID_SCENE_NUMBER       0x0000  /*!< Invalid Scene Number */
+#define ESP_BLE_MESH_SCENE_NUMBER_LEN           0x02    /*!< Length of the Scene Number */
+
+#define ESP_BLE_MESH_SCHEDULE_YEAR_ANY_YEAR     0x64    /*!< Any year of the Scheduled year */
+
+#define ESP_BLE_MESH_SCHEDULE_DAY_ANY_DAY       0x00    /*!< Any day of the Scheduled day */
+
+#define ESP_BLE_MESH_SCHEDULE_HOUR_ANY_HOUR     0x18    /*!< Any hour of the Scheduled hour */
+#define ESP_BLE_MESH_SCHEDULE_HOUR_ONCE_A_DAY   0x19    /*!< Any hour of the Scheduled Day */
+
+#define ESP_BLE_MESH_SCHEDULE_SEC_ANY_OF_HOUR   0x3C    /*!< Any minute of the Scheduled hour */
+#define ESP_BLE_MESH_SCHEDULE_SEC_EVERY_15_MIN  0x3D    /*!< Every 15 minutes of the Scheduled hour */
+#define ESP_BLE_MESH_SCHEDULE_SEC_EVERY_20_MIN  0x3E    /*!< Every 20 minutes of the Scheduled hour */
+#define ESP_BLE_MESH_SCHEDULE_SEC_ONCE_AN_HOUR  0x3F    /*!< Once of the Scheduled hour */
+
+#define ESP_BLE_MESH_SCHEDULE_SEC_ANY_OF_MIN    0x3C    /*!< Any second of the Scheduled minute */
+#define ESP_BLE_MESH_SCHEDULE_SEC_EVERY_15_SEC  0x3D    /*!< Every 15 seconds of the Scheduled minute */
+#define ESP_BLE_MESH_SCHEDULE_SEC_EVERY_20_SEC  0x3E    /*!< Every 20 seconds of the Scheduled minute */
+#define ESP_BLE_MESH_SCHEDULE_SEC_ONCE_AN_MIN   0x3F    /*!< Once of the Scheduled minute */
+
+#define ESP_BLE_MESH_SCHEDULE_ACT_TURN_OFF      0x00    /*!< Scheduled Action - Turn Off */
+#define ESP_BLE_MESH_SCHEDULE_ACT_TURN_ON       0x01    /*!< Scheduled Action - Turn On */
+#define ESP_BLE_MESH_SCHEDULE_ACT_SCENE_RECALL  0x02    /*!< Scheduled Action - Scene Recall */
+#define ESP_BLE_MESH_SCHEDULE_ACT_NO_ACTION     0x0F    /*!< Scheduled Action - No Action */
+
+#define ESP_BLE_MESH_SCHEDULE_SCENE_NO_SCENE    0x0000  /*!< Scheduled Scene - No Scene */
+
+#define ESP_BLE_MESH_SCHEDULE_ENTRY_MAX_INDEX   0x0F    /*!< Maximum number of Scheduled entries */
+
+#define ESP_BLE_MESH_TIME_NONE          0x00    /*!< Time Role - None */
+#define ESP_BLE_MESH_TIME_AUTHORITY     0x01    /*!< Time Role - Mesh Time Authority */
+#define ESP_BLE_MESH_TIME_RELAY         0x02    /*!< Time Role - Mesh Time Relay */
+#define ESP_BLE_MESH_TIME_CLINET        0x03    /*!< Time Role - Mesh Time Client */
+
+#define ESP_BLE_MESH_SCENE_SUCCESS      0x00    /*!< Scene operation - Success */
+#define ESP_BLE_MESH_SCENE_REG_FULL     0x01    /*!< Scene operation - Scene Register Full */
+#define ESP_BLE_MESH_SCENE_NOT_FOUND    0x02    /*!< Scene operation - Scene Not Found */
+
+/** Parameters of Time state */
+typedef struct {
+    struct {
+        uint8_t  tai_seconds[5];            /*!< The value of the TAI Seconds state */
+        uint8_t  subsecond;                 /*!< The value of the Subsecond field */
+        uint8_t  uncertainty;               /*!< The value of the Uncertainty field */
+        uint8_t  time_zone_offset_curr;     /*!< The value of the Time Zone Offset Current field */
+        uint8_t  time_zone_offset_new;      /*!< The value of the Time Zone Offset New state */
+        uint8_t  tai_zone_change[5];        /*!< The value of the TAI of Zone Chaneg field */
+        uint16_t time_authority : 1,        /*!< The value of the Time Authority bit */
+                 tai_utc_delta_curr : 15;   /*!< The value of the TAI-UTC Delta Current state */
+        uint16_t tai_utc_delta_new : 15;    /*!< The value of the TAI-UTC Delta New state */
+        uint8_t  tai_delta_change[5];       /*!< The value of the TAI of Delta Change field */
+    } time;                                 /*!< Parameters of the Time state */
+    uint8_t time_role;                      /*!< The value of the Time Role state */
+} esp_ble_mesh_time_state_t;
+
+/** User data of Time Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Time Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_time_state_t *state;           /*!< Parameters of the Time state */
+} esp_ble_mesh_time_srv_t;
+
+/** User data of Time Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Time Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_time_state_t *state;           /*!< Parameters of the Time state */
+} esp_ble_mesh_time_setup_srv_t;
+
+/**
+ * 1. Scene Store is an operation of storing values of a present state of an element.
+ * 2. The structure and meaning of the stored state is determined by a model. States
+ *    to be stored are specified by each model.
+ * 3. The Scene Store operation shall persistently store all values of all states
+ *    marked as Stored with Scene for all models present on all elements of a node.
+ * 4. If a model is extending another model, the extending model shall determine the
+ *    Stored with Scene behavior of that model.
+ */
+
+/** Parameters of Scene Register state */
+typedef struct {
+    uint16_t scene_number;  /*!< The value of the Scene Number */
+    uint8_t  scene_type;    /*!< The value of the Scene Type */
+    /**
+     * Scene value may use a union to represent later, the union contains
+     * structures of all the model states which can be stored in a scene.
+     */
+    struct net_buf_simple *scene_value; /*!< The value of the Scene Value */
+} esp_ble_mesh_scene_register_t;
+
+/**
+ * Parameters of Scenes state.
+ *
+ * Scenes serve as memory banks for storage of states (e.g., a power level
+ * or a light level/color). Values of states of an element can be stored
+ * as a scene and can be recalled later from the scene memory.
+ *
+ * A scene is represented by a Scene Number, which is a 16-bit non-zero,
+ * mesh-wide value. (There can be a maximum of 65535 scenes in a mesh
+ * network.) The meaning of a scene, as well as the state storage container
+ * associated with it, are determined by a model.
+ * 
+ * The Scenes state change may start numerous parallel model transitions.
+ * In that case, each individual model handles the transition internally.
+ *
+ * The scene transition is defined as a group of individual model transitions
+ * started by a Scene Recall operation. The scene transition is in progress
+ * when at least one transition from the group of individual model transitions
+ * is in progress.
+ */
+typedef struct {
+    const uint16_t scene_count;             /*!< The Scenes state's scene count */
+    esp_ble_mesh_scene_register_t *scenes;  /*!< Parameters of the Scenes state */
+
+    /**
+     * The Current Scene state is a 16-bit value that contains either the Scene
+     * Number of the currently active scene or a value of 0x0000 when no scene
+     * is active.
+     *
+     * When a Scene Store operation or a Scene Recall operation completes with
+     * success, the Current Scene state value shall be to the Scene Number used
+     * during that operation.
+     *
+     * When the Current Scene Number is deleted from a Scene Register state as a
+     * result of Scene Delete operation, the Current Scene state shall be set to
+     * 0x0000.
+     *
+     * When any of the element's state that is marked as “Stored with Scene” has
+     * changed not as a result of a Scene Recall operation, the value of the
+     * Current Scene state shall be set to 0x0000.
+     *
+     * When a scene transition is in progress, the value of the Current Scene
+     * state shall be set to 0x0000.
+     */
+    uint16_t current_scene;     /*!< The value of the Current Scene state */
+
+    /**
+     * The Target Scene state is a 16-bit value that contains the target Scene
+     * Number when a scene transition is in progress.
+     *
+     * When the scene transition is in progress and the target Scene Number is
+     * deleted from a Scene Register state as a result of Scene Delete operation,
+     * the Target Scene state shall be set to 0x0000.
+     *
+     * When the scene transition is in progress and a new Scene Number is stored
+     * in the Scene Register as a result of Scene Store operation, the Target
+     * Scene state shall be set to the new Scene Number.
+     *
+     * When the scene transition is not in progress, the value of the Target Scene
+     * state shall be set to 0x0000.
+     */
+    uint16_t target_scene;      /*!< The value of the Target Scene state */
+
+    /* Indicate the status code for the last operation */
+    uint8_t status_code;        /*!< The status code of the last scene operation */
+
+    /* Indicate if scene transition is in progress */
+    bool in_progress;           /*!< Indicate if the scene transition is in progress */
+} esp_ble_mesh_scenes_state_t;
+
+/** User data of Scene Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Scene Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_scenes_state_t *state;         /*!< Parameters of the Scenes state */
+    esp_ble_mesh_last_msg_info_t last;          /*!< Parameters of the last received set message */
+    esp_ble_mesh_state_transition_t transition; /*!< Parameters of state transition */
+} esp_ble_mesh_scene_srv_t;
+
+/** User data of Scene Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Scene Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_scenes_state_t *state;         /*!< Parameters of the Scenes state */
+} esp_ble_mesh_scene_setup_srv_t;
+
+/** Parameters of Scheduler Register state */
+typedef struct {
+    bool in_use;                /*!< Indicate if the registered schedule is in use */
+    uint64_t year : 7,          /*!< The value of Scheduled year for the action */
+             month : 12,        /*!< The value of Scheduled month for the action */
+             day : 5,           /*!< The value of Scheduled day of the month for the action */
+             hour : 5,          /*!< The value of Scheduled hour for the action */
+             minute : 6,        /*!< The value of Scheduled minute for the action */
+             second : 6,        /*!< The value of Scheduled second for the action */
+             day_of_week : 7,   /*!< The value of Schedule days of the week for the action */
+             action : 4,        /*!< The value of Action to be performed at the scheduled time */
+             trans_time : 8;    /*!< The value of Transition time for this action */
+    uint16_t scene_number;      /*!< The value of Scene Number to be used for some actions */
+} esp_ble_mesh_schedule_register_t;
+
+/** Parameters of Scheduler state */
+typedef struct {
+    const uint8_t schedule_count;                   /*!< Scheduler count */
+    esp_ble_mesh_schedule_register_t *schedules;    /*!< Up to 16 scheduled entries */
+} esp_ble_mesh_scheduler_state_t;
+
+/** User data of Scheduler Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Scheduler Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_scheduler_state_t *state;      /*!< Parameters of the Scheduler state */
+} esp_ble_mesh_scheduler_srv_t;
+
+/** User data of Scheduler Setup Server Model */
+typedef struct {
+    esp_ble_mesh_model_t *model;                /*!< Pointer to the Scheduler Setup Server Model. Initialized internally. */
+    esp_ble_mesh_server_rsp_ctrl_t rsp_ctrl;    /*!< Response control of the server model received messages */
+    esp_ble_mesh_scheduler_state_t *state;      /*!< Parameters of the Scheduler state */
+} esp_ble_mesh_scheduler_setup_srv_t;
+
+/** Parameters of Time Set state change event */
+typedef struct {
+    uint8_t  tai_seconds[5];        /*!< The current TAI time in seconds */
+    uint8_t  subsecond;             /*!< The sub-second time in units of 1/256 second */
+    uint8_t  uncertainty;           /*!< The estimated uncertainty in 10-millisecond steps */
+    uint16_t time_authority : 1;    /*!< 0 = No Time Authority, 1 = Time Authority */
+    uint16_t tai_utc_delta_curr : 15;   /*!< Current difference between TAI and UTC in seconds */
+    uint8_t  time_zone_offset_curr;     /*!< The local time zone offset in 15-minute increments */
+} esp_ble_mesh_state_change_time_set_t;
+
+/** Parameters of Time Status state change event */
+typedef struct {
+    uint8_t  tai_seconds[5];        /*!< The current TAI time in seconds */
+    uint8_t  subsecond;             /*!< The sub-second time in units of 1/256 second */
+    uint8_t  uncertainty;           /*!< The estimated uncertainty in 10-millisecond steps */
+    uint16_t time_authority : 1;    /*!< 0 = No Time Authority, 1 = Time Authority */
+    uint16_t tai_utc_delta_curr : 15;   /*!< Current difference between TAI and UTC in seconds */
+    uint8_t  time_zone_offset_curr;     /*!< The local time zone offset in 15-minute increments */
+} esp_ble_mesh_state_change_time_status_t;
+
+/** Parameters of Time Zone Set state change event */
+typedef struct {
+    uint8_t time_zone_offset_new;   /*!< Upcoming local time zone offset */
+    uint8_t tai_zone_change[5];     /*!< TAI Seconds time of the upcoming Time Zone Offset change */
+} esp_ble_mesh_state_change_time_zone_set_t;
+
+/** Parameters of TAI UTC Delta Set state change event */
+typedef struct {
+    uint16_t tai_utc_delta_new : 15;    /*!< Upcoming difference between TAI and UTC in seconds */
+    uint8_t tai_delta_change[5];        /*!< TAI Seconds time of the upcoming TAI-UTC Delta change */
+} esp_ble_mesh_state_change_tai_utc_delta_set_t;
+
+/** Parameter of Time Role Set state change event */
+typedef struct {
+    uint8_t time_role;      /*!< The Time Role for the element */
+} esp_ble_mesh_state_change_time_role_set_t;
+
+/** Parameter of Scene Store state change event */
+typedef struct {
+    uint16_t scene_number;  /*!< The number of scenes to be stored */
+} esp_ble_mesh_state_change_scene_store_t;
+
+/** Parameter of Scene Recall state change event */
+typedef struct {
+    uint16_t scene_number;  /*!< The number of scenes to be recalled */
+} esp_ble_mesh_state_change_scene_recall_t;
+
+/** Parameter of Scene Delete state change event */
+typedef struct {
+    uint16_t scene_number;  /*!< The number of scenes to be deleted */
+} esp_ble_mesh_state_change_scene_delete_t;
+
+/** Parameter of Scheduler Action Set state change event */
+typedef struct {
+    uint64_t index : 4;         /*!< Index of the Schedule Register entry to set */
+    uint64_t year : 7;          /*!< Scheduled year for the action */
+    uint64_t month : 12;        /*!< Scheduled month for the action */
+    uint64_t day : 5;           /*!< Scheduled day of the month for the action */
+    uint64_t hour : 5;          /*!< Scheduled hour for the action */
+    uint64_t minute : 6;        /*!< Scheduled minute for the action */
+    uint64_t second : 6;        /*!< Scheduled second for the action */
+    uint64_t day_of_week : 7;   /*!< Schedule days of the week for the action */
+    uint64_t action : 4;        /*!< Action to be performed at the scheduled time */
+    uint64_t trans_time : 8;    /*!< Transition time for this action */
+    uint16_t scene_number;      /*!< Scene number to be used for some actions */
+} esp_ble_mesh_state_change_scheduler_act_set_t;
+
+/**
+ * @brief Time Scene Server Model state change value union
+ */
+typedef union {
+    /**
+     * The recv_op in ctx can be used to decide which state is changed.
+     */
+    esp_ble_mesh_state_change_time_set_t          time_set;             /*!< Time Set */
+    esp_ble_mesh_state_change_time_status_t       time_status;          /*!< Time Status */
+    esp_ble_mesh_state_change_time_zone_set_t     time_zone_set;        /*!< Time Zone Set */
+    esp_ble_mesh_state_change_tai_utc_delta_set_t tai_utc_delta_set;    /*!< TAI UTC Delta Set */
+    esp_ble_mesh_state_change_time_role_set_t     time_role_set;        /*!< Time Role Set */
+    esp_ble_mesh_state_change_scene_store_t       scene_store;          /*!< Scene Store */
+    esp_ble_mesh_state_change_scene_recall_t      scene_recall;         /*!< Scene Recall */
+    esp_ble_mesh_state_change_scene_delete_t      scene_delete;         /*!< Scene Delete */
+    esp_ble_mesh_state_change_scheduler_act_set_t scheduler_act_set;    /*!< Scheduler Action Set */
+} esp_ble_mesh_time_scene_server_state_change_t;
+
+/** Context of the received Scheduler Action Get message */
+typedef struct {
+    uint8_t index;  /*!< Index of the Schedule Register entry to get */
+} esp_ble_mesh_server_recv_scheduler_act_get_t;
+
+/**
+ * @brief Time Scene Server Model received get message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_scheduler_act_get_t scheduler_act; /*!< Scheduler Action Get */
+} esp_ble_mesh_time_scene_server_recv_get_msg_t;
+
+/** Context of the received Time Set message */
+typedef struct {
+    uint8_t  tai_seconds[5];        /*!< The current TAI time in seconds */
+    uint8_t  subsecond;             /*!< The sub-second time in units of 1/256 second */
+    uint8_t  uncertainty;           /*!< The estimated uncertainty in 10-millisecond steps */
+    uint16_t time_authority : 1;    /*!< 0 = No Time Authority, 1 = Time Authority */
+    uint16_t tai_utc_delta : 15;    /*!< Current difference between TAI and UTC in seconds */
+    uint8_t  time_zone_offset;      /*!< The local time zone offset in 15-minute increments */
+} esp_ble_mesh_server_recv_time_set_t;
+
+/** Context of the received Time Zone Set message */
+typedef struct {
+    uint8_t time_zone_offset_new;   /*!< Upcoming local time zone offset */
+    uint8_t tai_zone_change[5];     /*!< TAI Seconds time of the upcoming Time Zone Offset change */
+} esp_ble_mesh_server_recv_time_zone_set_t;
+
+/** Context of the received TAI UTC Delta Set message */
+typedef struct {
+    uint16_t tai_utc_delta_new : 15;    /*!< Upcoming difference between TAI and UTC in seconds */
+    uint16_t padding : 1;               /*!< Always 0b0. Other values are Prohibited. */
+    uint8_t tai_delta_change[5];        /*!< TAI Seconds time of the upcoming TAI-UTC Delta change */
+} esp_ble_mesh_server_recv_tai_utc_delta_set_t;
+
+/** Context of the received Time Role Set message */
+typedef struct {
+    uint8_t time_role;      /*!< The Time Role for the element */
+} esp_ble_mesh_server_recv_time_role_set_t;
+
+/** Context of the received Scene Store message */
+typedef struct {
+    uint16_t scene_number;  /*!< The number of scenes to be stored */
+} esp_ble_mesh_server_recv_scene_store_t;
+
+/** Context of the received Scene Recall message */
+typedef struct {
+    bool     op_en;         /*!< Indicate if optional parameters are included */
+    uint16_t scene_number;  /*!< The number of scenes to be recalled */
+    uint8_t  tid;           /*!< Transaction ID */
+    uint8_t  trans_time;    /*!< Time to complete state transition (optional) */
+    uint8_t  delay;         /*!< Indicate message execution delay (C.1) */
+} esp_ble_mesh_server_recv_scene_recall_t;
+
+/** Context of the received Scene Delete message */
+typedef struct {
+    uint16_t scene_number;  /*!< The number of scenes to be deleted */
+} esp_ble_mesh_server_recv_scene_delete_t;
+
+/** Context of the received Scheduler Action Set message */
+typedef struct {
+    uint64_t index : 4;         /*!< Index of the Schedule Register entry to set */
+    uint64_t year : 7;          /*!< Scheduled year for the action */
+    uint64_t month : 12;        /*!< Scheduled month for the action */
+    uint64_t day : 5;           /*!< Scheduled day of the month for the action */
+    uint64_t hour : 5;          /*!< Scheduled hour for the action */
+    uint64_t minute : 6;        /*!< Scheduled minute for the action */
+    uint64_t second : 6;        /*!< Scheduled second for the action */
+    uint64_t day_of_week : 7;   /*!< Schedule days of the week for the action */
+    uint64_t action : 4;        /*!< Action to be performed at the scheduled time */
+    uint64_t trans_time : 8;    /*!< Transition time for this action */
+    uint16_t scene_number;      /*!< Scene number to be used for some actions */
+} esp_ble_mesh_server_recv_scheduler_act_set_t;
+
+/**
+ * @brief Time Scene Server Model received set message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_time_set_t          time;              /*!< Time Set */
+    esp_ble_mesh_server_recv_time_zone_set_t     time_zone;         /*!< Time Zone Set */
+    esp_ble_mesh_server_recv_tai_utc_delta_set_t tai_utc_delta;     /*!< TAI-UTC Delta Set */
+    esp_ble_mesh_server_recv_time_role_set_t     time_role;         /*!< Time Role Set */
+    esp_ble_mesh_server_recv_scene_store_t       scene_store;       /*!< Scene Store/Scene Store Unack */
+    esp_ble_mesh_server_recv_scene_recall_t      scene_recall;      /*!< Scene Recall/Scene Recall Unack */
+    esp_ble_mesh_server_recv_scene_delete_t      scene_delete;      /*!< Scene Delete/Scene Delete Unack */
+    esp_ble_mesh_server_recv_scheduler_act_set_t scheduler_act;     /*!< Scheduler Action Set/Scheduler Action Set Unack */
+} esp_ble_mesh_time_scene_server_recv_set_msg_t;
+
+/** Context of the received Time Status message */
+typedef struct {
+    uint8_t  tai_seconds[5];        /*!< The current TAI time in seconds */
+    uint8_t  subsecond;             /*!< The sub-second time in units of 1/256 second */
+    uint8_t  uncertainty;           /*!< The estimated uncertainty in 10-millisecond steps */
+    uint16_t time_authority : 1;    /*!< 0 = No Time Authority, 1 = Time Authority */
+    uint16_t tai_utc_delta : 15;    /*!< Current difference between TAI and UTC in seconds */
+    uint8_t  time_zone_offset;      /*!< The local time zone offset in 15-minute increments */
+} esp_ble_mesh_server_recv_time_status_t;
+
+/**
+ * @brief Time Scene Server Model received status message union
+ */
+typedef union {
+    esp_ble_mesh_server_recv_time_status_t time_status;     /*!< Time Status */
+} esp_ble_mesh_time_scene_server_recv_status_msg_t;
+
+/**
+ * @brief Time Scene Server Model callback value union
+ */
+typedef union {
+    esp_ble_mesh_time_scene_server_state_change_t state_change; /*!< ESP_BLE_MESH_TIME_SCENE_SERVER_STATE_CHANGE_EVT */
+    esp_ble_mesh_time_scene_server_recv_get_msg_t get;  /*!< ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_GET_MSG_EVT */
+    esp_ble_mesh_time_scene_server_recv_set_msg_t set;  /*!< ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_SET_MSG_EVT */
+    esp_ble_mesh_time_scene_server_recv_status_msg_t status;    /*!< ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_STATUS_MSG_EVT */
+} esp_ble_mesh_time_scene_server_cb_value_t;
+
+/** Time Scene Server Model callback parameters */
+typedef struct {
+    esp_ble_mesh_model_t  *model;   /*!< Pointer to Time and Scenes Server Models */
+    esp_ble_mesh_msg_ctx_t ctx;     /*!< Context of the received messages */
+    esp_ble_mesh_time_scene_server_cb_value_t value;    /*!< Value of the received Time and Scenes Messages */
+} esp_ble_mesh_time_scene_server_cb_param_t;
+
+/** This enum value is the event of Time Scene Server Model */
+typedef enum {
+    /**
+     * 1. When get_auto_rsp is set to ESP_BLE_MESH_SERVER_AUTO_RSP, no event will be
+     *    callback to the application layer when Time Scene Get messages are received.
+     * 2. When set_auto_rsp is set to ESP_BLE_MESH_SERVER_AUTO_RSP, this event will
+     *    be callback to the application layer when Time Scene Set/Set Unack messages
+     *    are received.
+     */
+    ESP_BLE_MESH_TIME_SCENE_SERVER_STATE_CHANGE_EVT,
+    /**
+     * When get_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will be
+     * callback to the application layer when Time Scene Get messages are received.
+     */
+    ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_GET_MSG_EVT,
+    /**
+     * When set_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will be
+     * callback to the application layer when Time Scene Set/Set Unack messages are received.
+     */
+    ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_SET_MSG_EVT,
+    /**
+     * When status_auto_rsp is set to ESP_BLE_MESH_SERVER_RSP_BY_APP, this event will
+     * be callback to the application layer when TIme Status message is received.
+     */
+    ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_STATUS_MSG_EVT,
+    ESP_BLE_MESH_TIME_SCENE_SERVER_EVT_MAX,
+} esp_ble_mesh_time_scene_server_cb_event_t;
+
+/**
+ *  @brief Bluetooth Mesh Time and Scenes Server Model function.
+ */
+
+/**
+ * @brief   Time Scene Server Model callback function type
+ * @param   event: Event type
+ * @param   param: Pointer to callback parameter
+ */
+typedef void (* esp_ble_mesh_time_scene_server_cb_t)(esp_ble_mesh_time_scene_server_cb_event_t event,
+            esp_ble_mesh_time_scene_server_cb_param_t *param);
+
+/**
+ * @brief       Register BLE Mesh Time and Scenes Server Model callback.
+ *
+ * @param[in]   callback: Pointer to the callback function.
+ *
+ * @return      ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_register_time_scene_server_callback(esp_ble_mesh_time_scene_server_cb_t callback);
+
 #endif /* _ESP_BLE_MESH_TIME_SCENE_MODEL_API_H_ */
 

+ 224 - 0
components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c

@@ -534,3 +534,227 @@ void btc_ble_mesh_generic_client_cb_handler(btc_msg_t *msg)
     btc_ble_mesh_generic_client_free_req_data(msg);
     return;
 }
+
+/* Generic Server Models related functions */
+
+static inline void btc_ble_mesh_generic_server_cb_to_app(
+        esp_ble_mesh_generic_server_cb_event_t event,
+        esp_ble_mesh_generic_server_cb_param_t *param)
+{
+    esp_ble_mesh_generic_server_cb_t btc_ble_mesh_cb =
+        (esp_ble_mesh_generic_server_cb_t)btc_profile_cb_get(BTC_PID_GENERIC_SERVER);
+    if (btc_ble_mesh_cb) {
+        btc_ble_mesh_cb(event, param);
+    }
+}
+
+static void btc_ble_mesh_generic_server_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src)
+{
+    esp_ble_mesh_generic_server_cb_param_t *p_dest_data = (esp_ble_mesh_generic_server_cb_param_t *)p_dest;
+    esp_ble_mesh_generic_server_cb_param_t *p_src_data = (esp_ble_mesh_generic_server_cb_param_t *)p_src;
+    u16_t length;
+
+    if (!msg || !p_src_data || !p_dest_data) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    switch (msg->act) {
+    case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT:
+        switch (p_src_data->ctx.recv_op) {
+        case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET:
+        case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK:
+            if (p_src_data->value.state_change.user_property_set.value) {
+                length = p_src_data->value.state_change.user_property_set.value->len;
+                p_dest_data->value.state_change.user_property_set.value = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.state_change.user_property_set.value == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.state_change.user_property_set.value,
+                                       p_src_data->value.state_change.user_property_set.value->data,
+                                       p_src_data->value.state_change.user_property_set.value->len);
+            }
+            break;
+        case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET:
+        case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK:
+            if (p_src_data->value.state_change.admin_property_set.value) {
+                length = p_src_data->value.state_change.admin_property_set.value->len;
+                p_dest_data->value.state_change.admin_property_set.value = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.state_change.admin_property_set.value == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.state_change.admin_property_set.value,
+                                       p_src_data->value.state_change.admin_property_set.value->data,
+                                       p_src_data->value.state_change.admin_property_set.value->len);
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT:
+        switch (p_src_data->ctx.recv_op) {
+        case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET:
+        case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK:
+            if (p_src_data->value.set.user_property.property_value) {
+                length = p_src_data->value.set.user_property.property_value->len;
+                p_dest_data->value.set.user_property.property_value = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.set.user_property.property_value == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.set.user_property.property_value,
+                                       p_src_data->value.set.user_property.property_value->data,
+                                       p_src_data->value.set.user_property.property_value->len);
+            }
+            break;
+        case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET:
+        case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK:
+            if (p_src_data->value.set.admin_property.property_value) {
+                length = p_src_data->value.set.admin_property.property_value->len;
+                p_dest_data->value.set.admin_property.property_value = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.set.admin_property.property_value == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.set.admin_property.property_value,
+                                       p_src_data->value.set.admin_property.property_value->data,
+                                       p_src_data->value.set.admin_property.property_value->len);
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void btc_ble_mesh_generic_server_free_req_data(btc_msg_t *msg)
+{
+    esp_ble_mesh_generic_server_cb_param_t *arg = NULL;
+
+    if (!msg || !msg->arg) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    arg = (esp_ble_mesh_generic_server_cb_param_t *)(msg->arg);
+
+    switch (msg->act) {
+    case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT:
+        switch (arg->ctx.recv_op) {
+        case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET:
+        case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK:
+            bt_mesh_free_buf(arg->value.state_change.user_property_set.value);
+            break;
+        case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET:
+        case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK:
+            bt_mesh_free_buf(arg->value.state_change.admin_property_set.value);
+            break;
+        default:
+            break;
+        }
+        break;
+    case ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT:
+        switch (arg->ctx.recv_op) {
+        case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET:
+        case ESP_BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK:
+            bt_mesh_free_buf(arg->value.set.user_property.property_value);
+            break;
+        case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET:
+        case ESP_BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK:
+            bt_mesh_free_buf(arg->value.set.admin_property.property_value);
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void btc_ble_mesh_generic_server_callback(esp_ble_mesh_generic_server_cb_param_t *cb_params, uint8_t act)
+{
+    btc_msg_t msg = {0};
+
+    LOG_DEBUG("%s", __func__);
+
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_GENERIC_SERVER;
+    msg.act = act;
+
+    btc_transfer_context(&msg, cb_params,
+        sizeof(esp_ble_mesh_generic_server_cb_param_t), btc_ble_mesh_generic_server_copy_req_data);
+}
+
+void bt_mesh_generic_server_cb_evt_to_btc(u8_t evt_type,
+        struct bt_mesh_model *model,
+        struct bt_mesh_msg_ctx *ctx,
+        const u8_t *val, size_t len)
+{
+    esp_ble_mesh_generic_server_cb_param_t cb_params = {0};
+    size_t length;
+    uint8_t act;
+
+    if (model == NULL || ctx == NULL) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    switch (evt_type) {
+    case BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE:
+        act = ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG:
+        act = ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG:
+        act = ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT;
+        break;
+    default:
+        LOG_ERROR("%s, Unknown Generic Server event type", __func__);
+        return;
+    }
+
+    cb_params.model = (esp_ble_mesh_model_t *)model;
+    cb_params.ctx.net_idx = ctx->net_idx;
+    cb_params.ctx.app_idx = ctx->app_idx;
+    cb_params.ctx.addr = ctx->addr;
+    cb_params.ctx.recv_ttl = ctx->recv_ttl;
+    cb_params.ctx.recv_op = ctx->recv_op;
+    cb_params.ctx.recv_dst = ctx->recv_dst;
+
+    if (val && len) {
+        length = (len <= sizeof(cb_params.value)) ? len : sizeof(cb_params.value);
+        memcpy(&cb_params.value, val, length);
+    }
+
+    btc_ble_mesh_generic_server_callback(&cb_params, act);
+    return;
+}
+
+void btc_ble_mesh_generic_server_cb_handler(btc_msg_t *msg)
+{
+    esp_ble_mesh_generic_server_cb_param_t *param = NULL;
+
+    if (!msg || !msg->arg) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    param = (esp_ble_mesh_generic_server_cb_param_t *)(msg->arg);
+
+    if (msg->act < ESP_BLE_MESH_GENERIC_SERVER_EVT_MAX) {
+        btc_ble_mesh_generic_server_cb_to_app(msg->act, param);
+    } else {
+        LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act);
+    }
+
+    btc_ble_mesh_generic_server_free_req_data(msg);
+    return;
+}

+ 194 - 0
components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c

@@ -379,3 +379,197 @@ void btc_ble_mesh_lighting_client_cb_handler(btc_msg_t *msg)
     return;
 }
 
+/* Lighting Server Models related functions */
+
+static inline void btc_ble_mesh_lighting_server_cb_to_app(
+        esp_ble_mesh_lighting_server_cb_event_t event,
+        esp_ble_mesh_lighting_server_cb_param_t *param)
+{
+    esp_ble_mesh_lighting_server_cb_t btc_ble_mesh_cb =
+        (esp_ble_mesh_lighting_server_cb_t)btc_profile_cb_get(BTC_PID_LIGHTING_SERVER);
+    if (btc_ble_mesh_cb) {
+        btc_ble_mesh_cb(event, param);
+    }
+}
+
+static void btc_ble_mesh_lighting_server_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src)
+{
+    esp_ble_mesh_lighting_server_cb_param_t *p_dest_data = (esp_ble_mesh_lighting_server_cb_param_t *)p_dest;
+    esp_ble_mesh_lighting_server_cb_param_t *p_src_data = (esp_ble_mesh_lighting_server_cb_param_t *)p_src;
+    u16_t length;
+
+    if (!msg || !p_src_data || !p_dest_data) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    switch (msg->act) {
+    case ESP_BLE_MESH_LIGHTING_SERVER_STATE_CHANGE_EVT:
+        if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET ||
+            p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK) {
+            if (p_src_data->value.state_change.lc_property_set.property_value) {
+                length = p_src_data->value.state_change.lc_property_set.property_value->len;
+                p_dest_data->value.state_change.lc_property_set.property_value = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.state_change.lc_property_set.property_value == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.state_change.lc_property_set.property_value,
+                                       p_src_data->value.state_change.lc_property_set.property_value->data,
+                                       p_src_data->value.state_change.lc_property_set.property_value->len);
+            }
+        }
+        break;
+    case ESP_BLE_MESH_LIGHTING_SERVER_RECV_SET_MSG_EVT:
+        if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET ||
+            p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK) {
+            if (p_src_data->value.set.lc_property.property_value) {
+                length = p_src_data->value.set.lc_property.property_value->len;
+                p_dest_data->value.set.lc_property.property_value = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.set.lc_property.property_value == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.set.lc_property.property_value,
+                                       p_src_data->value.set.lc_property.property_value->data,
+                                       p_src_data->value.set.lc_property.property_value->len);
+            }
+        }
+        break;
+    case ESP_BLE_MESH_LIGHTING_SERVER_RECV_STATUS_MSG_EVT:
+        if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_STATUS) {
+            if (p_src_data->value.status.sensor_status.data) {
+                length = p_src_data->value.status.sensor_status.data->len;
+                p_dest_data->value.status.sensor_status.data = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.status.sensor_status.data == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.status.sensor_status.data,
+                                       p_src_data->value.status.sensor_status.data->data,
+                                       p_src_data->value.status.sensor_status.data->len);
+            }
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void btc_ble_mesh_lighting_server_free_req_data(btc_msg_t *msg)
+{
+    esp_ble_mesh_lighting_server_cb_param_t *arg = NULL;
+
+    if (!msg || !msg->arg) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    arg = (esp_ble_mesh_lighting_server_cb_param_t *)(msg->arg);
+
+    switch (msg->act) {
+    case ESP_BLE_MESH_LIGHTING_SERVER_STATE_CHANGE_EVT:
+        if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET ||
+            arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK) {
+            bt_mesh_free_buf(arg->value.state_change.lc_property_set.property_value);
+        }
+        break;
+    case ESP_BLE_MESH_LIGHTING_SERVER_RECV_SET_MSG_EVT:
+        if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET ||
+            arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK) {
+            bt_mesh_free_buf(arg->value.set.lc_property.property_value);
+        }
+        break;
+    case ESP_BLE_MESH_LIGHTING_SERVER_RECV_STATUS_MSG_EVT:
+        if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_STATUS) {
+            bt_mesh_free_buf(arg->value.status.sensor_status.data);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void btc_ble_mesh_lighting_server_callback(esp_ble_mesh_lighting_server_cb_param_t *cb_params, uint8_t act)
+{
+    btc_msg_t msg = {0};
+
+    LOG_DEBUG("%s", __func__);
+
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_LIGHTING_SERVER;
+    msg.act = act;
+
+    btc_transfer_context(
+        &msg, cb_params, sizeof(esp_ble_mesh_lighting_server_cb_param_t), btc_ble_mesh_lighting_server_copy_req_data);
+}
+
+void bt_mesh_lighting_server_cb_evt_to_btc(u8_t evt_type,
+        struct bt_mesh_model *model,
+        struct bt_mesh_msg_ctx *ctx,
+        const u8_t *val, size_t len)
+{
+    esp_ble_mesh_lighting_server_cb_param_t cb_params = {0};
+    size_t length;
+    uint8_t act;
+
+    if (model == NULL || ctx == NULL) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    switch (evt_type) {
+    case BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE:
+        act = ESP_BLE_MESH_LIGHTING_SERVER_STATE_CHANGE_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG:
+        act = ESP_BLE_MESH_LIGHTING_SERVER_RECV_GET_MSG_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG:
+        act = ESP_BLE_MESH_LIGHTING_SERVER_RECV_SET_MSG_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_STATUS_MSG:
+        act = ESP_BLE_MESH_LIGHTING_SERVER_RECV_STATUS_MSG_EVT;
+        break;
+    default:
+        LOG_ERROR("%s, Unknown Lighting Server event type", __func__);
+        return;
+    }
+
+    cb_params.model = (esp_ble_mesh_model_t *)model;
+    cb_params.ctx.net_idx = ctx->net_idx;
+    cb_params.ctx.app_idx = ctx->app_idx;
+    cb_params.ctx.addr = ctx->addr;
+    cb_params.ctx.recv_ttl = ctx->recv_ttl;
+    cb_params.ctx.recv_op = ctx->recv_op;
+    cb_params.ctx.recv_dst = ctx->recv_dst;
+
+    if (val && len) {
+        length = (len <= sizeof(cb_params.value)) ? len : sizeof(cb_params.value);
+        memcpy(&cb_params.value, val, length);
+    }
+
+    btc_ble_mesh_lighting_server_callback(&cb_params, act);
+    return;
+}
+
+void btc_ble_mesh_lighting_server_cb_handler(btc_msg_t *msg)
+{
+    esp_ble_mesh_lighting_server_cb_param_t *param = NULL;
+
+    if (!msg || !msg->arg) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    param = (esp_ble_mesh_lighting_server_cb_param_t *)(msg->arg);
+
+    if (msg->act < ESP_BLE_MESH_LIGHTING_SERVER_EVT_MAX) {
+        btc_ble_mesh_lighting_server_cb_to_app(msg->act, param);
+    } else {
+        LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act);
+    }
+
+    btc_ble_mesh_lighting_server_free_req_data(msg);
+    return;
+}

+ 302 - 5
components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c

@@ -48,6 +48,7 @@
 #include "sensor_client.h"
 #include "time_scene_client.h"
 #include "client_common.h"
+#include "state_binding.h"
 
 #include "btc_ble_mesh_prov.h"
 #include "btc_ble_mesh_config_model.h"
@@ -176,6 +177,16 @@ void btc_ble_mesh_model_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
         }
         break;
     }
+    case BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE:
+        LOG_DEBUG("%s, BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE", __func__);
+        dst->model_update_state.value = osi_malloc(sizeof(esp_ble_mesh_server_state_value_t));
+        if (dst->model_update_state.value) {
+            memcpy(dst->model_update_state.value, src->model_update_state.value,
+                sizeof(esp_ble_mesh_server_state_value_t));
+        } else {
+            LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+        }
+        break;
     default:
         LOG_DEBUG("%s, Unknown deep copy act %d", __func__, msg->act);
         break;
@@ -203,6 +214,11 @@ static void btc_ble_mesh_model_arg_deep_free(btc_msg_t *msg)
             osi_free(arg->model_send.ctx);
         }
         break;
+    case BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE:
+        if (arg->model_update_state.value) {
+            osi_free(arg->model_update_state.value);
+        }
+        break;
     default:
         break;
     }
@@ -422,7 +438,7 @@ static void btc_ble_mesh_model_send_comp_cb(esp_ble_mesh_model_t *model, esp_ble
     mesh_param.model_send_comp.err_code = err;
     mesh_param.model_send_comp.opcode = opcode;
     mesh_param.model_send_comp.model = model;
-    mesh_param.model_send_comp.ctx   = ctx;
+    mesh_param.model_send_comp.ctx = ctx;
 
     msg.sig = BTC_SIG_API_CB;
     msg.pid = BTC_PID_MODEL;
@@ -457,6 +473,29 @@ static void btc_ble_mesh_model_publish_comp_cb(esp_ble_mesh_model_t *model, int
     return;
 }
 
+static void btc_ble_mesh_server_model_update_state_comp_cb(esp_ble_mesh_model_t *model,
+        esp_ble_mesh_server_state_type_t type, int err)
+{
+    esp_ble_mesh_model_cb_param_t mesh_param = {0};
+    btc_msg_t msg = {0};
+    bt_status_t ret;
+
+    mesh_param.server_model_update_state.err_code = err;
+    mesh_param.server_model_update_state.model = model;
+    mesh_param.server_model_update_state.type = type;
+
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_MODEL;
+    msg.act = ESP_BLE_MESH_SERVER_MODEL_UPDATE_STATE_COMP_EVT;
+    ret = btc_transfer_context(&msg, &mesh_param,
+                               sizeof(esp_ble_mesh_model_cb_param_t), NULL);
+
+    if (ret != BT_STATUS_SUCCESS) {
+        LOG_ERROR("%s btc_transfer_context failed", __func__);
+    }
+    return;
+}
+
 #if CONFIG_BLE_MESH_NODE
 static void btc_ble_mesh_oob_pub_key_cb(void)
 {
@@ -1230,6 +1269,45 @@ extern const struct bt_mesh_model_op sensor_cli_op[];
 extern const struct bt_mesh_model_op time_cli_op[];
 extern const struct bt_mesh_model_op scene_cli_op[];
 extern const struct bt_mesh_model_op scheduler_cli_op[];
+/* Generic Server Models */
+extern const struct bt_mesh_model_op gen_onoff_srv_op[];
+extern const struct bt_mesh_model_op gen_level_srv_op[];
+extern const struct bt_mesh_model_op gen_def_trans_time_srv_op[];
+extern const struct bt_mesh_model_op gen_power_onoff_srv_op[];
+extern const struct bt_mesh_model_op gen_power_onoff_setup_srv_op[];
+extern const struct bt_mesh_model_op gen_power_level_srv_op[];
+extern const struct bt_mesh_model_op gen_power_level_setup_srv_op[];
+extern const struct bt_mesh_model_op gen_battery_srv_op[];
+extern const struct bt_mesh_model_op gen_location_srv_op[];
+extern const struct bt_mesh_model_op gen_location_setup_srv_op[];
+extern const struct bt_mesh_model_op gen_user_prop_srv_op[];
+extern const struct bt_mesh_model_op gen_admin_prop_srv_op[];
+extern const struct bt_mesh_model_op gen_manu_prop_srv_op[];
+extern const struct bt_mesh_model_op gen_client_prop_srv_op[];
+/* Lighting Server Models */
+extern const struct bt_mesh_model_op light_lightness_srv_op[];
+extern const struct bt_mesh_model_op light_lightness_setup_srv_op[];
+extern const struct bt_mesh_model_op light_ctl_srv_op[];
+extern const struct bt_mesh_model_op light_ctl_setup_srv_op[];
+extern const struct bt_mesh_model_op light_ctl_temp_srv_op[];
+extern const struct bt_mesh_model_op light_hsl_srv_op[];
+extern const struct bt_mesh_model_op light_hsl_hue_srv_op[];
+extern const struct bt_mesh_model_op light_hsl_sat_srv_op[];
+extern const struct bt_mesh_model_op light_hsl_setup_srv_op[];
+extern const struct bt_mesh_model_op light_xyl_srv_op[];
+extern const struct bt_mesh_model_op light_xyl_setup_srv_op[];
+extern const struct bt_mesh_model_op light_lc_srv_op[];
+extern const struct bt_mesh_model_op light_lc_setup_srv_op[];
+/* Time and Scenes Server Models */
+extern const struct bt_mesh_model_op time_srv_op[];
+extern const struct bt_mesh_model_op time_setup_srv_op[];
+extern const struct bt_mesh_model_op scene_srv_op[];
+extern const struct bt_mesh_model_op scene_setup_srv_op[];
+extern const struct bt_mesh_model_op scheduler_srv_op[];
+extern const struct bt_mesh_model_op scheduler_setup_srv_op[];
+/* Sensor Server Models */
+extern const struct bt_mesh_model_op sensor_srv_op[];
+extern const struct bt_mesh_model_op sensor_setup_srv_op[];
 
 static void btc_ble_mesh_model_op_add(esp_ble_mesh_model_t *model)
 {
@@ -1240,8 +1318,8 @@ static void btc_ble_mesh_model_op_add(esp_ble_mesh_model_t *model)
         return;
     }
 
-    /* 1. For SIG client models, model->op will be NULL and initialized here.
-     * 2. The vendor model opcode is 3 bytes.
+    /* For SIG client and server models, model->op will be NULL and initialized here.
+     * For vendor models whose opcode is 3 bytes, model->op will be initialized here.
      */
     if ((model->op != NULL) && (model->op->opcode >= 0x10000)) {
         goto add_model_op;
@@ -1419,10 +1497,221 @@ static void btc_ble_mesh_model_op_add(esp_ble_mesh_model_t *model)
         }
         break;
     }
-    default: {
+    case BLE_MESH_MODEL_ID_GEN_ONOFF_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_onoff_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_LEVEL_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_level_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_def_trans_time_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_power_onoff_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_power_onoff_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_power_level_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_power_level_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_BATTERY_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_battery_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_LOCATION_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_location_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_user_prop_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_admin_prop_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_manu_prop_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_client_prop_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)gen_location_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_lightness_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_lightness_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_ctl_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_ctl_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_ctl_temp_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_hsl_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_hsl_hue_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_hsl_sat_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_hsl_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_XYL_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_xyl_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_xyl_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_LC_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_lc_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)light_lc_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_TIME_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)time_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_TIME_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)time_setup_srv_op;
+        if (model->pub) {
+            /* Time Setup Server model does not support subscribing nor publishing. */
+            LOG_ERROR("%s, Time Setup Server shall not support publication", __func__);
+            return;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_SCENE_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)scene_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_SCENE_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)scene_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_SCHEDULER_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)scheduler_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)scheduler_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_SENSOR_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)sensor_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    case BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV:
+        model->op = (esp_ble_mesh_model_op_t *)sensor_setup_srv_op;
+        if (model->pub) {
+            model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update;
+        }
+        break;
+    default:
         goto add_model_op;
     }
-    }
     return;
 
 add_model_op:
@@ -1447,6 +1736,7 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg)
         LOG_ERROR("%s, Invalid parameter", __func__);
         return;
     }
+
     arg = (btc_ble_mesh_prov_args_t *)(msg->arg);
 
     switch (msg->act) {
@@ -1887,6 +2177,13 @@ void btc_ble_mesh_model_call_handler(btc_msg_t *msg)
                                         arg->model_send.opcode, err);
         break;
     }
+    case BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE:
+        err = bt_mesh_update_binding_state(
+                (struct bt_mesh_model *)arg->model_update_state.model, arg->model_update_state.type,
+                (bt_mesh_server_state_value_t *)arg->model_update_state.value);
+        btc_ble_mesh_server_model_update_state_comp_cb(arg->model_update_state.model,
+            arg->model_update_state.type, err);
+        break;
     default:
         LOG_WARN("%s, Unknown msg->act %d", __func__, msg->act);
         break;

+ 273 - 0
components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c

@@ -624,3 +624,276 @@ void btc_ble_mesh_sensor_client_cb_handler(btc_msg_t *msg)
     return;
 }
 
+/* Sensor Server Models related functions */
+
+static inline void btc_ble_mesh_sensor_server_cb_to_app(
+        esp_ble_mesh_sensor_server_cb_event_t event,
+        esp_ble_mesh_sensor_server_cb_param_t *param)
+{
+    esp_ble_mesh_sensor_server_cb_t btc_ble_mesh_cb =
+        (esp_ble_mesh_sensor_server_cb_t)btc_profile_cb_get(BTC_PID_SENSOR_SERVER);
+    if (btc_ble_mesh_cb) {
+        btc_ble_mesh_cb(event, param);
+    }
+}
+
+static void btc_ble_mesh_sensor_server_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src)
+{
+    esp_ble_mesh_sensor_server_cb_param_t *p_dest_data = (esp_ble_mesh_sensor_server_cb_param_t *)p_dest;
+    esp_ble_mesh_sensor_server_cb_param_t *p_src_data = (esp_ble_mesh_sensor_server_cb_param_t *)p_src;
+    u16_t length;
+
+    if (!msg || !p_src_data || !p_dest_data) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    switch (msg->act) {
+    case ESP_BLE_MESH_SENSOR_SERVER_STATE_CHANGE_EVT:
+        if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET ||
+            p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK) {
+            if (p_src_data->value.state_change.sensor_cadence_set.trigger_delta_down) {
+                length = p_src_data->value.state_change.sensor_cadence_set.trigger_delta_down->len;
+                p_dest_data->value.state_change.sensor_cadence_set.trigger_delta_down = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.state_change.sensor_cadence_set.trigger_delta_down == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.state_change.sensor_cadence_set.trigger_delta_down,
+                                       p_src_data->value.state_change.sensor_cadence_set.trigger_delta_down->data,
+                                       p_src_data->value.state_change.sensor_cadence_set.trigger_delta_down->len);
+            }
+            if (p_src_data->value.state_change.sensor_cadence_set.trigger_delta_up) {
+                length = p_src_data->value.state_change.sensor_cadence_set.trigger_delta_up->len;
+                p_dest_data->value.state_change.sensor_cadence_set.trigger_delta_up = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.state_change.sensor_cadence_set.trigger_delta_up == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.state_change.sensor_cadence_set.trigger_delta_up,
+                                       p_src_data->value.state_change.sensor_cadence_set.trigger_delta_up->data,
+                                       p_src_data->value.state_change.sensor_cadence_set.trigger_delta_up->len);
+            }
+            if (p_src_data->value.state_change.sensor_cadence_set.fast_cadence_low) {
+                length = p_src_data->value.state_change.sensor_cadence_set.fast_cadence_low->len;
+                p_dest_data->value.state_change.sensor_cadence_set.fast_cadence_low = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.state_change.sensor_cadence_set.fast_cadence_low == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.state_change.sensor_cadence_set.fast_cadence_low,
+                                       p_src_data->value.state_change.sensor_cadence_set.fast_cadence_low->data,
+                                       p_src_data->value.state_change.sensor_cadence_set.fast_cadence_low->len);
+            }
+            if (p_src_data->value.state_change.sensor_cadence_set.fast_cadence_high) {
+                length = p_src_data->value.state_change.sensor_cadence_set.fast_cadence_high->len;
+                p_dest_data->value.state_change.sensor_cadence_set.fast_cadence_high = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.state_change.sensor_cadence_set.fast_cadence_high == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.state_change.sensor_cadence_set.fast_cadence_high,
+                                       p_src_data->value.state_change.sensor_cadence_set.fast_cadence_high->data,
+                                       p_src_data->value.state_change.sensor_cadence_set.fast_cadence_high->len);
+            }
+        } else if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET ||
+            p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK) {
+            if (p_src_data->value.state_change.sensor_setting_set.setting_value) {
+                length = p_src_data->value.state_change.sensor_setting_set.setting_value->len;
+                p_dest_data->value.state_change.sensor_setting_set.setting_value = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.state_change.sensor_setting_set.setting_value == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.state_change.sensor_setting_set.setting_value,
+                                       p_src_data->value.state_change.sensor_setting_set.setting_value->data,
+                                       p_src_data->value.state_change.sensor_setting_set.setting_value->len);
+            }
+        }
+        break;
+    case ESP_BLE_MESH_SENSOR_SERVER_RECV_GET_MSG_EVT:
+        if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET) {
+            if (p_src_data->value.get.sensor_column.raw_value_x) {
+                length = p_src_data->value.get.sensor_column.raw_value_x->len;
+                p_dest_data->value.get.sensor_column.raw_value_x = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.get.sensor_column.raw_value_x == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.get.sensor_column.raw_value_x,
+                                       p_src_data->value.get.sensor_column.raw_value_x->data,
+                                       p_src_data->value.get.sensor_column.raw_value_x->len);
+            }
+        } else if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET) {
+            if (p_src_data->value.get.sensor_series.raw_value) {
+                length = p_src_data->value.get.sensor_series.raw_value->len;
+                p_dest_data->value.get.sensor_series.raw_value = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.get.sensor_series.raw_value == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.get.sensor_series.raw_value,
+                                       p_src_data->value.get.sensor_series.raw_value->data,
+                                       p_src_data->value.get.sensor_series.raw_value->len);
+            }
+        }
+        break;
+    case ESP_BLE_MESH_SENSOR_SERVER_RECV_SET_MSG_EVT:
+        if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET ||
+            p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK) {
+            if (p_src_data->value.set.sensor_cadence.cadence) {
+                length = p_src_data->value.set.sensor_cadence.cadence->len;
+                p_dest_data->value.set.sensor_cadence.cadence = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.set.sensor_cadence.cadence == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.set.sensor_cadence.cadence,
+                                       p_src_data->value.set.sensor_cadence.cadence->data,
+                                       p_src_data->value.set.sensor_cadence.cadence->len);
+            }
+        } else if (p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET ||
+            p_src_data->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK) {
+            if (p_src_data->value.set.sensor_setting.setting_raw) {
+                length = p_src_data->value.set.sensor_setting.setting_raw->len;
+                p_dest_data->value.set.sensor_setting.setting_raw = bt_mesh_alloc_buf(length);
+                if (p_dest_data->value.set.sensor_setting.setting_raw == NULL) {
+                    LOG_ERROR("%s, Failed to allocate memory, act %d", __func__, msg->act);
+                    return;
+                }
+                net_buf_simple_add_mem(p_dest_data->value.set.sensor_setting.setting_raw,
+                                       p_src_data->value.set.sensor_setting.setting_raw->data,
+                                       p_src_data->value.set.sensor_setting.setting_raw->len);
+            }
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void btc_ble_mesh_sensor_server_free_req_data(btc_msg_t *msg)
+{
+    esp_ble_mesh_sensor_server_cb_param_t *arg = NULL;
+
+    if (!msg || !msg->arg) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    arg = (esp_ble_mesh_sensor_server_cb_param_t *)(msg->arg);
+
+    switch (msg->act) {
+    case ESP_BLE_MESH_SENSOR_SERVER_STATE_CHANGE_EVT:
+        if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET ||
+            arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK) {
+            bt_mesh_free_buf(arg->value.state_change.sensor_cadence_set.trigger_delta_down);
+            bt_mesh_free_buf(arg->value.state_change.sensor_cadence_set.trigger_delta_up);
+            bt_mesh_free_buf(arg->value.state_change.sensor_cadence_set.fast_cadence_low);
+            bt_mesh_free_buf(arg->value.state_change.sensor_cadence_set.fast_cadence_high);
+        } else if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET ||
+            arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK) {
+            bt_mesh_free_buf(arg->value.state_change.sensor_setting_set.setting_value);
+        }
+        break;
+    case ESP_BLE_MESH_SENSOR_SERVER_RECV_GET_MSG_EVT:
+        if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET) {
+            bt_mesh_free_buf(arg->value.get.sensor_column.raw_value_x);
+        } else if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET) {
+            bt_mesh_free_buf(arg->value.get.sensor_series.raw_value);
+        }
+        break;
+    case ESP_BLE_MESH_SENSOR_SERVER_RECV_SET_MSG_EVT:
+        if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET ||
+            arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK) {
+            bt_mesh_free_buf(arg->value.set.sensor_cadence.cadence);
+        } else if (arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET ||
+            arg->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK) {
+            bt_mesh_free_buf(arg->value.set.sensor_setting.setting_raw);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void btc_ble_mesh_sensor_server_callback(esp_ble_mesh_sensor_server_cb_param_t *cb_params, uint8_t act)
+{
+    btc_msg_t msg = {0};
+
+    LOG_DEBUG("%s", __func__);
+
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_SENSOR_SERVER;
+    msg.act = act;
+
+    btc_transfer_context(
+        &msg, cb_params, sizeof(esp_ble_mesh_sensor_server_cb_param_t), btc_ble_mesh_sensor_server_copy_req_data);
+}
+
+void bt_mesh_sensor_server_cb_evt_to_btc(u8_t evt_type,
+        struct bt_mesh_model *model,
+        struct bt_mesh_msg_ctx *ctx,
+        const u8_t *val, size_t len)
+{
+    esp_ble_mesh_sensor_server_cb_param_t cb_params = {0};
+    size_t length;
+    uint8_t act;
+
+    if (model == NULL || ctx == NULL) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    switch (evt_type) {
+    case BTC_BLE_MESH_EVT_SENSOR_SERVER_STATE_CHANGE:
+        act = ESP_BLE_MESH_SENSOR_SERVER_STATE_CHANGE_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG:
+        act = ESP_BLE_MESH_SENSOR_SERVER_RECV_GET_MSG_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_SET_MSG:
+        act = ESP_BLE_MESH_SENSOR_SERVER_RECV_SET_MSG_EVT;
+        break;
+    default:
+        LOG_ERROR("%s, Unknown Sensor Server event type", __func__);
+        return;
+    }
+
+    cb_params.model = (esp_ble_mesh_model_t *)model;
+    cb_params.ctx.net_idx = ctx->net_idx;
+    cb_params.ctx.app_idx = ctx->app_idx;
+    cb_params.ctx.addr = ctx->addr;
+    cb_params.ctx.recv_ttl = ctx->recv_ttl;
+    cb_params.ctx.recv_op = ctx->recv_op;
+    cb_params.ctx.recv_dst = ctx->recv_dst;
+
+    if (val && len) {
+        length = (len <= sizeof(cb_params.value)) ? len : sizeof(cb_params.value);
+        memcpy(&cb_params.value, val, length);
+    }
+
+    btc_ble_mesh_sensor_server_callback(&cb_params, act);
+    return;
+}
+
+void btc_ble_mesh_sensor_server_cb_handler(btc_msg_t *msg)
+{
+    esp_ble_mesh_sensor_server_cb_param_t *param = NULL;
+
+    if (!msg || !msg->arg) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    param = (esp_ble_mesh_sensor_server_cb_param_t *)(msg->arg);
+
+    if (msg->act < ESP_BLE_MESH_SENSOR_SERVER_EVT_MAX) {
+        btc_ble_mesh_sensor_server_cb_to_app(msg->act, param);
+    } else {
+        LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act);
+    }
+
+    btc_ble_mesh_sensor_server_free_req_data(msg);
+    return;
+}

+ 96 - 0
components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c

@@ -381,3 +381,99 @@ void btc_ble_mesh_time_scene_client_cb_handler(btc_msg_t *msg)
     return;
 }
 
+/* Time and Scenes Server Models related functions */
+
+static inline void btc_ble_mesh_time_scene_server_cb_to_app(
+        esp_ble_mesh_time_scene_server_cb_event_t event,
+        esp_ble_mesh_time_scene_server_cb_param_t *param)
+{
+    esp_ble_mesh_time_scene_server_cb_t btc_ble_mesh_cb =
+        (esp_ble_mesh_time_scene_server_cb_t)btc_profile_cb_get(BTC_PID_TIME_SCENE_SERVER);
+    if (btc_ble_mesh_cb) {
+        btc_ble_mesh_cb(event, param);
+    }
+}
+
+static void btc_ble_mesh_time_scene_server_callback(esp_ble_mesh_time_scene_server_cb_param_t *cb_params, uint8_t act)
+{
+    btc_msg_t msg = {0};
+
+    LOG_DEBUG("%s", __func__);
+
+    msg.sig = BTC_SIG_API_CB;
+    msg.pid = BTC_PID_TIME_SCENE_SERVER;
+    msg.act = act;
+
+    btc_transfer_context(
+        &msg, cb_params, sizeof(esp_ble_mesh_time_scene_server_cb_param_t), NULL);
+}
+
+void bt_mesh_time_scene_server_cb_evt_to_btc(u8_t evt_type,
+        struct bt_mesh_model *model,
+        struct bt_mesh_msg_ctx *ctx,
+        const u8_t *val, size_t len)
+{
+    esp_ble_mesh_time_scene_server_cb_param_t cb_params = {0};
+    size_t length;
+    uint8_t act;
+
+    if (model == NULL || ctx == NULL) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    switch (evt_type) {
+    case BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE:
+        act = ESP_BLE_MESH_TIME_SCENE_SERVER_STATE_CHANGE_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG:
+        act = ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_GET_MSG_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG:
+        act = ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_SET_MSG_EVT;
+        break;
+    case BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_STATUS_MSG:
+        act = ESP_BLE_MESH_TIME_SCENE_SERVER_RECV_STATUS_MSG_EVT;
+        break;
+    default:
+        LOG_ERROR("%s, Unknown Time Scene Server event type", __func__);
+        return;
+    }
+
+    cb_params.model = (esp_ble_mesh_model_t *)model;
+    cb_params.ctx.net_idx = ctx->net_idx;
+    cb_params.ctx.app_idx = ctx->app_idx;
+    cb_params.ctx.addr = ctx->addr;
+    cb_params.ctx.recv_ttl = ctx->recv_ttl;
+    cb_params.ctx.recv_op = ctx->recv_op;
+    cb_params.ctx.recv_dst = ctx->recv_dst;
+
+    if (val && len) {
+        length = (len <= sizeof(cb_params.value)) ? len : sizeof(cb_params.value);
+        memcpy(&cb_params.value, val, length);
+    }
+
+    btc_ble_mesh_time_scene_server_callback(&cb_params, act);
+    return;
+}
+
+void btc_ble_mesh_time_scene_server_cb_handler(btc_msg_t *msg)
+{
+    esp_ble_mesh_time_scene_server_cb_param_t *param = NULL;
+
+    if (!msg || !msg->arg) {
+        LOG_ERROR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    param = (esp_ble_mesh_time_scene_server_cb_param_t *)(msg->arg);
+
+    if (msg->act < ESP_BLE_MESH_TIME_SCENE_SERVER_EVT_MAX) {
+        btc_ble_mesh_time_scene_server_cb_to_app(msg->act, param);
+    } else {
+        LOG_ERROR("%s, Unknown msg->act = %d", __func__, msg->act);
+    }
+
+    return;
+}
+

+ 14 - 0
components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h

@@ -60,4 +60,18 @@ void bt_mesh_generic_client_cb_evt_to_btc(u32_t opcode, u8_t evt_type,
         struct bt_mesh_msg_ctx *ctx,
         const u8_t *val, size_t len);
 
+typedef enum {
+    BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE,
+    BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG,
+    BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG,
+    BTC_BLE_MESH_EVT_GENERIC_SERVER_MAX,
+} btc_ble_mesh_generic_server_evt_t;
+
+void bt_mesh_generic_server_cb_evt_to_btc(u8_t evt_type,
+        struct bt_mesh_model *model,
+        struct bt_mesh_msg_ctx *ctx,
+        const u8_t *val, size_t len);
+
+void btc_ble_mesh_generic_server_cb_handler(btc_msg_t *msg);
+
 #endif /* _BTC_BLE_MESH_GENERIC_MODEL_H_ */

+ 15 - 0
components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h

@@ -60,5 +60,20 @@ void bt_mesh_lighting_client_cb_evt_to_btc(u32_t opcode, u8_t evt_type,
         struct bt_mesh_msg_ctx *ctx,
         const u8_t *val, size_t len);
 
+typedef enum {
+    BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE,
+    BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG,
+    BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG,
+    BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_STATUS_MSG,
+    BTC_BLE_MESH_EVT_LIGHTING_SERVER_MAX,
+} btc_ble_mesh_lighting_server_evt_t;
+
+void bt_mesh_lighting_server_cb_evt_to_btc(u8_t evt_type,
+        struct bt_mesh_model *model,
+        struct bt_mesh_msg_ctx *ctx,
+        const u8_t *val, size_t len);
+
+void btc_ble_mesh_lighting_server_cb_handler(btc_msg_t *msg);
+
 #endif /* _BTC_BLE_MESH_LIGHTING_MODEL_H_ */
 

+ 6 - 0
components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h

@@ -69,6 +69,7 @@ typedef enum {
     BTC_BLE_MESH_ACT_MODEL_PUBLISH,
     BTC_BLE_MESH_ACT_SERVER_MODEL_SEND,
     BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND,
+    BTC_BLE_MESH_ACT_SERVER_MODEL_UPDATE_STATE,
 } btc_ble_mesh_model_act_t;
 
 typedef union {
@@ -215,6 +216,11 @@ typedef union {
         uint8_t device_role;
         int32_t msg_timeout;
     } model_send;
+    struct ble_mesh_server_model_update_state_args {
+        esp_ble_mesh_model_t *model;
+        esp_ble_mesh_server_state_type_t type;
+        esp_ble_mesh_server_state_value_t *value;
+    } model_update_state;
 } btc_ble_mesh_model_args_t;
 
 void btc_ble_mesh_prov_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);

+ 14 - 0
components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h

@@ -60,5 +60,19 @@ void bt_mesh_sensor_client_cb_evt_to_btc(u32_t opcode, u8_t evt_type,
         struct bt_mesh_msg_ctx *ctx,
         const u8_t *val, size_t len);
 
+typedef enum {
+    BTC_BLE_MESH_EVT_SENSOR_SERVER_STATE_CHANGE,
+    BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG,
+    BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_SET_MSG,
+    BTC_BLE_MESH_EVT_SENSOR_SERVER_MAX,
+} btc_ble_mesh_sensor_server_evt_t;
+
+void bt_mesh_sensor_server_cb_evt_to_btc(u8_t evt_type,
+        struct bt_mesh_model *model,
+        struct bt_mesh_msg_ctx *ctx,
+        const u8_t *val, size_t len);
+
+void btc_ble_mesh_sensor_server_cb_handler(btc_msg_t *msg);
+
 #endif /* _BTC_BLE_MESH_SENSOR_MODEL_H_ */
 

+ 15 - 0
components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h

@@ -60,5 +60,20 @@ void bt_mesh_time_scene_client_cb_evt_to_btc(u32_t opcode, u8_t evt_type,
         struct bt_mesh_msg_ctx *ctx,
         const u8_t *val, size_t len);
 
+typedef enum {
+    BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE,
+    BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG,
+    BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG,
+    BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_STATUS_MSG,
+    BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_MAX,
+} btc_ble_mesh_time_scene_server_evt_t;
+
+void bt_mesh_time_scene_server_cb_evt_to_btc(u8_t evt_type,
+        struct bt_mesh_model *model,
+        struct bt_mesh_msg_ctx *ctx,
+        const u8_t *val, size_t len);
+
+void btc_ble_mesh_time_scene_server_cb_handler(btc_msg_t *msg);
+
 #endif /* _BTC_BLE_MESH_TIME_SCENE_MODEL_H_ */
 

+ 42 - 2
components/bt/esp_ble_mesh/mesh_core/access.c

@@ -27,13 +27,18 @@
 #include "transport.h"
 #include "access.h"
 #include "foundation.h"
-
 #include "mesh_common.h"
+#include "provisioner_main.h"
+
 #include "generic_client.h"
 #include "sensor_client.h"
 #include "time_scene_client.h"
 #include "lighting_client.h"
-#include "provisioner_main.h"
+
+#include "generic_server.h"
+#include "sensor_server.h"
+#include "time_scene_server.h"
+#include "lighting_server.h"
 
 #define BLE_MESH_SDU_MAX_LEN    384
 
@@ -103,6 +108,41 @@ static const struct {
 #if defined(CONFIG_BLE_MESH_LIGHT_LC_CLI)
     { BLE_MESH_MODEL_ID_LIGHT_LC_CLI, bt_mesh_light_lc_cli_init },
 #endif
+    { BLE_MESH_MODEL_ID_GEN_ONOFF_SRV,             bt_mesh_gen_onoff_srv_init             },
+    { BLE_MESH_MODEL_ID_GEN_LEVEL_SRV,             bt_mesh_gen_level_srv_init             },
+    { BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV,    bt_mesh_gen_def_trans_time_srv_init    },
+    { BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV,       bt_mesh_gen_power_onoff_srv_init       },
+    { BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV, bt_mesh_gen_power_onoff_setup_srv_init },
+    { BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV,       bt_mesh_gen_power_level_srv_init       },
+    { BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV, bt_mesh_gen_power_level_setup_srv_init },
+    { BLE_MESH_MODEL_ID_GEN_BATTERY_SRV,           bt_mesh_gen_battery_srv_init           },
+    { BLE_MESH_MODEL_ID_GEN_LOCATION_SRV,          bt_mesh_gen_location_srv_init          },
+    { BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV,    bt_mesh_gen_location_setup_srv_init    },
+    { BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV,         bt_mesh_gen_user_prop_srv_init         },
+    { BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV,        bt_mesh_gen_admin_prop_srv_init        },
+    { BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV, bt_mesh_gen_manu_prop_srv_init         },
+    { BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV,       bt_mesh_gen_client_prop_srv_init       },
+    { BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV,       bt_mesh_light_lightness_srv_init       },
+    { BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV, bt_mesh_light_lightness_setup_srv_init },
+    { BLE_MESH_MODEL_ID_LIGHT_CTL_SRV,             bt_mesh_light_ctl_srv_init             },
+    { BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV,       bt_mesh_light_ctl_setup_srv_init       },
+    { BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV,        bt_mesh_light_ctl_temp_srv_init        },
+    { BLE_MESH_MODEL_ID_LIGHT_HSL_SRV,             bt_mesh_light_hsl_srv_init             },
+    { BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV,         bt_mesh_light_hsl_hue_srv_init         },
+    { BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV,         bt_mesh_light_hsl_sat_srv_init         },
+    { BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV,       bt_mesh_light_hsl_setup_srv_init       },
+    { BLE_MESH_MODEL_ID_LIGHT_XYL_SRV,             bt_mesh_light_xyl_srv_init             },
+    { BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV,       bt_mesh_light_xyl_setup_srv_init       },
+    { BLE_MESH_MODEL_ID_LIGHT_LC_SRV,              bt_mesh_light_lc_srv_init              },
+    { BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV,        bt_mesh_light_lc_setup_srv_init        },
+    { BLE_MESH_MODEL_ID_TIME_SRV,                  bt_mesh_time_srv_init                  },
+    { BLE_MESH_MODEL_ID_TIME_SETUP_SRV,            bt_mesh_time_setup_srv_init            },
+    { BLE_MESH_MODEL_ID_SCENE_SRV,                 bt_mesh_scene_srv_init                 },
+    { BLE_MESH_MODEL_ID_SCENE_SETUP_SRV,           bt_mesh_scene_setup_srv_init           },
+    { BLE_MESH_MODEL_ID_SCHEDULER_SRV,             bt_mesh_scheduler_srv_init             },
+    { BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV,       bt_mesh_scheduler_setup_srv_init       },
+    { BLE_MESH_MODEL_ID_SENSOR_SRV,                bt_mesh_sensor_srv_init                },
+    { BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV,          bt_mesh_sensor_setup_srv_init          },
 };
 
 void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,

+ 2 - 0
components/bt/esp_ble_mesh/mesh_core/include/mesh_kernel.h

@@ -182,6 +182,8 @@ struct k_delayed_work {
  */
 int k_delayed_work_submit(struct k_delayed_work *work, s32_t delay);
 
+int k_delayed_work_submit_periodic(struct k_delayed_work *work, s32_t period);
+
 /**
  * @brief Get time remaining before a delayed work gets scheduled.
  *

+ 18 - 2
components/bt/esp_ble_mesh/mesh_core/mesh_kernel.c

@@ -124,8 +124,7 @@ void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler)
     return;
 }
 
-int k_delayed_work_submit(struct k_delayed_work *work,
-                          s32_t delay)
+int k_delayed_work_submit(struct k_delayed_work *work, s32_t delay)
 {
     assert(work != NULL && bm_alarm_hash_map != NULL);
 
@@ -141,6 +140,23 @@ int k_delayed_work_submit(struct k_delayed_work *work,
     return 0;
 }
 
+int k_delayed_work_submit_periodic(struct k_delayed_work *work, s32_t period)
+{
+    assert(work != NULL && bm_alarm_hash_map != NULL);
+
+    osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work);
+    if (alarm == NULL) {
+        BT_WARN("%s, Unable to find expected alarm in hash map", __func__);
+        return -EINVAL;
+    }
+
+    /* Cancel the alarm first before starting it. */
+    osi_alarm_cancel(alarm);
+    osi_alarm_set_periodic(alarm, period);
+
+    return 0;
+}
+
 int k_delayed_work_cancel(struct k_delayed_work *work)
 {
     assert(work != NULL && bm_alarm_hash_map != NULL);

+ 3 - 3
components/bt/esp_ble_mesh/mesh_models/client/include/client_common.h

@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef _MODEL_COMMON_H_
-#define _MODEL_COMMON_H_
+#ifndef _CLIENT_COMMON_H_
+#define _CLIENT_COMMON_H_
 
 #include "mesh_access.h"
 
@@ -136,5 +136,5 @@ typedef struct {
  */
 int bt_mesh_set_client_model_role(bt_mesh_role_param_t *common);
 
-#endif /* _MODEL_COMMON_H_ */
+#endif /* _CLIENT_COMMON_H_ */
 

+ 150 - 0
components/bt/esp_ble_mesh/mesh_models/server/device_property.c

@@ -0,0 +1,150 @@
+// Copyright 2017-2019 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.
+
+#include <string.h>
+#include <stdint.h>
+
+#include "mesh_types.h"
+
+#include "server_common.h"
+#include "device_property.h"
+
+static struct bt_mesh_dev_prop {
+    u16_t prop_id;
+    u8_t  len;
+} device_properties [] = {
+    { BLE_MESH_INVALID_DEVICE_PROPERTY_ID,                               0xFF },
+    { BLE_MESH_AVERAGE_AMBIENT_TEMPERATURE_IN_A_PERIOD_OF_DAY,           0x03 },
+    { BLE_MESH_AVERAGE_INPUT_CURRENT,                                    0x03 },
+    { BLE_MESH_AVERAGE_INPUT_VOLTAGE,                                    0x03 },
+    { BLE_MESH_AVERAGE_OUTPUT_CURRENT,                                   0x03 },
+    { BLE_MESH_AVERAGE_OUTPUT_VOLTAGE,                                   0x03 },
+    { BLE_MESH_CENTER_BEAM_INTENSITY_AT_FULL_POWER,                      0x02 },
+    { BLE_MESH_CHROMATICITY_TOLERANCE,                                   0x01 },
+    { BLE_MESH_COLOR_RENDERING_INDEX_R9,                                 0x01 },
+    { BLE_MESH_COLOR_RENDERING_INDEX_RA,                                 0x01 },
+    { BLE_MESH_DEVICE_APPEARANCE,                                        0x02 },
+    { BLE_MESH_DEVICE_COUNTRY_OF_ORIGIN,                                 0x02 },
+    { BLE_MESH_DEVICE_DATE_OF_MANUFACTURE,                               0x04 },
+    { BLE_MESH_DEVICE_ENERGY_USE_SINCE_TURN_ON,                          0x04 },
+    { BLE_MESH_DEVICE_FIRMWARE_REVISION,                                 0x08 },
+    { BLE_MESH_DEVICE_GLOBAL_TRADE_ITEM_NUMBER,                          0x08 },
+    { BLE_MESH_DEVICE_HARDWARE_REVISION,                                 0x16 },
+    { BLE_MESH_DEVICE_MANUFACTURER_NAME,                                 0x36 },
+    { BLE_MESH_DEVICE_MODEL_NUMBER,                                      0x24 },
+    { BLE_MESH_DEVICE_OPERATING_TEMPERATURE_RANGE_SPECIFICATION,         0x04 },
+    { BLE_MESH_DEVICE_OPERATING_TEMPERATURE_STATISTICAL_VALUES,          0x09 },
+    { BLE_MESH_DEVICE_OVER_TEMPERATURE_EVENT_STATISTICS,                 0x06 },
+    { BLE_MESH_DEVICE_POWER_RANGE_SPECIFICATION,                         0x12 },
+    { BLE_MESH_DEVICE_RUNTIME_SINCE_TURN_ON,                             0x04 },
+    { BLE_MESH_DEVICE_RUNTIME_WARRANTY,                                  0x04 },
+    { BLE_MESH_DEVICE_SERIAL_NUMBER,                                     0x16 },
+    { BLE_MESH_DEVICE_SOFTWARE_REVISION,                                 0x08 },
+    { BLE_MESH_DEVICE_UNDER_TEMPERATURE_EVENT_STATISTICS,                0x06 },
+    { BLE_MESH_INDOOR_AMBIENT_TEMPERATURE_STATISTICAL_VALUES,            0x05 },
+    { BLE_MESH_INITIAL_CIE_1931_CHROMATICITY_COORDINATES,                0x04 },
+    { BLE_MESH_INITIAL_CORRELATED_COLOR_TEMPERATURE,                     0x02 },
+    { BLE_MESH_INITIAL_LUMINOUS_FLUX,                                    0x02 },
+    { BLE_MESH_INITIAL_PLANCKIAN_DISTANCE,                               0x02 },
+    { BLE_MESH_INPUT_CURRENT_RANGE_SPECIFICATION,                        0x06 },
+    { BLE_MESH_INPUT_CURRENT_STATISTICS,                                 0x09 },
+    { BLE_MESH_INPUT_OVER_CURRENT_EVENT_STATISTICS,                      0x06 },
+    { BLE_MESH_INPUT_OVER_RIPPLE_VOLTAGE_EVENT_STATISTICS,               0x06 },
+    { BLE_MESH_INPUT_OVER_VOLTAGE_EVENT_STATISTICS,                      0x06 },
+    { BLE_MESH_INPUT_UNDER_CURRENT_EVENT_STATISTICS,                     0x06 },
+    { BLE_MESH_INPUT_UNDER_VOLTAGE_EVENT_STATISTICS,                     0x06 },
+    { BLE_MESH_INPUT_VOLTAGE_RANGE_SPECIFICATION,                        0x06 },
+    { BLE_MESH_INPUT_VOLTAGE_RIPPLE_SPECIFICATION,                       0x01 },
+    { BLE_MESH_INPUT_VOLTAGE_STATISTICS,                                 0x09 },
+    { BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_ON,                        0x04 },
+    { BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_PROLONG,                   0x04 },
+    { BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_STANDBY,                   0x04 },
+    { BLE_MESH_LIGHT_CONTROL_LIGHTNESS_ON,                               0x02 },
+    { BLE_MESH_LIGHT_CONTROL_LIGHTNESS_PROLONG,                          0x02 },
+    { BLE_MESH_LIGHT_CONTROL_LIGHTNESS_STANDBY,                          0x02 },
+    { BLE_MESH_LIGHT_CONTROL_REGULATOR_ACCURACY,                         0x01 },
+    { BLE_MESH_LIGHT_CONTROL_REGULATOR_KID,                              0x04 },
+    { BLE_MESH_LIGHT_CONTROL_REGULATOR_KIU,                              0x04 },
+    { BLE_MESH_LIGHT_CONTROL_REGULATOR_KPD,                              0x04 },
+    { BLE_MESH_LIGHT_CONTROL_REGULATOR_KPU,                              0x04 },
+    { BLE_MESH_LIGHT_CONTROL_TIME_FADE,                                  0x03 },
+    { BLE_MESH_LIGHT_CONTROL_TIME_FADE_ON,                               0x03 },
+    { BLE_MESH_LIGHT_CONTROL_TIME_FADE_STANDBY_AUTO,                     0x03 },
+    { BLE_MESH_LIGHT_CONTROL_TIME_FADE_STANDBY_MANUAL,                   0x03 },
+    { BLE_MESH_LIGHT_CONTROL_TIME_OCCUPANCY_DELAY,                       0x03 },
+    { BLE_MESH_LIGHT_CONTROL_TIME_PROLONG,                               0x03 },
+    { BLE_MESH_LIGHT_CONTROL_TIME_RUN_ON,                                0x03 },
+    { BLE_MESH_LUMEN_MAINTENANCE_FACTOR,                                 0x01 },
+    { BLE_MESH_LUMINOUS_EFFICACY,                                        0x02 },
+    { BLE_MESH_LUMINOUS_ENERGY_SINCE_TURN_ON,                            0x04 },
+    { BLE_MESH_LUMINOUS_EXPOSURE,                                        0x04 },
+    { BLE_MESH_LUMINOUS_FLUX_RANGE,                                      0x04 },
+    { BLE_MESH_MOTION_SENSED,                                            0x01 },
+    { BLE_MESH_MOTION_THRESHOLD,                                         0x01 },
+    { BLE_MESH_OPEN_CIRCUIT_EVENT_STATISTICS,                            0x06 },
+    { BLE_MESH_OUTDOOR_STATISTICAL_VALUES,                               0x05 },
+    { BLE_MESH_OUTPUT_CURRENT_RANGE,                                     0x04 },
+    { BLE_MESH_OUTPUT_CURRENT_STATISTICS,                                0x09 },
+    { BLE_MESH_OUTPUT_RIPPLE_VOLTAGE_SPECIFICATION,                      0x01 },
+    { BLE_MESH_OUTPUT_VOLTAGE_RANGE,                                     0x06 },
+    { BLE_MESH_OUTPUT_VOLTAGE_STATISTICS,                                0x09 },
+    { BLE_MESH_OVER_OUTPUT_RIPPLE_VOLTAGE_EVENT_STATISTICS,              0x06 },
+    { BLE_MESH_PEOPLE_COUNT,                                             0x02 },
+    { BLE_MESH_PRESENCE_DETECTED,                                        0x01 },
+    { BLE_MESH_PRESENT_AMBIENT_LIGHT_LEVEL,                              0x04 },
+    { BLE_MESH_PRESENT_AMBIENT_TEMPERATURE,                              0x01 },
+    { BLE_MESH_PRESENT_CIE_1931_CHROMATICITY,                            0x04 },
+    { BLE_MESH_PRESENT_CORRELATED_COLOR_TEMPERATURE,                     0x02 },
+    { BLE_MESH_PRESENT_DEVICE_INPUT_POWER,                               0x04 },
+    { BLE_MESH_PRESENT_DEVICE_OPERATING_EFFICIENCY,                      0x01 },
+    { BLE_MESH_PRESENT_DEVICE_OPERATING_TEMPERATURE,                     0x02 },
+    { BLE_MESH_PRESENT_ILLUMINANCE,                                      0x04 },
+    { BLE_MESH_PRESENT_INDOOR_AMBIENT_TEMPERATURE,                       0x01 },
+    { BLE_MESH_PRESENT_INPUT_CURRENT,                                    0x02 },
+    { BLE_MESH_PRESENT_INPUT_RIPPLE_VOLTAGE,                             0x01 },
+    { BLE_MESH_PRESENT_INPUT_VOLTAGE,                                    0x02 },
+    { BLE_MESH_PRESENT_LUMINOUS_FLUX,                                    0x02 },
+    { BLE_MESH_PRESENT_OUTDOOR_AMBIENT_TEMPERATURE,                      0x01 },
+    { BLE_MESH_PRESENT_OUTPUT_CURRENT,                                   0x02 },
+    { BLE_MESH_PRESENT_OUTPUT_VOLTAGE,                                   0x02 },
+    { BLE_MESH_PRESENT_PLANCKIAN_DISTANCE,                               0x02 },
+    { BLE_MESH_PRESENT_RELATIVE_OUTPUT_RIPPLE_VOLTAGE,                   0x01 },
+    { BLE_MESH_RELATIVE_DEVICE_ENERGY_USE_IN_A_PERIOD_OF_DAY,            0x06 },
+    { BLE_MESH_RELATIVE_DEVICE_RUNTIME_IN_A_GENERIC_LEVEL_RANGE,         0x05 },
+    { BLE_MESH_RELATIVE_EXPOSURE_TIME_IN_AN_ILLUMINANCE_RANGE,           0x09 },
+    { BLE_MESH_RELATIVE_RUNTIME_IN_A_CORRELATED_COLOR_TEMPERATURE_RANGE, 0x04 },
+    { BLE_MESH_RELATIVE_RUNTIME_IN_A_DEVICE_OPERATING_TEMPERATURE_RANGE, 0x05 },
+    { BLE_MESH_RELATIVE_RUNTIME_IN_AN_INPUT_CURRENT_RANGE,               0x05 },
+    { BLE_MESH_RELATIVE_RUNTIME_IN_AN_INPUT_VOLTAGE_RANGE,               0x05 },
+    { BLE_MESH_SHORT_CIRCUIT_EVENT_STATISTICS,                           0x06 },
+    { BLE_MESH_TIME_SINCE_MOTION_SENSED,                                 0x02 },
+    { BLE_MESH_TIME_SINCE_PRESENCE_DETECTED,                             0x02 },
+    { BLE_MESH_TOTAL_DEVICE_ENERGY_USE,                                  0x04 },
+    { BLE_MESH_TOTAL_DEVICE_OFF_ON_CYCLES,                               0x04 },
+    { BLE_MESH_TOTAL_DEVICE_POWER_ON_CYCLES,                             0x04 },
+    { BLE_MESH_TOTAL_DEVICE_POWER_ON_TIME,                               0x04 },
+    { BLE_MESH_TOTAL_DEVICE_RUNTIME,                                     0x04 },
+    { BLE_MESH_TOTAL_LIGHT_EXPOSURE_TIME,                                0x04 },
+    { BLE_MESH_TOTAL_LUMINOUS_ENERGY,                                    0x04 },
+};
+
+u8_t bt_mesh_get_dev_prop_len(u16_t prop_id)
+{
+    if (prop_id > BLE_MESH_TOTAL_LUMINOUS_ENERGY) {
+        BT_ERR("%s, Unknown Device Property ID 0x%04x", __func__, prop_id);
+        return UINT8_MAX;
+    }
+
+    return device_properties[prop_id].len;
+}

+ 2629 - 0
components/bt/esp_ble_mesh/mesh_models/server/generic_server.c

@@ -0,0 +1,2629 @@
+/* Bluetooth: Mesh Generic Server Models
+ *
+ * Copyright (c) 2018 Vikrant More
+ * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "osi/mutex.h"
+
+#include "mesh_types.h"
+#include "mesh_kernel.h"
+#include "mesh_trace.h"
+#include "mesh_common.h"
+#include "mesh.h"
+#include "access.h"
+#include "model_opcode.h"
+#include "transport.h"
+
+#include "server_common.h"
+#include "state_binding.h"
+#include "state_transition.h"
+#include "device_property.h"
+
+#include "btc_ble_mesh_generic_model.h"
+
+static osi_mutex_t generic_server_mutex;
+
+static void bt_mesh_generic_server_mutex_new(void)
+{
+    if (!generic_server_mutex) {
+        osi_mutex_new(&generic_server_mutex);
+        __ASSERT(generic_server_mutex, "%s, fail", __func__);
+    }
+}
+
+void bt_mesh_generic_server_lock(void)
+{
+    osi_mutex_lock(&generic_server_mutex, OSI_MUTEX_MAX_TIMEOUT);
+}
+
+void bt_mesh_generic_server_unlock(void)
+{
+    osi_mutex_unlock(&generic_server_mutex);
+}
+
+/* message handlers (Start) */
+
+/* Generic OnOff Server message handlers */
+static void send_gen_onoff_status(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  bool publish)
+{
+    struct bt_mesh_gen_onoff_srv *srv = model->user_data;
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 3;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS);
+    net_buf_simple_add_u8(msg, srv->state.onoff);
+    if (srv->transition.counter) {
+        bt_mesh_server_calc_remain_time(&srv->transition);
+        net_buf_simple_add_u8(msg, srv->state.target_onoff);
+        net_buf_simple_add_u8(msg, srv->transition.remain_time);
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_onoff_get(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_onoff_srv *srv = model->user_data;
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    send_gen_onoff_status(model, ctx, false);
+    return;
+}
+
+void gen_onoff_publish(struct bt_mesh_model *model)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    send_gen_onoff_status(model, NULL, true);
+    return;
+}
+
+static void gen_onoff_set(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_onoff_srv *srv = model->user_data;
+    u8_t tid, onoff, trans_time, delay;
+    bool optional;
+    s64_t now;
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    onoff = net_buf_simple_pull_u8(buf);
+    if (onoff > BLE_MESH_STATE_ON) {
+        BT_ERR("%s, Invalid OnOff value 0x%02x", __func__, onoff);
+        return;
+    }
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .onoff_set.op_en = optional,
+            .onoff_set.onoff = onoff,
+            .onoff_set.tid = tid,
+            .onoff_set.trans_time = trans_time,
+            .onoff_set.delay = delay,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
+            send_gen_onoff_status(model, ctx, false);
+        }
+        send_gen_onoff_status(model, NULL, true);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_generic_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state.target_onoff = onoff;
+
+    if (srv->state.target_onoff != srv->state.onoff) {
+        generic_onoff_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_gen_server_state_change_t change = {
+            .gen_onoff_set.onoff = srv->state.onoff,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
+            send_gen_onoff_status(model, ctx, false);
+        }
+        send_gen_onoff_status(model, NULL, true);
+
+        bt_mesh_generic_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state.onoff = srv->state.target_onoff;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
+        send_gen_onoff_status(model, ctx, false);
+    }
+    send_gen_onoff_status(model, NULL, true);
+
+    bt_mesh_generic_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+/* Generic Level Server message handlers */
+static void send_gen_level_status(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  bool publish)
+{
+    struct bt_mesh_gen_level_srv *srv = model->user_data;
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 5;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_LEVEL_STATUS);
+    net_buf_simple_add_le16(msg, srv->state.level);
+    if (srv->transition.counter) {
+        if (srv->state.move_start) {
+            if (srv->state.positive) {
+                net_buf_simple_add_le16(msg, INT16_MAX);
+            } else { /* 0 should not be possible */
+                net_buf_simple_add_le16(msg, INT16_MIN);
+            }
+            net_buf_simple_add_u8(msg, BLE_MESH_UNKNOWN_REMAIN_TIME);
+        } else {
+            bt_mesh_server_calc_remain_time(&srv->transition);
+            net_buf_simple_add_le16(msg, srv->state.target_level);
+            net_buf_simple_add_u8(msg, srv->transition.remain_time);
+        }
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_level_get(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_level_srv *srv = model->user_data;
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    send_gen_level_status(model, ctx, false);
+    return;
+}
+
+void gen_level_publish(struct bt_mesh_model *model)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    send_gen_level_status(model, NULL, true);
+    return;
+}
+
+static void gen_level_set(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_level_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    bool optional;
+    s16_t level;
+    s64_t now;
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    level = (s16_t) net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .level_set.op_en = optional,
+            .level_set.level = level,
+            .level_set.tid = tid,
+            .level_set.trans_time = trans_time,
+            .level_set.delay = delay,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LEVEL_SET) {
+            send_gen_level_status(model, ctx, false);
+        }
+        send_gen_level_status(model, NULL, true);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_generic_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state.target_level = level;
+
+    /**
+     * If the target state is equal to the current state, the transition
+     * shall not be started and is considered complete.
+     */
+    if (srv->state.target_level != srv->state.level) {
+        generic_level_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_gen_server_state_change_t change = {
+            .gen_level_set.level = srv->state.level,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LEVEL_SET) {
+            send_gen_level_status(model, ctx, false);
+        }
+        send_gen_level_status(model, NULL, true);
+
+        bt_mesh_generic_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state.level = srv->state.target_level;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LEVEL_SET) {
+        send_gen_level_status(model, ctx, false);
+    }
+    send_gen_level_status(model, NULL, true);
+
+    bt_mesh_generic_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+static void gen_delta_set(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_level_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    s32_t tmp32, delta;
+    bool optional;
+    s64_t now;
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    delta = (s32_t)net_buf_simple_pull_le32(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .delta_set.op_en = optional,
+            .delta_set.delta_level = delta,
+            .delta_set.tid = tid,
+            .delta_set.trans_time = trans_time,
+            .delta_set.delay = delay,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    /**
+     * A number of Generic Delta Set and Generic Delta Set Unacknowledged
+     * messages with the same transaction identifier set in the TID field
+     * may be sent.
+     *
+     * A new transaction starts when the TID field value in the received
+     * message is different from the TID field value in the previously
+     * received message that was using the same source and destination
+     * addresses or from the most recently received message with the same
+     * TID field value that was received 6 or more seconds earlier.
+     */
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (srv->state.last_delta == delta) {
+            if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DELTA_SET) {
+                send_gen_level_status(model, ctx, false);
+            }
+            send_gen_level_status(model, NULL, true);
+            /* In this condition, no event will be callback to application layer */
+            return;
+        }
+
+        tmp32 = srv->state.last_level + delta;
+    } else {
+        /* Starts a new transaction */
+        srv->state.last_level = srv->state.level;
+        tmp32 = srv->state.level + delta;
+    }
+
+    bt_mesh_generic_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state.last_delta = delta;
+    if (tmp32 < INT16_MIN) {
+        tmp32 = INT16_MIN;
+    } else if (tmp32 > INT16_MAX) {
+        tmp32 = INT16_MAX;
+    }
+    srv->state.target_level = tmp32;
+
+    /**
+     * If the target state is equal to the current state, the transition
+     * shall not be started and is considered complete.
+     */
+    if (srv->state.target_level != srv->state.level) {
+        generic_level_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_gen_server_state_change_t change = {
+            .gen_delta_set.level = srv->state.level,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DELTA_SET) {
+            send_gen_level_status(model, ctx, false);
+        }
+        send_gen_level_status(model, NULL, true);
+
+        bt_mesh_generic_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state.level = srv->state.target_level;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DELTA_SET) {
+        send_gen_level_status(model, ctx, false);
+    }
+    send_gen_level_status(model, NULL, true);
+
+    bt_mesh_generic_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+static void gen_move_set(struct bt_mesh_model *model,
+                         struct bt_mesh_msg_ctx *ctx,
+                         struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_level_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    bool optional;
+    s16_t delta;
+    s32_t tmp32;
+    s64_t now;
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    delta = (s16_t) net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .move_set.op_en = optional,
+            .move_set.delta_level = delta,
+            .move_set.tid = tid,
+            .move_set.trans_time = trans_time,
+            .move_set.delay = delay,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MOVE_SET) {
+            send_gen_level_status(model, ctx, false);
+        }
+        send_gen_level_status(model, NULL, true);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_generic_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state.last_delta = delta;
+
+    tmp32 = srv->state.level + delta;
+    if (tmp32 < INT16_MIN) {
+        tmp32 = INT16_MIN;
+    } else if (tmp32 > INT16_MAX) {
+        tmp32 = INT16_MAX;
+    }
+    srv->state.target_level = tmp32;
+
+    /**
+     * If the target state is equal to the current state, the transition
+     * shall not be started and is considered complete.
+     */
+    if (srv->state.target_level != srv->state.level) {
+        generic_level_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_gen_server_state_change_t change = {
+            .gen_move_set.level = srv->state.level,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MOVE_SET) {
+            send_gen_level_status(model, ctx, false);
+        }
+        send_gen_level_status(model, NULL, true);
+        srv->state.move_start = false;
+
+        bt_mesh_generic_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    if (delta) {
+        srv->state.move_start = true;
+        srv->state.positive = (delta > 0) ? true : false;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MOVE_SET) {
+        send_gen_level_status(model, ctx, false);
+    }
+    send_gen_level_status(model, NULL, true);
+
+    bt_mesh_generic_server_unlock();
+
+    /**
+     * If (trans_time == 0) OR (delta == 0)
+     * 1. If the resulting Transition Time is equal to 0 or is undefined,
+     *    the Generic Move Set command will not initiate any Generic Level
+     *    state change.
+     * 2. When a Generic Level Server receives the message with a value of
+     *    the Delta Level field equal to 0, it shall stop changing the
+     *    Generic Level state. (if delta == 0, srv->state.target_level will
+     *    equal to srv->state.level)
+     */
+    if (srv->transition.counter == 0U) {
+        srv->state.move_start = false;
+        bt_mesh_gen_server_state_change_t change = {
+            .gen_move_set.level = srv->state.level,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        return;
+    }
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+/* Generic Default Transition Time Server message handlers */
+static void send_gen_def_trans_time_status(struct bt_mesh_model *model,
+                                           struct bt_mesh_msg_ctx *ctx,
+                                           bool publish)
+{
+    struct bt_mesh_gen_def_trans_time_srv *srv = model->user_data;
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 1;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_STATUS);
+    net_buf_simple_add_u8(msg, srv->state.trans_time);
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_def_trans_time_get(struct bt_mesh_model *model,
+                                   struct bt_mesh_msg_ctx *ctx,
+                                   struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_def_trans_time_srv *srv = model->user_data;
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    send_gen_def_trans_time_status(model, ctx, false);
+    return;
+}
+
+static void gen_def_trans_time_set(struct bt_mesh_model *model,
+                                   struct bt_mesh_msg_ctx *ctx,
+                                   struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_def_trans_time_srv *srv = model->user_data;
+    u8_t trans_time;
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    trans_time = net_buf_simple_pull_u8(buf);
+    if ((trans_time & 0x3F) == 0x3F) {
+        BT_WARN("%s, Invalid Transaction Number of Steps 0x3F", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .def_trans_time_set.trans_time = trans_time,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (srv->state.trans_time != trans_time) {
+        srv->state.trans_time = trans_time;
+    }
+
+    bt_mesh_gen_server_state_change_t change = {
+        .gen_def_trans_time_set.trans_time = trans_time,
+    };
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET) {
+        send_gen_def_trans_time_status(model, ctx, false);
+    }
+    send_gen_def_trans_time_status(model, NULL, true);
+
+    return;
+}
+
+/* Generic Power OnOff Server message handlers */
+static void send_gen_onpowerup_status(struct bt_mesh_model *model,
+                                      struct bt_mesh_msg_ctx *ctx,
+                                      bool publish)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 1;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_ONPOWERUP_STATUS);
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV: {
+        struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
+        net_buf_simple_add_u8(msg, srv->state->onpowerup);
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV: {
+        struct bt_mesh_gen_power_onoff_setup_srv *srv = model->user_data;
+        net_buf_simple_add_u8(msg, srv->state->onpowerup);
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Generic Power OnOff Server 0x%04x", __func__, model->id);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_onpowerup_get(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    send_gen_onpowerup_status(model, ctx, false);
+    return;
+}
+
+/* Generic Power OnOff Setup Server message handlers */
+void gen_onpowerup_publish(struct bt_mesh_model *model)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV: {
+        struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Generic Power OnOff Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV: {
+        struct bt_mesh_gen_power_onoff_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Generic Power OnOff Setup Server state", __func__);
+            return;
+        }
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Generic Power OnOff Server 0x%04x", __func__, model->id);
+        return;
+    }
+
+    send_gen_onpowerup_status(model, NULL, true);
+    return;
+}
+
+static void gen_onpowerup_set(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_power_onoff_setup_srv *srv = model->user_data;
+    u8_t onpowerup;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    onpowerup = net_buf_simple_pull_u8(buf);
+    if (onpowerup > BLE_MESH_STATE_RESTORE) {
+        BT_WARN("%s, Invalid OnPowerUp value 0x%02x", __func__, onpowerup);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .onpowerup_set.onpowerup = onpowerup,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (srv->state->onpowerup != onpowerup) {
+        srv->state->onpowerup = onpowerup;
+    }
+
+    bt_mesh_gen_server_state_change_t change = {
+        .gen_onpowerup_set.onpowerup = onpowerup,
+    };
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET) {
+        send_gen_onpowerup_status(model, ctx, false);
+    }
+    send_gen_onpowerup_status(model, NULL, true);
+
+    return;
+}
+
+/* Generic Power Level Server message handlers */
+static void send_gen_power_level_status(struct bt_mesh_model *model,
+                                        struct bt_mesh_msg_ctx *ctx,
+                                        bool publish, u16_t opcode)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 5;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, opcode);
+    switch (opcode) {
+    case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS:
+    case BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS: {
+        struct bt_mesh_gen_power_level_srv *srv = model->user_data;
+        if (opcode == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS) {
+            net_buf_simple_add_le16(msg, srv->state->power_actual);
+            if (srv->transition.counter) {
+                bt_mesh_server_calc_remain_time(&srv->transition);
+                net_buf_simple_add_le16(msg, srv->state->target_power_actual);
+                net_buf_simple_add_u8(msg, srv->transition.remain_time);
+            }
+        } else if (opcode == BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS) {
+            net_buf_simple_add_le16(msg, srv->state->power_last);
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV) {
+            struct bt_mesh_gen_power_level_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->power_default);
+        } else if (model->id == BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV) {
+            struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->power_default);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV) {
+            struct bt_mesh_gen_power_level_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->power_range_min);
+            net_buf_simple_add_le16(msg, srv->state->power_range_max);
+        } else if (model->id == BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV) {
+            struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->power_range_min);
+            net_buf_simple_add_le16(msg, srv->state->power_range_max);
+        }
+        break;
+    default:
+        BT_WARN("%s, Unknown Generic Power status opcode 0x%04x", __func__, opcode);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_power_level_get(struct bt_mesh_model *model,
+                                struct bt_mesh_msg_ctx *ctx,
+                                struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_power_level_srv *srv = model->user_data;
+    u16_t opcode;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET:
+        opcode = BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET:
+        opcode = BLE_MESH_MODEL_OP_GEN_POWER_LAST_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET:
+        opcode = BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET:
+        opcode = BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS;
+        break;
+    default:
+        BT_WARN("%s, Unknown Generic Power Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    send_gen_power_level_status(model, ctx, false, opcode);
+    return;
+}
+
+void gen_power_level_publish(struct bt_mesh_model *model, u16_t opcode)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV: {
+        struct bt_mesh_gen_power_level_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Generic Power Level Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case ESP_BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV: {
+        struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Generic Power Level Setup Server state", __func__);
+            return;
+        }
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Generic Power Level Server 0x%04x", __func__, model->id);
+        return;
+    }
+
+    send_gen_power_level_status(model, NULL, true, opcode);
+    return;
+}
+
+static void gen_power_level_set(struct bt_mesh_model *model,
+                                struct bt_mesh_msg_ctx *ctx,
+                                struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_power_level_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    bool optional;
+    u16_t power;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    power = net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .power_level_set.op_en = optional,
+            .power_level_set.power = power,
+            .power_level_set.tid = tid,
+            .power_level_set.trans_time = trans_time,
+            .power_level_set.delay = delay,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET) {
+            send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
+        }
+        send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_generic_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    if (power) {
+        if (srv->state->power_range_min && power < srv->state->power_range_min) {
+            power = srv->state->power_range_min;
+        } else if (srv->state->power_range_max && power > srv->state->power_range_max) {
+            power = srv->state->power_range_max;
+        }
+    }
+    srv->state->target_power_actual = power;
+
+    /* If the target state is equal to the current state, the transition
+     * shall not be started and is considered complete.
+     */
+    if (srv->state->target_power_actual != srv->state->power_actual) {
+        generic_power_level_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_gen_server_state_change_t change = {
+            .gen_power_level_set.power = srv->state->power_actual,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET) {
+            send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
+        }
+        send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
+
+        bt_mesh_generic_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state->power_actual = srv->state->target_power_actual;
+        /* Whenever the Generic Power Actual state is changed to a non-zero value
+         * as a result of a non-transactional message or a completed sequence of
+         * transactional messages, the value of the Generic Power Last state shall
+         * be set to the value of the Generic Power Actual state.
+         */
+        if (srv->state->power_actual) {
+            srv->state->power_last = srv->state->power_actual;
+        }
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET) {
+        send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
+    }
+    send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
+
+    bt_mesh_generic_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+/* Generic Power Level Setup Server message handlers */
+static void gen_power_default_set(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
+    u16_t power;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    power = net_buf_simple_pull_le16(buf);
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .power_default_set.power = power, /* Just callback the actual recived value */
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    /**
+     * Value 0x0000 has a special meaning defined: use the value of the
+     * Generic Power Last state as the default value.
+     */
+    if (power == 0x0000) {
+        power = srv->state->power_last;
+    }
+
+    if (srv->state->power_default != power) {
+        srv->state->power_default = power;
+    }
+
+    bt_mesh_gen_server_state_change_t change = {
+        .gen_power_default_set.power = power,
+    };
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET) {
+        send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS);
+    }
+    send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_STATUS);
+
+    return;
+}
+
+static void gen_power_range_set(struct bt_mesh_model *model,
+                                struct bt_mesh_msg_ctx *ctx,
+                                struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
+    u16_t range_min, range_max;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    range_min = net_buf_simple_pull_le16(buf);
+    range_max = net_buf_simple_pull_le16(buf);
+
+    if (range_min > range_max) {
+        BT_ERR("%s, Range Min 0x%04x is greater than Range Max 0x%04x",
+            __func__, range_min, range_max);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .power_range_set.range_min = range_min,
+            .power_range_set.range_max = range_max,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (range_min == 0x0000) {
+        srv->state->status_code = BLE_MESH_CANNOT_SET_RANGE_MIN;
+    } else if (range_max == 0x0000) {
+        srv->state->status_code = BLE_MESH_CANNOT_SET_RANGE_MAX;
+    } else {
+        srv->state->status_code = BLE_MESH_RANGE_UPDATE_SUCCESS;
+    }
+
+    if (range_min && srv->state->power_range_min != range_min) {
+        srv->state->power_range_min = range_min;
+    }
+
+    if (range_max && srv->state->power_range_max != range_max) {
+        srv->state->power_range_max = range_max;
+    }
+
+    bt_mesh_gen_server_state_change_t change = {
+        .gen_power_range_set.range_min = srv->state->power_range_min,
+        .gen_power_range_set.range_max = srv->state->power_range_max,
+    };
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET) {
+        send_gen_power_level_status(model, ctx, false, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS);
+    }
+    send_gen_power_level_status(model, NULL, true, BLE_MESH_MODEL_OP_GEN_POWER_RANGE_STATUS);
+
+    return;
+}
+
+/* Generic Battery Server message handlers */
+static void gen_battery_get(struct bt_mesh_model *model,
+                            struct bt_mesh_msg_ctx *ctx,
+                            struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_battery_srv *srv = model->user_data;
+    NET_BUF_SIMPLE_DEFINE(msg, 2 + 8 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    bt_mesh_model_msg_init(&msg, BLE_MESH_MODEL_OP_GEN_BATTERY_STATUS);
+    net_buf_simple_add_le32(&msg, srv->state.time_to_discharge << 8 | srv->state.battery_level);
+    net_buf_simple_add_le32(&msg, srv->state.battery_flags << 24 | srv->state.time_to_charge);
+
+    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL));
+    return;
+}
+
+/* Generic Location Server message handlers */
+static void send_gen_location_status(struct bt_mesh_model *model,
+                                     struct bt_mesh_msg_ctx *ctx,
+                                     bool publish, u16_t opcode)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 1 + 10;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, opcode);
+    switch (opcode) {
+    case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_GEN_LOCATION_SRV) {
+            struct bt_mesh_gen_location_srv *srv = model->user_data;
+            net_buf_simple_add_le32(msg, srv->state->global_latitude);
+            net_buf_simple_add_le32(msg, srv->state->global_longitude);
+            net_buf_simple_add_le16(msg, srv->state->global_altitude);
+        } else if (model->id == BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV) {
+            struct bt_mesh_gen_location_setup_srv *srv = model->user_data;
+            net_buf_simple_add_le32(msg, srv->state->global_latitude);
+            net_buf_simple_add_le32(msg, srv->state->global_longitude);
+            net_buf_simple_add_le16(msg, srv->state->global_altitude);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_GEN_LOCATION_SRV) {
+            struct bt_mesh_gen_location_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->local_north);
+            net_buf_simple_add_le16(msg, srv->state->local_east);
+            net_buf_simple_add_le16(msg, srv->state->local_altitude);
+            net_buf_simple_add_u8(msg, srv->state->floor_number);
+            net_buf_simple_add_le16(msg, srv->state->uncertainty);
+        } else if (model->id == BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV) {
+            struct bt_mesh_gen_location_setup_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->local_north);
+            net_buf_simple_add_le16(msg, srv->state->local_east);
+            net_buf_simple_add_le16(msg, srv->state->local_altitude);
+            net_buf_simple_add_u8(msg, srv->state->floor_number);
+            net_buf_simple_add_le16(msg, srv->state->uncertainty);
+        }
+        break;
+    default:
+        BT_WARN("%s, Unknown Generic Location status opcode 0x%04x", __func__, opcode);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_location_get(struct bt_mesh_model *model,
+                             struct bt_mesh_msg_ctx *ctx,
+                             struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_location_srv *srv = model->user_data;
+    u16_t opcode;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET:
+        opcode = BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET:
+        opcode = BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS;
+        break;
+    default:
+        BT_WARN("%s, Unknown Generic Location Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    send_gen_location_status(model, ctx, false, opcode);
+    return;
+}
+
+/* Generic Location Setup Server message handlers */
+static void gen_location_set(struct bt_mesh_model *model,
+                             struct bt_mesh_msg_ctx *ctx,
+                             struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_location_setup_srv *srv = model->user_data;
+    u16_t opcode;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET:
+    case BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK: {
+        opcode = BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_STATUS;
+        s32_t latitude = net_buf_simple_pull_le32(buf);
+        s32_t longitude = net_buf_simple_pull_le32(buf);
+        s16_t altitude = net_buf_simple_pull_le16(buf);
+
+        /* Callback the received message to the application layer */
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_gen_server_recv_set_msg_t set = {
+                .loc_global_set.latitude = latitude,
+                .loc_global_set.longitude = longitude,
+                .loc_global_set.altitude = altitude,
+            };
+            bt_mesh_generic_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+            return;
+        }
+
+        if (latitude != 0x80000000) {
+            srv->state->global_latitude = latitude;
+        }
+        if (longitude != 0x80000000) {
+            srv->state->global_longitude = longitude;
+        }
+        if (altitude != 0x7FFF) {
+            srv->state->global_altitude = altitude;
+        }
+
+        bt_mesh_gen_server_state_change_t change = {
+            .gen_loc_global_set.latitude = srv->state->global_latitude,
+            .gen_loc_global_set.longitude = srv->state->global_longitude,
+            .gen_loc_global_set.altitude = srv->state->global_altitude,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        break;
+    }
+    case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET:
+    case BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK: {
+        opcode = BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_STATUS;
+        u16_t north = net_buf_simple_pull_le16(buf);
+        u16_t east = net_buf_simple_pull_le16(buf);
+        u16_t altitude = net_buf_simple_pull_le16(buf);
+        u8_t floor = net_buf_simple_pull_u8(buf);
+        u16_t uncertainty = net_buf_simple_pull_le16(buf);
+
+        /* Callback the received message to the application layer */
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_gen_server_recv_set_msg_t set = {
+                .loc_local_set.north = north,
+                .loc_local_set.east = east,
+                .loc_local_set.altitude = altitude,
+                .loc_local_set.floor_number = floor,
+                .loc_local_set.uncertainty = uncertainty,
+            };
+            bt_mesh_generic_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+            return;
+        }
+
+        if (north != 0x8000) {
+            srv->state->local_north = north;
+        }
+        if (east != 0x8000) {
+            srv->state->local_east = east;
+        }
+        if (altitude != 0x7FFF) {
+            srv->state->local_altitude = altitude;
+        }
+        if (floor != 0xFF) {
+            srv->state->floor_number = floor;
+        }
+        srv->state->uncertainty = uncertainty;
+
+        bt_mesh_gen_server_state_change_t change = {
+            .gen_loc_local_set.north = srv->state->local_north,
+            .gen_loc_local_set.east = srv->state->local_east,
+            .gen_loc_local_set.altitude = srv->state->local_altitude,
+            .gen_loc_local_set.floor_number = srv->state->floor_number,
+            .gen_loc_local_set.uncertainty = srv->state->uncertainty,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown Generic Location Set opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET ||
+        ctx->recv_op == BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET) {
+        send_gen_location_status(model, ctx, false, opcode);
+    }
+    send_gen_location_status(model, NULL, true, opcode);
+
+    return;
+}
+
+/* Generic User Property Server message handlers */
+struct bt_mesh_generic_property *gen_get_user_property(struct bt_mesh_model *model,
+                                    u16_t property_id)
+{
+    struct bt_mesh_gen_user_prop_srv *srv = model->user_data;
+    u8_t i;
+
+    for (i = 0U; i < srv->property_count; i++) {
+        if (srv->properties[i].id == property_id) {
+            return &srv->properties[i];
+        }
+    }
+
+    return NULL;
+}
+
+static void send_gen_user_prop_status(struct bt_mesh_model *model,
+                                      struct bt_mesh_msg_ctx *ctx,
+                                      u16_t property_id, bool publish)
+{
+    struct bt_mesh_generic_property *property = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t length;
+
+    if (property_id == BLE_MESH_INVALID_DEVICE_PROPERTY_ID) {
+        BT_ERR("%s, Invalid User Property ID 0x%04x", __func__, property_id);
+        return;
+    }
+
+    property = gen_get_user_property(model, property_id);
+    if (property == NULL) {
+        BT_WARN("%s, User property 0x%04x not exist", __func__, property_id);
+        length = sizeof(property_id);
+    } else {
+        length = sizeof(property->id) + sizeof(property->user_access) + property->val->len;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, 1 + length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_STATUS);
+    if (property == NULL) {
+        net_buf_simple_add_le16(msg, property_id);
+    } else {
+        net_buf_simple_add_le16(msg, property->id);
+        net_buf_simple_add_u8(msg, property->user_access);
+        if ((ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET &&
+            property->user_access != USER_ACCESS_PROHIBIT &&
+            property->user_access != USER_ACCESS_WRITE) ||
+            ((ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET ||
+            ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK) &&
+            property->user_access != USER_ACCESS_PROHIBIT &&
+            property->user_access != USER_ACCESS_READ)) {
+            net_buf_simple_add_mem(msg, property->val->data, property->val->len);
+        }
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_user_prop_get(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_user_prop_srv *srv = model->user_data;
+
+    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        /**
+         * Also we can use __packed for esp_ble_mesh_gen_user_property_get_t,
+         * and directly callback with buf->data & buf->len.
+         */
+        bt_mesh_gen_server_recv_get_msg_t get = {0};
+        const u8_t *param = NULL;
+        size_t len = 0;
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET) {
+            get.user_property_get.id = net_buf_simple_pull_le16(buf);
+            param = (const u8_t *)&get;
+            len = sizeof(get);
+        }
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, param, len);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET: {
+        struct net_buf_simple *msg = NULL;
+        u8_t i;
+        msg = bt_mesh_alloc_buf(1 + srv->property_count * 2 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+        bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_STATUS);
+        for (i = 0U; i < srv->property_count; i++) {
+            if (srv->properties[i].admin_access != ADMIN_NOT_USER_PROP &&
+                srv->properties[i].manu_access != MANU_NOT_USER_PROP) {
+                net_buf_simple_add_le16(msg, srv->properties[i].id);
+            }
+        }
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+        return;
+    }
+    case BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET: {
+        u16_t property_id = net_buf_simple_pull_le16(buf);
+        send_gen_user_prop_status(model, ctx, property_id, false);
+        return;
+    }
+    default:
+        BT_WARN("%s, Unknown Generic User Property Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+}
+
+static void gen_user_prop_set(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_user_prop_srv *srv = model->user_data;
+    struct bt_mesh_generic_property *property = NULL;
+    u16_t property_id;
+    u8_t expect_len;
+
+    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    property_id = net_buf_simple_pull_le16(buf);
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .user_property_set.id = property_id,
+            .user_property_set.value = buf,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    property = gen_get_user_property(model, property_id);
+    if (property == NULL || property->user_access == USER_ACCESS_PROHIBIT ||
+        property->user_access == USER_ACCESS_READ) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET) {
+            send_gen_user_prop_status(model, ctx, property_id, false);
+        }
+        send_gen_user_prop_status(model, ctx, property_id, true);
+        return;
+    }
+
+    /* For BLE Mesh Model BQB test:
+     * PTS will send Generic User Property Set/Set Unack messages with
+     * invalid device property value length, these messages need to be
+     * ignored, otherwise the test case will fail.
+     */
+    expect_len = bt_mesh_get_dev_prop_len(property_id);
+    if (buf->len != expect_len) {
+        BT_ERR("%s, Invalid User Property length, ID 0x%04x, expect %d, actual %d",
+            __func__, property_id, expect_len, buf->len);
+        return;
+    }
+
+    net_buf_simple_reset(property->val);
+    net_buf_simple_add_mem(property->val, buf->data, MIN(buf->len, property->val->size));
+
+    bt_mesh_gen_server_state_change_t change = {
+        .gen_user_prop_set.id = property_id,
+        .gen_user_prop_set.value = property->val,
+    };
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET) {
+        send_gen_user_prop_status(model, ctx, property_id, false);
+    }
+    send_gen_user_prop_status(model, ctx, property_id, true);
+
+    return;
+}
+
+/* Generic Admin Property Server message handlers */
+struct bt_mesh_generic_property *gen_get_admin_property(struct bt_mesh_model *model,
+                                    u16_t property_id)
+{
+    struct bt_mesh_gen_admin_prop_srv *srv = model->user_data;
+    u8_t i;
+
+    for (i = 0U; i < srv->property_count; i++) {
+        if (srv->properties[i].id == property_id) {
+            return &srv->properties[i];
+        }
+    }
+
+    return NULL;
+}
+
+static void send_gen_admin_prop_status(struct bt_mesh_model *model,
+                                       struct bt_mesh_msg_ctx *ctx,
+                                       u16_t property_id, bool publish)
+{
+    struct bt_mesh_generic_property *property = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t length;
+
+    if (property_id == BLE_MESH_INVALID_DEVICE_PROPERTY_ID) {
+        BT_ERR("%s, Invalid User Property ID 0x%04x", __func__, property_id);
+        return;
+    }
+
+    property = gen_get_admin_property(model, property_id);
+    if (property == NULL) {
+        BT_WARN("%s, Admin property 0x%04x not exist", __func__, property_id);
+        length = sizeof(property_id);
+    } else {
+        length = sizeof(property->id) + sizeof(property->admin_access) + property->val->len;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, 1 + length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_STATUS);
+    if (property == NULL) {
+        net_buf_simple_add_le16(msg, property_id);
+    } else {
+        net_buf_simple_add_le16(msg, property->id);
+        net_buf_simple_add_u8(msg, property->admin_access);
+        if (ctx->recv_op != BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET ||
+            property->admin_access != ADMIN_ACCESS_WRITE) {
+            net_buf_simple_add_mem(msg, property->val->data, property->val->len);
+        }
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_admin_prop_get(struct bt_mesh_model *model,
+                               struct bt_mesh_msg_ctx *ctx,
+                               struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_admin_prop_srv *srv = model->user_data;
+
+    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_get_msg_t get = {0};
+        const u8_t *param = NULL;
+        size_t len = 0;
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET) {
+            get.admin_property_get.id = net_buf_simple_pull_le16(buf);
+            param = (const u8_t *)&get;
+            len = sizeof(get);
+        }
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, param, len);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET: {
+        struct net_buf_simple *msg = NULL;
+        u8_t i;
+        msg = bt_mesh_alloc_buf(1 + srv->property_count * 2 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+        bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_STATUS);
+        for (i = 0U; i < srv->property_count; i++) {
+            net_buf_simple_add_le16(msg, srv->properties[i].id);
+        }
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+        return;
+    }
+    case BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET: {
+        u16_t property_id = net_buf_simple_pull_le16(buf);
+        send_gen_admin_prop_status(model, ctx, property_id, false);
+        return;
+    }
+    default:
+        BT_WARN("%s, Unknown Generic Admin Property Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+}
+
+static void gen_admin_prop_set(struct bt_mesh_model *model,
+                               struct bt_mesh_msg_ctx *ctx,
+                               struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_admin_prop_srv *srv = model->user_data;
+    struct bt_mesh_generic_property *property = NULL;
+    u16_t property_id;
+    u8_t access;
+
+    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    property_id = net_buf_simple_pull_le16(buf);
+    access = net_buf_simple_pull_u8(buf);
+    if (access > ADMIN_ACCESS_READ_WRITE) {
+        BT_ERR("%s, Invalid Admin Access 0x%02x", __func__, access);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .admin_property_set.id = property_id,
+            .admin_property_set.access = access,
+            .admin_property_set.value = buf,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    property = gen_get_admin_property(model, property_id);
+    if (property == NULL) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET) {
+            send_gen_admin_prop_status(model, ctx, property_id, false);
+        }
+        send_gen_admin_prop_status(model, ctx, property_id, true);
+        return;
+    }
+
+    property->admin_access = access;
+
+    net_buf_simple_reset(property->val);
+    net_buf_simple_add_mem(property->val, buf->data, MIN(buf->len, property->val->size));
+
+    bt_mesh_gen_server_state_change_t change = {
+        .gen_admin_prop_set.id = property_id,
+        .gen_admin_prop_set.access = property->admin_access,
+        .gen_admin_prop_set.value = property->val,
+    };
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET) {
+        send_gen_admin_prop_status(model, ctx, property_id, false);
+    }
+    send_gen_admin_prop_status(model, ctx, property_id, true);
+
+    return;
+}
+
+/* Generic Manufacturer Property Server message handlers */
+struct bt_mesh_generic_property *gen_get_manu_property(struct bt_mesh_model *model,
+                                    u16_t property_id)
+{
+    struct bt_mesh_gen_manu_prop_srv *srv = model->user_data;
+    u8_t i;
+
+    for (i = 0U; i < srv->property_count; i++) {
+        if (srv->properties[i].id == property_id) {
+            return &srv->properties[i];
+        }
+    }
+
+    return NULL;
+}
+
+static void send_gen_manu_prop_status(struct bt_mesh_model *model,
+                                      struct bt_mesh_msg_ctx *ctx,
+                                      u16_t property_id, bool publish)
+{
+    struct bt_mesh_generic_property *property = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t length;
+
+    if (property_id == BLE_MESH_INVALID_DEVICE_PROPERTY_ID) {
+        BT_ERR("%s, Invalid User Property ID 0x%04x", __func__, property_id);
+        return;
+    }
+
+    property = gen_get_manu_property(model, property_id);
+    if (property == NULL) {
+        BT_WARN("%s, Manufacturer property 0x%04x not exist", __func__, property_id);
+        length = sizeof(property_id);
+    } else {
+        length = sizeof(property->id) + sizeof(property->manu_access) + property->val->len;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, 1 + length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_STATUS);
+    if (property == NULL) {
+        net_buf_simple_add_le16(msg, property_id);
+    } else {
+        net_buf_simple_add_le16(msg, property->id);
+        net_buf_simple_add_u8(msg, property->manu_access);
+        net_buf_simple_add_mem(msg, property->val->data, property->val->len);
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void gen_manu_prop_get(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_manu_prop_srv *srv = model->user_data;
+
+    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_get_msg_t get = {0};
+        const u8_t *param = NULL;
+        size_t len = 0;
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET) {
+            get.manu_property_get.id = net_buf_simple_pull_le16(buf);
+            param = (const u8_t *)&get;
+            len = sizeof(get);
+        }
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, param, len);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET: {
+        struct net_buf_simple *msg = NULL;
+        u8_t i;
+        msg = bt_mesh_alloc_buf(1 + srv->property_count * 2 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+        bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_STATUS);
+        for (i = 0U; i < srv->property_count; i++) {
+            net_buf_simple_add_le16(msg, srv->properties[i].id);
+        }
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+        return;
+    }
+    case BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET: {
+        u16_t property_id = net_buf_simple_pull_le16(buf);
+        send_gen_manu_prop_status(model, ctx, property_id, false);
+        return;
+    }
+    default:
+        BT_WARN("%s, Unknown Generic Manufacturer Property Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+}
+
+static void gen_manu_prop_set(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_manu_prop_srv *srv = model->user_data;
+    struct bt_mesh_generic_property *property = NULL;
+    u16_t property_id;
+    u8_t access;
+
+    if (srv == NULL || srv->property_count == 0U || srv->properties == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    property_id = net_buf_simple_pull_le16(buf);
+    access = net_buf_simple_pull_u8(buf);
+    if (access > MANU_ACCESS_READ) {
+        BT_ERR("%s, Invalid Manufacturer Access 0x%02x", __func__, access);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_set_msg_t set = {
+            .manu_property_set.id = property_id,
+            .manu_property_set.access = access,
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    property = gen_get_manu_property(model, property_id);
+    if (property == NULL) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET) {
+            send_gen_manu_prop_status(model, ctx, property_id, false);
+        }
+        send_gen_manu_prop_status(model, ctx, property_id, true);
+        return;
+    }
+
+    property->manu_access = access;
+
+    bt_mesh_gen_server_state_change_t change = {
+        .gen_manu_prop_set.id = property_id,
+        .gen_manu_prop_set.access = property->manu_access,
+    };
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET) {
+        send_gen_manu_prop_status(model, ctx, property_id, false);
+    }
+    send_gen_manu_prop_status(model, ctx, property_id, true);
+
+    return;
+}
+
+/* Generic Client Property Server message handlers */
+static int search_prop_id_index(const u16_t *array, u8_t array_idx, u16_t id)
+{
+    static const u16_t *start = NULL;
+    u8_t index;
+    u16_t temp;
+
+    if (start == NULL) {
+        start = array;
+    }
+
+    if (array_idx == 0U) {
+        if (*array >= id) {
+            return array - start;
+        } else {
+            return -1;
+        }
+    }
+
+    index = array_idx / 2;
+    temp = array[index];
+
+    if (temp == id) {
+        return array + index - start;
+    } else if (temp > id) {
+        return search_prop_id_index(array, index, id);
+    } else {
+        return search_prop_id_index(array + index + 1, array_idx - 1 - index, id);
+    }
+}
+
+static void gen_client_prop_get(struct bt_mesh_model *model,
+                                struct bt_mesh_msg_ctx *ctx,
+                                struct net_buf_simple *buf)
+{
+    struct bt_mesh_gen_client_prop_srv *srv = model->user_data;
+    struct net_buf_simple *sdu = NULL;
+    u16_t total_len = 5;
+    u16_t property_id;
+    int i, index;
+
+    if (srv == NULL || srv->id_count == 0U || srv->property_ids == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_gen_server_recv_get_msg_t get = {
+            .client_properties_get.id = net_buf_simple_pull_le16(buf),
+        };
+        bt_mesh_generic_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_GENERIC_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+        return;
+    }
+
+    /* The sequence shall be in an ascending order of Property ID values and shall
+     * start with a smallest Property ID that is greater than or equal to the value
+     * of the Generic Client Property field of the Generic Client Properities Get
+     * message that it is responding to.
+     */
+
+    property_id = net_buf_simple_pull_le16(buf);
+    index = search_prop_id_index(srv->property_ids, srv->id_count - 1, property_id);
+    if (index < 0) {
+        NET_BUF_SIMPLE_DEFINE(msg, 1 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        bt_mesh_model_msg_init(&msg, BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS);
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL));
+        return;
+    }
+
+    sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN));
+    if (sdu == NULL) {
+        BT_ERR("%s, Failed to allocate memory", __func__);
+        return;
+    }
+
+    bt_mesh_model_msg_init(sdu, BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_STATUS);
+    for (i = index; i < srv->id_count; i++) {
+        total_len += sizeof(u16_t);
+        if (total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) {
+            /* Add this in case the message is too long */
+            break;
+        }
+        net_buf_simple_add_le16(sdu, srv->property_ids[i]);
+    }
+
+    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, sdu, NULL, NULL));
+    bt_mesh_free_buf(sdu);
+    return;
+}
+
+/* message handlers (End) */
+
+/* Mapping of message handlers for Generic OnOff Server (0x1000) */
+const struct bt_mesh_model_op gen_onoff_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_ONOFF_GET,       0, gen_onoff_get },
+    { BLE_MESH_MODEL_OP_GEN_ONOFF_SET,       2, gen_onoff_set },
+    { BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Levl Server (0x1002) */
+const struct bt_mesh_model_op gen_level_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_LEVEL_GET,       0, gen_level_get },
+    { BLE_MESH_MODEL_OP_GEN_LEVEL_SET,       3, gen_level_set },
+    { BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK, 3, gen_level_set },
+    { BLE_MESH_MODEL_OP_GEN_DELTA_SET,       5, gen_delta_set },
+    { BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK, 5, gen_delta_set },
+    { BLE_MESH_MODEL_OP_GEN_MOVE_SET,        3, gen_move_set  },
+    { BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK,  3, gen_move_set  },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Default TT Server (0x1004) */
+const struct bt_mesh_model_op gen_def_trans_time_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_GET,       0, gen_def_trans_time_get },
+    { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET,       1, gen_def_trans_time_set },
+    { BLE_MESH_MODEL_OP_GEN_DEF_TRANS_TIME_SET_UNACK, 1, gen_def_trans_time_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Power OnOff Server (0x1006) */
+const struct bt_mesh_model_op gen_power_onoff_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_GET, 0, gen_onpowerup_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Power OnOff Setup Server (0x1007) */
+const struct bt_mesh_model_op gen_power_onoff_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET,       1, gen_onpowerup_set },
+    { BLE_MESH_MODEL_OP_GEN_ONPOWERUP_SET_UNACK, 1, gen_onpowerup_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Power Level Server (0x1009) */
+const struct bt_mesh_model_op gen_power_level_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_GET,       0, gen_power_level_get },
+    { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET,       3, gen_power_level_set },
+    { BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_SET_UNACK, 3, gen_power_level_set },
+    { BLE_MESH_MODEL_OP_GEN_POWER_LAST_GET,        0, gen_power_level_get },
+    { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_GET,     0, gen_power_level_get },
+    { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_GET,       0, gen_power_level_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Power Level Setup Server (0x100A) */
+const struct bt_mesh_model_op gen_power_level_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET,       2, gen_power_default_set },
+    { BLE_MESH_MODEL_OP_GEN_POWER_DEFAULT_SET_UNACK, 2, gen_power_default_set },
+    { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET,         4, gen_power_range_set   },
+    { BLE_MESH_MODEL_OP_GEN_POWER_RANGE_SET_UNACK,   4, gen_power_range_set   },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Battery Server (0x100C) */
+const struct bt_mesh_model_op gen_battery_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_BATTERY_GET, 0, gen_battery_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Location Server (0x100E) */
+const struct bt_mesh_model_op gen_location_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_GET, 0, gen_location_get },
+    { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_GET,  0, gen_location_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Location Setup Server (0x100F) */
+const struct bt_mesh_model_op gen_location_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET,       10, gen_location_set },
+    { BLE_MESH_MODEL_OP_GEN_LOC_GLOBAL_SET_UNACK, 10, gen_location_set },
+    { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET,         9, gen_location_set },
+    { BLE_MESH_MODEL_OP_GEN_LOC_LOCAL_SET_UNACK,   9, gen_location_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic User Property Server (0x1013) */
+const struct bt_mesh_model_op gen_user_prop_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_USER_PROPERTIES_GET,     0, gen_user_prop_get },
+    { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_GET,       2, gen_user_prop_get },
+    { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET,       3, gen_user_prop_set },
+    { BLE_MESH_MODEL_OP_GEN_USER_PROPERTY_SET_UNACK, 3, gen_user_prop_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Admin Property Server (0x1011) */
+const struct bt_mesh_model_op gen_admin_prop_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTIES_GET,     0, gen_admin_prop_get },
+    { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_GET,       2, gen_admin_prop_get },
+    { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET,       4, gen_admin_prop_set },
+    { BLE_MESH_MODEL_OP_GEN_ADMIN_PROPERTY_SET_UNACK, 4, gen_admin_prop_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Manufacturer Property Server (0x1012) */
+const struct bt_mesh_model_op gen_manu_prop_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTIES_GET,     0, gen_manu_prop_get },
+    { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_GET,       2, gen_manu_prop_get },
+    { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET,       3, gen_manu_prop_set },
+    { BLE_MESH_MODEL_OP_GEN_MANU_PROPERTY_SET_UNACK, 3, gen_manu_prop_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Generic Client Property Server (0x1014) */
+const struct bt_mesh_model_op gen_client_prop_srv_op[] = {
+    { BLE_MESH_MODEL_OP_GEN_CLIENT_PROPERTIES_GET, 2, gen_client_prop_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+static inline int property_id_compare(const void *p1, const void *p2)
+{
+    if (*(u16_t *)p1 < *(u16_t *)p2) return -1;
+    if (*(u16_t *)p1 > *(u16_t *)p2) return 1;
+    return 0;
+}
+
+static int generic_server_init(struct bt_mesh_model *model)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, No Generic Server context provided, model_id 0x%04x", __func__, model->id);
+        return -EINVAL;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_GEN_ONOFF_SRV: {
+        struct bt_mesh_gen_onoff_srv *srv = model->user_data;
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, generic_onoff_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_LEVEL_SRV: {
+        struct bt_mesh_gen_level_srv *srv = model->user_data;
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, generic_level_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV: {
+        struct bt_mesh_gen_def_trans_time_srv *srv = model->user_data;
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV: {
+        struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Generic OnPowerUp State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV: {
+        struct bt_mesh_gen_power_onoff_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Generic OnPowerUp State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV: {
+        struct bt_mesh_gen_power_level_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Generic Power Level State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, generic_power_level_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV: {
+        struct bt_mesh_gen_power_level_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Generic Power Level State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_BATTERY_SRV: {
+        struct bt_mesh_gen_battery_srv *srv = model->user_data;
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_LOCATION_SRV: {
+        struct bt_mesh_gen_location_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Generic Location State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV: {
+        struct bt_mesh_gen_location_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Generic Location State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_USER_PROP_SRV: {
+        struct bt_mesh_gen_user_prop_srv *srv = model->user_data;
+        if (srv->property_count == 0U || srv->properties == NULL) {
+            BT_ERR("%s, NULL Generic User Property State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV: {
+        struct bt_mesh_gen_admin_prop_srv *srv = model->user_data;
+        if (srv->property_count == 0U || srv->properties == NULL) {
+            BT_ERR("%s, NULL Generic Admin Property State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV: {
+        struct bt_mesh_gen_manu_prop_srv *srv = model->user_data;
+        if (srv->property_count == 0U || srv->properties == NULL) {
+            BT_ERR("%s, NULL Generic Manufacturer Property State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV: {
+        struct bt_mesh_gen_client_prop_srv *srv = model->user_data;
+        if (srv->id_count == 0U || srv->property_ids == NULL) {
+            BT_ERR("%s, NULL Generic Client Property State", __func__);
+            return -EINVAL;
+        }
+        /* Quick sort the Client Property IDs in ascending order */
+        qsort(srv->property_ids, srv->id_count, sizeof(u16_t), property_id_compare);
+        srv->model = model;
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown Generic Server Model, model_id 0x%04x", __func__, model->id);
+        return -EINVAL;
+    }
+
+    bt_mesh_generic_server_mutex_new();
+
+    return 0;
+}
+
+int bt_mesh_gen_onoff_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic OnOff Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_level_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Level Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_def_trans_time_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Default Trans Time Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_power_onoff_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Power OnOff Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /* When this model is present on an element, the corresponding Generic
+     * Power OnOff Setup Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Generic Power OnOff Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_power_onoff_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_power_level_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Power Level Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /* When this model is present on an Element, the corresponding Generic
+     * Power Level Setup Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Generic Power Level Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_power_level_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_battery_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Battery Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_location_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Location Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_location_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    /* When this model is present on an Element, the corresponding Generic
+     * Location Setup Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_GEN_LOCATION_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Generic Location Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_user_prop_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic User Property has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_admin_prop_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Admin Property has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_manu_prop_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Manufacturer Property has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}
+
+int bt_mesh_gen_client_prop_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Generic Client Property has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return generic_server_init(model);
+}

+ 1045 - 0
components/bt/esp_ble_mesh/mesh_models/server/include/device_property.h

@@ -0,0 +1,1045 @@
+// Copyright 2017-2019 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.
+
+#ifndef _DEVICE_PROPERTY_H_
+#define _DEVICE_PROPERTY_H_
+
+#include "mesh_types.h"
+
+/**
+ * BLE Mesh Device Properties.
+ *
+ * Name                                                        Type                                                                                ID          Characteristic                               Type Size
+ * Average Ambient Temperature In A Period Of Day              org.bluetooth.property.average_ambient_temperature_in_a_period_of_day               0x0001      Temperature 8 In A Period Of Day             3
+ * Average Input Current                                       org.bluetooth.property.average_input_current                                        0x0002      Average Current                              3
+ * Average Input Voltage                                       org.bluetooth.property.average_input_voltage                                        0x0003      Average Voltage                              3
+ * Average Output Current                                      org.bluetooth.property.average_output_current                                       0x0004      Average Current                              3
+ * Average Output Voltage                                      org.bluetooth.property.average_output_voltage                                       0x0005      Average Voltage                              3
+ * Center Beam Intensity At Full Power                         org.bluetooth.property.center_beam_intensity_at_full_power                          0x0006      Luminous Intensity                           2
+ * Chromaticity Tolerance                                      org.bluetooth.property.chromaticity_tolerance                                       0x0007      Chromaticity Tolerance                       1
+ * Color Rendering Index R9                                    org.bluetooth.property.color_rendering_index_r9                                     0x0008      Cie 13.3-1995 Color Rendering Index          1
+ * Color Rendering Index Ra                                    org.bluetooth.property.color_rendering_index_ra                                     0x0009      Cie 13.3-1995 Color Rendering Index          1
+ * Device Appearance                                           org.bluetooth.property.device_appearance                                            0x000A      Gap.Appearance                               2
+ * Device Country Of Origin                                    org.bluetooth.property.device_country_of_origin                                     0x000B      Country Code                                 2
+ * Device Date Of Manufacture                                  org.bluetooth.property.device_date_of_manufacture                                   0x000C      Date Utc                                     4
+ * Device Energy Use Since Turn On                             org.bluetooth.property.device_energy_use_since_turn_on                              0x000D      Energy                                       4
+ * Device Firmware Revision                                    org.bluetooth.property.device_firmware_revision                                     0x000E      Fixed String 8                               8
+ * Device Global Trade Item Number                             org.bluetooth.property.device_global_trade_item_number                              0x000F      Global Trade Item Number                     8
+ * Device Hardware Revision                                    org.bluetooth.property.device_hardware_revision                                     0x0010      Fixed String 16                              16
+ * Device Manufacturer Name                                    org.bluetooth.property.device_manufacturer_name                                     0x0011      Fixed String 36                              36
+ * Device Model Number                                         org.bluetooth.property.device_model_number                                          0x0012      Fixed String 24                              24
+ * Device Operating Temperature Range Specification            org.bluetooth.property.device_operating_temperature_range_specification             0x0013      Temperature Range                            4
+ * Device Operating Temperature Statistical Values             org.bluetooth.property.device_operating_temperature_statistical_values              0x0014      Temperature Statistics                       9
+ * Device Over Temperature Event Statistics                    org.bluetooth.property.device_over_temperature_event_statistics                     0x0015      Event Statistics                             6
+ * Device Power Range Specification                            org.bluetooth.property.device_power_range_specification                             0x0016      Power Specification                          12
+ * Device Runtime Since Turn On                                org.bluetooth.property.device_runtime_since_turn_on                                 0x0017      Time Hour 24                                 4
+ * Device Runtime Warranty                                     org.bluetooth.property.device_runtime_warranty                                      0x0018      Time Hour 24                                 4
+ * Device Serial Number                                        org.bluetooth.property.device_serial_number                                         0x0019      Fixed String 16                              16
+ * Device Software Revision                                    org.bluetooth.property.device_software_revision                                     0x001A      Fixed String 8                               8
+ * Device Under Temperature Event Statistics                   org.bluetooth.property.device_under_temperature_event_statistics                    0x001B      Event Statistics                             6
+ * Indoor Ambient Temperature Statistical Values               org.bluetooth.property.indoor_ambient_temperature_statistical_values                0x001C      Temperature 8 Statistics                     5
+ * Initial CIE 1931 Chromaticity Coordinates                   org.bluetooth.property.initial_cie_1931_chromaticity_coordinates                    0x001D      Chromaticity Coordinates                     4
+ * Initial Correlated Color Temperature                        org.bluetooth.property.initial_correlated_color_temperature                         0x001E      Correlated Color Temperature                 2
+ * Initial Luminous Flux                                       org.bluetooth.property.initial_luminous_flux                                        0x001F      Luminous Flux                                2
+ * Initial Planckian Distance                                  org.bluetooth.property.initial_planckian_distance                                   0x0020      Chromatic Distance From Planckian            2
+ * Input Current Range Specification                           org.bluetooth.property.input_current_range_specification                            0x0021      Electric Current Specification               6
+ * Input Current Statistics                                    org.bluetooth.property.input_current_statistics                                     0x0022      Electric Current Statistics                  9
+ * Input Over Current Event Statistics                         org.bluetooth.property.input_over_current_event_statistics                          0x0023      Event Statistics                             6
+ * Input Over Ripple Voltage Event Statistics                  org.bluetooth.property.input_over_ripple_voltage_event_statistics                   0x0024      Event Statistics                             6
+ * Input Over Voltage Event Statistics                         org.bluetooth.property.input_over_voltage_event_statistics                          0x0025      Event Statistics                             6
+ * Input Under Current Event Statistics                        org.bluetooth.property.input_under_current_event_statistics                         0x0026      Event Statistics                             6
+ * Input Under Voltage Event Statistics                        org.bluetooth.property.input_under_voltage_event_statistics                         0x0027      Event Statistics                             6
+ * Input Voltage Range Specification                           org.bluetooth.property.input_voltage_range_specification                            0x0028      Voltage Specification                        6
+ * Input Voltage Ripple Specification                          org.bluetooth.property.input_voltage_ripple_specification                           0x0029      Percentage 8                                 1
+ * Input Voltage Statistics                                    org.bluetooth.property.input_voltage_statistics                                     0x002A      Voltage Statistics                           9
+ * Light Control Ambient LuxLevel On                           org.bluetooth.property.light_control_ambient_luxlevel_on                            0x002B      Illuminance                                  4
+ * Light Control Ambient LuxLevel Prolong                      org.bluetooth.property.light_control_ambient_luxlevel_prolong                       0x002C      Illuminance                                  4
+ * Light Control Ambient LuxLevel Standby                      org.bluetooth.property.light_control_ambient_luxlevel_standby                       0x002D      Illuminance                                  4
+ * Light Control Lightness On                                  org.bluetooth.property.light_control_lightness_on                                   0x002E      Perceived Lightness                          2
+ * Light Control Lightness Prolong                             org.bluetooth.property.light_control_lightness_prolong                              0x002F      Perceived Lightness                          2
+ * Light Control Lightness Standby                             org.bluetooth.property.light_control_lightness_standby                              0x0030      Perceived Lightness                          2
+ * Light Control Regulator Accuracy                            org.bluetooth.property.light_control_regulator_accuracy                             0x0031      Percentage 8                                 1
+ * Light Control Regulator Kid                                 org.bluetooth.property.light_control_regulator_kid                                  0x0032      Coefficient                                  4
+ * Light Control Regulator Kiu                                 org.bluetooth.property.light_control_regulator_kiu                                  0x0033      Coefficient                                  4
+ * Light Control Regulator Kpd                                 org.bluetooth.property.light_control_regulator_kpd                                  0x0034      Coefficient                                  4
+ * Light Control Regulator Kpu                                 org.bluetooth.property.light_control_regulator_kpu                                  0x0035      Coefficient                                  4
+ * Light Control Time Fade                                     org.bluetooth.property.light_control_time_fade                                      0x0036      Time Millisecond 24                          4
+ * Light Control Time Fade On                                  org.bluetooth.property.light_control_time_fade_on                                   0x0037      Time Millisecond 24                          4
+ * Light Control Time Fade Standby Auto                        org.bluetooth.property.light_control_time_fade_standby_auto                         0x0038      Time Millisecond 24                          4
+ * Light Control Time Fade Standby Manual                      org.bluetooth.property.light_control_time_fade_standby_manual                       0x0039      Time Millisecond 24                          4
+ * Light Control Time Occupancy Delay                          org.bluetooth.property.light_control_time_occupancy_delay                           0x003A      Time Millisecond 24                          4
+ * Light Control Time Prolong                                  org.bluetooth.property.light_control_time_prolong                                   0x003B      Time Millisecond 24                          4
+ * Light Control Time Run On                                   org.bluetooth.property.light_control_time_run_on                                    0x003C      Time Millisecond 24                          4
+ * Lumen Maintenance Factor                                    org.bluetooth.property.lumen_maintenance_factor                                     0x003D      Percentage 8                                 1
+ * Luminous Efficacy                                           org.bluetooth.property.luminous_efficacy                                            0x003E      Luminous Efficacy                            2
+ * Luminous Energy Since Turn On                               org.bluetooth.property.luminous_energy_since_turn_on                                0x003F      Luminous Energy                              4
+ * Luminous Exposure                                           org.bluetooth.property.luminous_exposure                                            0x0040      Luminous Exposure                            4
+ * Luminous Flux Range                                         org.bluetooth.property.luminous_flux_range                                          0x0041      Luminous Flux Range                          4
+ * Motion Sensed                                               org.bluetooth.property.motion_sensed                                                0x0042      Percentage 8                                 1
+ * Motion Threshold                                            org.bluetooth.property.motion_threshold                                             0x0043      Percentage 8                                 1
+ * Open Circuit Event Statistics                               org.bluetooth.property.open_circuit_event_statistics                                0x0044      Event Statistics                             6
+ * Outdoor Statistical Values                                  org.bluetooth.property.outdoor_statistical_values                                   0x0045      Temperature 8 Statistics                     5
+ * Output Current Range                                        org.bluetooth.property.output_current_range                                         0x0046      Electric Current Range                       4
+ * Output Current Statistics                                   org.bluetooth.property.output_current_statistics                                    0x0047      Electric Current Statistics                  9
+ * Output Ripple Voltage Specification                         org.bluetooth.property.output_ripple_voltage_specification                          0x0048      Percentage 8                                 1
+ * Output Voltage Range                                        org.bluetooth.property.output_voltage_range                                         0x0049      Voltage Specification                        6
+ * Output Voltage Statistics                                   org.bluetooth.property.output_voltage_statistics                                    0x004A      Voltage Statistics                           9
+ * Over Output Ripple Voltage Event Statistics                 org.bluetooth.property.over_output_ripple_voltage_event_statistics                  0x004B      Event Statistics                             6
+ * People Count                                                org.bluetooth.property.people_count                                                 0x004C      Count 16                                     2
+ * Presence Detected                                           org.bluetooth.property.presence_detected                                            0x004D      Boolean                                      1
+ * Present Ambient Light Level                                 org.bluetooth.property.present_ambient_light_level                                  0x004E      Illuminance                                  4
+ * Present Ambient Temperature                                 org.bluetooth.property.present_ambient_temperature                                  0x004F      Temperature 8                                1
+ * Present CIE 1931 Chromaticity Coordinates                   org.bluetooth.property.present_cie_1931_chromaticity                                0x0050      Chromaticity Coordinates                     4
+ * Present Correlated Color Temperature                        org.bluetooth.property.present_correlated_color_temperature                         0x0051      Correlated Color Temperature                 2
+ * Present Device Input Power                                  org.bluetooth.property.present_device_input_power                                   0x0052      Power                                        4
+ * Present Device Operating Efficiency                         org.bluetooth.property.present_device_operating_efficiency                          0x0053      Percentage 8                                 1
+ * Present Device Operating Temperature                        org.bluetooth.property.present_device_operating_temperature                         0x0054      Temperature                                  2
+ * Present Illuminance                                         org.bluetooth.property.present_illuminance                                          0x0055      Illuminance                                  4
+ * Present Indoor Ambient Temperature                          org.bluetooth.property.present_indoor_ambient_temperature                           0x0056      Temperature 8                                1
+ * Present Input Current                                       org.bluetooth.property.present_input_current                                        0x0057      Electric Current                             2
+ * Present Input Ripple Voltage                                org.bluetooth.property.present_input_ripple_voltage                                 0x0058      Percentage 8                                 1
+ * Present Input Voltage                                       org.bluetooth.property.present_input_voltage                                        0x0059      Voltage                                      2
+ * Present Luminous Flux                                       org.bluetooth.property.present_luminous_flux                                        0x005A      Luminous Flux                                2
+ * Present Outdoor Ambient Temperature                         org.bluetooth.property.present_outdoor_ambient_temperature                          0x005B      Temperature 8                                1
+ * Present Output Current                                      org.bluetooth.property.present_output_current                                       0x005C      Electric Current                             2
+ * Present Output Voltage                                      org.bluetooth.property.present_output_voltage                                       0x005D      Voltage                                      2
+ * Present Planckian Distance                                  org.bluetooth.property.present_planckian_distance                                   0x005E      Chromatic Distance From Planckian            2
+ * Present Relative Output Ripple Voltage                      org.bluetooth.property.present_relative_output_ripple_voltage                       0x005F      Percentage 8                                 1
+ * Relative Device Energy Use In A Period Of Day               org.bluetooth.property.relative_device_energy_use_in_a_period_of_day                0x0060      Energy In A Period Of Day                    6
+ * Relative Device Runtime In A Generic Level Range            org.bluetooth.property.relative_device_runtime_in_a_generic_level_range             0x0061      Relative Runtime In A Generic Level Range    5
+ * Relative Exposure Time In An Illuminance Range              org.bluetooth.property.relative_exposure_time_in_an_illuminance_range               0x0062      Relative Value In An Illuminance Range       9
+ * Relative Runtime In A Correlated Color Temperature Range    org.bluetooth.property.relative_runtime_in_a_correlated_color_temperature_range     0x0063      Luminous Energy                              4
+ * Relative Runtime In A Device Operating Temperature Range    org.bluetooth.property.relative_runtime_in_a_device_operating_temperature_range     0x0064      Relative Value In A Temperature Range        5
+ * Relative Runtime In An Input Current Range                  org.bluetooth.property.relative_runtime_in_an_input_current_range                   0x0065      Relative Runtime In A Current Range          5
+ * Relative Runtime In An Input Voltage Range                  org.bluetooth.property.relative_runtime_in_an_input_voltage_range                   0x0066      Relative Value In A Voltage Range            5
+ * Short Circuit Event Statistics                              org.bluetooth.property.short_circuit_event_statistics                               0x0067      Event Statistics                             6
+ * Time Since Motion Sensed                                    org.bluetooth.property.time_since_motion_sensed                                     0x0068      Time Second 16                               2
+ * Time Since Presence Detected                                org.bluetooth.property.time_since_presence_detected                                 0x0069      Time Second 16                               2
+ * Total Device Energy Use                                     org.bluetooth.property.total_device_energy_use                                      0x006A      Energy                                       4
+ * Total Device Off On Cycles                                  org.bluetooth.property.total_device_off_on_cycles                                   0x006B      Count 24                                     4
+ * Total Device Power On Cycles                                org.bluetooth.property.total_device_power_on_cycles                                 0x006C      Count 24                                     4
+ * Total Device Power On Time                                  org.bluetooth.property.total_device_power_on_time                                   0x006D      Time Hour 24                                 4
+ * Total Device Runtime                                        org.bluetooth.property.total_device_runtime                                         0x006E      Time Hour 24                                 4
+ * Total Light Exposure Time                                   org.bluetooth.property.total_light_exposure_time                                    0x006F      Time Hour 24                                 4
+ * Total Luminous Energy                                       org.bluetooth.property.total_luminous_energy                                        0x0070      Luminous Energy                              4
+ */
+
+/**
+ * Characteristics referenced by BLE Mesh Device Properties.
+ *
+ * Name                                        Uniform Type Identifier                                                     Assigned Number     Specification Level
+ * Average Current                             org.bluetooth.characteristic.average_current                                2AE0                Adopted
+ * Average Voltage                             org.bluetooth.characteristic.average_voltage                                2AE1                Adopted
+ * Boolean                                     org.bluetooth.characteristic.boolean                                        2AE2                Adopted
+ * Chromatic Distance From Planckian           org.bluetooth.characteristic.chromatic_distance_from_planckian              2AE3                Adopted
+ * Chromaticity Coordinate                     org.bluetooth.characteristic.chromaticity_coordinate                        2B1C                Adopted
+ * Chromaticity Coordinates                    org.bluetooth.characteristic.chromaticity_coordinates                       2AE4                Adopted
+ * Chromaticity In CCT And Duv Values          org.bluetooth.characteristic.chromaticity_in_cct_and_duv_values             2AE5                Adopted
+ * Chromaticity Tolerance                      org.bluetooth.characteristic.chromaticity_tolerance                         2AE6                Adopted
+ * CIE 13.3-1995 Color Rendering Index         org.bluetooth.characteristic.cie_13.3-1995_color_rendering_index            2AE7                Adopted
+ * Coefficient                                 org.bluetooth.characteristic.coefficient                                    2AE8                Adopted
+ * Correlated Color Temperature                org.bluetooth.characteristic.correlated_color_temperature                   2AE9                Adopted
+ * Count 16                                    org.bluetooth.characteristic.count_16                                       2AEA                Adopted
+ * Count 24                                    org.bluetooth.characteristic.count_24                                       2AEB                Adopted
+ * Country Code                                org.bluetooth.characteristic.country_code                                   2AEC                Adopted
+ * Date UTC                                    org.bluetooth.characteristic.date_utc                                       2AED                Adopted
+ * Electric Current                            org.bluetooth.characteristic.electric_current                               2AEE                Adopted
+ * Electric Current Range                      org.bluetooth.characteristic.electric_current_range                         2AEF                Adopted
+ * Electric Current Specification              org.bluetooth.characteristic.electric_current_specification                 2AF0                Adopted
+ * Electric Current Statistics                 org.bluetooth.characteristic.electric_current_statistics                    2AF1                Adopted
+ * Energy                                      org.bluetooth.characteristic.energy                                         2AF2                Adopted
+ * Energy In A Period Of Day                   org.bluetooth.characteristic.energy_in_a_period_of_day                      2AF3                Adopted
+ * Event Statistics                            org.bluetooth.characteristic.event_statistics                               2AF4                Adopted
+ * Fixed String 16                             org.bluetooth.characteristic.fixed_string_16                                2AF5                Adopted
+ * Fixed String 24                             org.bluetooth.characteristic.fixed_string_24                                2AF6                Adopted
+ * Fixed String 36                             org.bluetooth.characteristic.fixed_string_36                                2AF7                Adopted
+ * Fixed String 8                              org.bluetooth.characteristic.fixed_string_8                                 2AF8                Adopted
+ * Generic Level                               org.bluetooth.characteristic.generic_level                                  2AF9                Adopted
+ * Global Trade Item Number                    org.bluetooth.characteristic.global_trade_item_number                       2AFA                Adopted
+ * Illuminance                                 org.bluetooth.characteristic.illuminance                                    2AFB                Adopted
+ * Luminous Efficacy                           org.bluetooth.characteristic.luminous_efficacy                              2AFC                Adopted
+ * Luminous Energy                             org.bluetooth.characteristic.luminous_energy                                2AFD                Adopted
+ * Luminous Exposure                           org.bluetooth.characteristic.luminous_exposure                              2AFE                Adopted
+ * Luminous Flux                               org.bluetooth.characteristic.luminous_flux                                  2AFF                Adopted
+ * Luminous Flux Range                         org.bluetooth.characteristic.luminous_flux_range                            2B00                Adopted
+ * Luminous Intensity                          org.bluetooth.characteristic.luminous_intensity                             2B01                Adopted
+ * Mass Flow                                   org.bluetooth.characteristic.mass_flow                                      2B02                Adopted
+ * Mesh Provisioning Data In                   org.bluetooth.characteristic.mesh_provisioning_data_in                      2ADB                Adopted
+ * Mesh Provisioning Data Out                  org.bluetooth.characteristic.mesh_provisioning_data_out                     2ADC                Adopted
+ * Mesh Proxy Data In                          org.bluetooth.characteristic.mesh_proxy_data_in                             2ADD                Adopted
+ * Mesh Proxy Data Out                         org.bluetooth.characteristic.mesh_proxy_data_out                            2ADE                Adopted
+ * Perceived Lightness                         org.bluetooth.characteristic.perceived_lightness                            2B03                Adopted
+ * Percentage 8                                org.bluetooth.characteristic.percentage_8                                   2B04                Adopted
+ * Power                                       org.bluetooth.characteristic.power                                          2B05                Adopted
+ * Power Specification                         org.bluetooth.characteristic.power_specification                            2B06                Adopted
+ * Relative Runtime In A Current Range         org.bluetooth.characteristic.relative_runtime_in_a_current_range            2B07                Adopted
+ * Relative Runtime In A Generic Level Range   org.bluetooth.characteristic.relative_runtime_in_a_generic_level_range      2B08                Adopted
+ * Relative Value In A Period of Day           org.bluetooth.characteristic.relative_value_in_a_period_of_day              2B0B                Adopted
+ * Relative Value In A Temperature Range       org.bluetooth.characteristic.relative_value_in_a_temperature_range          2B0C                Adopted
+ * Relative Value In A Voltage Range           org.bluetooth.characteristic.relative_value_in_a_voltage_range              2B09                Adopted
+ * Relative Value In An Illuminance Range      org.bluetooth.characteristic.relative_value_in_an_illuminance_range         2B0A                Adopted
+ * Temperature 8                               org.bluetooth.characteristic.temperature_8                                  2B0D                Adopted
+ * Temperature 8 In A Period Of Day            org.bluetooth.characteristic.temperature_8_in_a_period_of_day               2B0E                Adopted
+ * Temperature 8 Statistics                    org.bluetooth.characteristic.temperature_8_statistics                       2B0F                Adopted
+ * Temperature Range                           org.bluetooth.characteristic.temperature_range                              2B10                Adopted
+ * Temperature Statistics                      org.bluetooth.characteristic.temperature_statistics                         2B11                Adopted
+ * Time Decihour 8                             org.bluetooth.characteristic.time_decihour_8                                2B12                Adopted
+ * Time Exponential 8                          org.bluetooth.characteristic.time_exponential_8                             2B13                Adopted
+ * Time Hour 24                                org.bluetooth.characteristic.time_hour_24                                   2B14                Adopted
+ * Time Millisecond 24                         org.bluetooth.characteristic.time_millisecond_24                            2B15                Adopted
+ * Time Second 16                              org.bluetooth.characteristic.time_second_16                                 2B16                Adopted
+ * Time Second 8                               org.bluetooth.characteristic.time_second_8                                  2B17                Adopted
+ * Voltage                                     org.bluetooth.characteristic.voltage                                        2B18                Adopted
+ * Voltage Specification                       org.bluetooth.characteristic.voltage_specification                          2B19                Adopted
+ * Voltage Statistics                          org.bluetooth.characteristic.voltage_statistics                             2B1A                Adopted
+ * Volume Flow                                 org.bluetooth.characteristic.volume_flow                                    2B1B                Adopted
+ */
+
+/**
+ * @brief BLE Mesh Device Property IDs
+ */
+#define BLE_MESH_AVERAGE_AMBIENT_TEMPERATURE_IN_A_PERIOD_OF_DAY             0x0001
+#define BLE_MESH_AVERAGE_INPUT_CURRENT                                      0x0002
+#define BLE_MESH_AVERAGE_INPUT_VOLTAGE                                      0x0003
+#define BLE_MESH_AVERAGE_OUTPUT_CURRENT                                     0x0004
+#define BLE_MESH_AVERAGE_OUTPUT_VOLTAGE                                     0x0005
+#define BLE_MESH_CENTER_BEAM_INTENSITY_AT_FULL_POWER                        0x0006
+#define BLE_MESH_CHROMATICITY_TOLERANCE                                     0x0007
+#define BLE_MESH_COLOR_RENDERING_INDEX_R9                                   0x0008
+#define BLE_MESH_COLOR_RENDERING_INDEX_RA                                   0x0009
+#define BLE_MESH_DEVICE_APPEARANCE                                          0x000A
+#define BLE_MESH_DEVICE_COUNTRY_OF_ORIGIN                                   0x000B
+#define BLE_MESH_DEVICE_DATE_OF_MANUFACTURE                                 0x000C
+#define BLE_MESH_DEVICE_ENERGY_USE_SINCE_TURN_ON                            0x000D
+#define BLE_MESH_DEVICE_FIRMWARE_REVISION                                   0x000E
+#define BLE_MESH_DEVICE_GLOBAL_TRADE_ITEM_NUMBER                            0x000F
+#define BLE_MESH_DEVICE_HARDWARE_REVISION                                   0x0010
+#define BLE_MESH_DEVICE_MANUFACTURER_NAME                                   0x0011
+#define BLE_MESH_DEVICE_MODEL_NUMBER                                        0x0012
+#define BLE_MESH_DEVICE_OPERATING_TEMPERATURE_RANGE_SPECIFICATION           0x0013
+#define BLE_MESH_DEVICE_OPERATING_TEMPERATURE_STATISTICAL_VALUES            0x0014
+#define BLE_MESH_DEVICE_OVER_TEMPERATURE_EVENT_STATISTICS                   0x0015
+#define BLE_MESH_DEVICE_POWER_RANGE_SPECIFICATION                           0x0016
+#define BLE_MESH_DEVICE_RUNTIME_SINCE_TURN_ON                               0x0017
+#define BLE_MESH_DEVICE_RUNTIME_WARRANTY                                    0x0018
+#define BLE_MESH_DEVICE_SERIAL_NUMBER                                       0x0019
+#define BLE_MESH_DEVICE_SOFTWARE_REVISION                                   0x001A
+#define BLE_MESH_DEVICE_UNDER_TEMPERATURE_EVENT_STATISTICS                  0x001B
+#define BLE_MESH_INDOOR_AMBIENT_TEMPERATURE_STATISTICAL_VALUES              0x001C
+#define BLE_MESH_INITIAL_CIE_1931_CHROMATICITY_COORDINATES                  0x001D
+#define BLE_MESH_INITIAL_CORRELATED_COLOR_TEMPERATURE                       0x001E
+#define BLE_MESH_INITIAL_LUMINOUS_FLUX                                      0x001F
+#define BLE_MESH_INITIAL_PLANCKIAN_DISTANCE                                 0x0020
+#define BLE_MESH_INPUT_CURRENT_RANGE_SPECIFICATION                          0x0021
+#define BLE_MESH_INPUT_CURRENT_STATISTICS                                   0x0022
+#define BLE_MESH_INPUT_OVER_CURRENT_EVENT_STATISTICS                        0x0023
+#define BLE_MESH_INPUT_OVER_RIPPLE_VOLTAGE_EVENT_STATISTICS                 0x0024
+#define BLE_MESH_INPUT_OVER_VOLTAGE_EVENT_STATISTICS                        0x0025
+#define BLE_MESH_INPUT_UNDER_CURRENT_EVENT_STATISTICS                       0x0026
+#define BLE_MESH_INPUT_UNDER_VOLTAGE_EVENT_STATISTICS                       0x0027
+#define BLE_MESH_INPUT_VOLTAGE_RANGE_SPECIFICATION                          0x0028
+#define BLE_MESH_INPUT_VOLTAGE_RIPPLE_SPECIFICATION                         0x0029
+#define BLE_MESH_INPUT_VOLTAGE_STATISTICS                                   0x002A
+#define BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_ON                          0x002B
+#define BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_PROLONG                     0x002C
+#define BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_STANDBY                     0x002D
+#define BLE_MESH_LIGHT_CONTROL_LIGHTNESS_ON                                 0x002E
+#define BLE_MESH_LIGHT_CONTROL_LIGHTNESS_PROLONG                            0x002F
+#define BLE_MESH_LIGHT_CONTROL_LIGHTNESS_STANDBY                            0x0030
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_ACCURACY                           0x0031
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_KID                                0x0032
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_KIU                                0x0033
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_KPD                                0x0034
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_KPU                                0x0035
+#define BLE_MESH_LIGHT_CONTROL_TIME_FADE                                    0x0036
+#define BLE_MESH_LIGHT_CONTROL_TIME_FADE_ON                                 0x0037
+#define BLE_MESH_LIGHT_CONTROL_TIME_FADE_STANDBY_AUTO                       0x0038
+#define BLE_MESH_LIGHT_CONTROL_TIME_FADE_STANDBY_MANUAL                     0x0039
+#define BLE_MESH_LIGHT_CONTROL_TIME_OCCUPANCY_DELAY                         0x003A
+#define BLE_MESH_LIGHT_CONTROL_TIME_PROLONG                                 0x003B
+#define BLE_MESH_LIGHT_CONTROL_TIME_RUN_ON                                  0x003C
+#define BLE_MESH_LUMEN_MAINTENANCE_FACTOR                                   0x003D
+#define BLE_MESH_LUMINOUS_EFFICACY                                          0x003E
+#define BLE_MESH_LUMINOUS_ENERGY_SINCE_TURN_ON                              0x003F
+#define BLE_MESH_LUMINOUS_EXPOSURE                                          0x0040
+#define BLE_MESH_LUMINOUS_FLUX_RANGE                                        0x0041
+#define BLE_MESH_MOTION_SENSED                                              0x0042
+#define BLE_MESH_MOTION_THRESHOLD                                           0x0043
+#define BLE_MESH_OPEN_CIRCUIT_EVENT_STATISTICS                              0x0044
+#define BLE_MESH_OUTDOOR_STATISTICAL_VALUES                                 0x0045
+#define BLE_MESH_OUTPUT_CURRENT_RANGE                                       0x0046
+#define BLE_MESH_OUTPUT_CURRENT_STATISTICS                                  0x0047
+#define BLE_MESH_OUTPUT_RIPPLE_VOLTAGE_SPECIFICATION                        0x0048
+#define BLE_MESH_OUTPUT_VOLTAGE_RANGE                                       0x0049
+#define BLE_MESH_OUTPUT_VOLTAGE_STATISTICS                                  0x004A
+#define BLE_MESH_OVER_OUTPUT_RIPPLE_VOLTAGE_EVENT_STATISTICS                0x004B
+#define BLE_MESH_PEOPLE_COUNT                                               0x004C
+#define BLE_MESH_PRESENCE_DETECTED                                          0x004D
+#define BLE_MESH_PRESENT_AMBIENT_LIGHT_LEVEL                                0x004E
+#define BLE_MESH_PRESENT_AMBIENT_TEMPERATURE                                0x004F
+#define BLE_MESH_PRESENT_CIE_1931_CHROMATICITY                              0x0050
+#define BLE_MESH_PRESENT_CORRELATED_COLOR_TEMPERATURE                       0x0051
+#define BLE_MESH_PRESENT_DEVICE_INPUT_POWER                                 0x0052
+#define BLE_MESH_PRESENT_DEVICE_OPERATING_EFFICIENCY                        0x0053
+#define BLE_MESH_PRESENT_DEVICE_OPERATING_TEMPERATURE                       0x0054
+#define BLE_MESH_PRESENT_ILLUMINANCE                                        0x0055
+#define BLE_MESH_PRESENT_INDOOR_AMBIENT_TEMPERATURE                         0x0056
+#define BLE_MESH_PRESENT_INPUT_CURRENT                                      0x0057
+#define BLE_MESH_PRESENT_INPUT_RIPPLE_VOLTAGE                               0x0058
+#define BLE_MESH_PRESENT_INPUT_VOLTAGE                                      0x0059
+#define BLE_MESH_PRESENT_LUMINOUS_FLUX                                      0x005A
+#define BLE_MESH_PRESENT_OUTDOOR_AMBIENT_TEMPERATURE                        0x005B
+#define BLE_MESH_PRESENT_OUTPUT_CURRENT                                     0x005C
+#define BLE_MESH_PRESENT_OUTPUT_VOLTAGE                                     0x005D
+#define BLE_MESH_PRESENT_PLANCKIAN_DISTANCE                                 0x005E
+#define BLE_MESH_PRESENT_RELATIVE_OUTPUT_RIPPLE_VOLTAGE                     0x005F
+#define BLE_MESH_RELATIVE_DEVICE_ENERGY_USE_IN_A_PERIOD_OF_DAY              0x0060
+#define BLE_MESH_RELATIVE_DEVICE_RUNTIME_IN_A_GENERIC_LEVEL_RANGE           0x0061
+#define BLE_MESH_RELATIVE_EXPOSURE_TIME_IN_AN_ILLUMINANCE_RANGE             0x0062
+#define BLE_MESH_RELATIVE_RUNTIME_IN_A_CORRELATED_COLOR_TEMPERATURE_RANGE   0x0063
+#define BLE_MESH_RELATIVE_RUNTIME_IN_A_DEVICE_OPERATING_TEMPERATURE_RANGE   0x0064
+#define BLE_MESH_RELATIVE_RUNTIME_IN_AN_INPUT_CURRENT_RANGE                 0x0065
+#define BLE_MESH_RELATIVE_RUNTIME_IN_AN_INPUT_VOLTAGE_RANGE                 0x0066
+#define BLE_MESH_SHORT_CIRCUIT_EVENT_STATISTICS                             0x0067
+#define BLE_MESH_TIME_SINCE_MOTION_SENSED                                   0x0068
+#define BLE_MESH_TIME_SINCE_PRESENCE_DETECTED                               0x0069
+#define BLE_MESH_TOTAL_DEVICE_ENERGY_USE                                    0x006A
+#define BLE_MESH_TOTAL_DEVICE_OFF_ON_CYCLES                                 0x006B
+#define BLE_MESH_TOTAL_DEVICE_POWER_ON_CYCLES                               0x006C
+#define BLE_MESH_TOTAL_DEVICE_POWER_ON_TIME                                 0x006D
+#define BLE_MESH_TOTAL_DEVICE_RUNTIME                                       0x006E
+#define BLE_MESH_TOTAL_LIGHT_EXPOSURE_TIME                                  0x006F
+#define BLE_MESH_TOTAL_LUMINOUS_ENERGY                                      0x0070
+
+/**
+ * @brief BLE Mesh Device Property value length
+ */
+#define BLE_MESH_AVERAGE_AMBIENT_TEMPERATURE_IN_A_PERIOD_OF_DAY_LEN             0x03
+#define BLE_MESH_AVERAGE_INPUT_CURRENT_LEN                                      0x03
+#define BLE_MESH_AVERAGE_INPUT_VOLTAGE_LEN                                      0x03
+#define BLE_MESH_AVERAGE_OUTPUT_CURRENT_LEN                                     0x03
+#define BLE_MESH_AVERAGE_OUTPUT_VOLTAGE_LEN                                     0x03
+#define BLE_MESH_CENTER_BEAM_INTENSITY_AT_FULL_POWER_LEN                        0x02
+#define BLE_MESH_CHROMATICITY_TOLERANCE_LEN                                     0x01
+#define BLE_MESH_COLOR_RENDERING_INDEX_R9_LEN                                   0x01
+#define BLE_MESH_COLOR_RENDERING_INDEX_RA_LEN                                   0x01
+#define BLE_MESH_DEVICE_APPEARANCE_LEN                                          0x02
+#define BLE_MESH_DEVICE_COUNTRY_OF_ORIGIN_LEN                                   0x02
+#define BLE_MESH_DEVICE_DATE_OF_MANUFACTURE_LEN                                 0x04
+#define BLE_MESH_DEVICE_ENERGY_USE_SINCE_TURN_ON_LEN                            0x04
+#define BLE_MESH_DEVICE_FIRMWARE_REVISION_LEN                                   0x08
+#define BLE_MESH_DEVICE_GLOBAL_TRADE_ITEM_NUMBER_LEN                            0x08
+#define BLE_MESH_DEVICE_HARDWARE_REVISION_LEN                                   0x16
+#define BLE_MESH_DEVICE_MANUFACTURER_NAME_LEN                                   0x36
+#define BLE_MESH_DEVICE_MODEL_NUMBER_LEN                                        0x24
+#define BLE_MESH_DEVICE_OPERATING_TEMPERATURE_RANGE_SPECIFICATION_LEN           0x04
+#define BLE_MESH_DEVICE_OPERATING_TEMPERATURE_STATISTICAL_VALUES_LEN            0x09
+#define BLE_MESH_DEVICE_OVER_TEMPERATURE_EVENT_STATISTICS_LEN                   0x06
+#define BLE_MESH_DEVICE_POWER_RANGE_SPECIFICATION_LEN                           0x12
+#define BLE_MESH_DEVICE_RUNTIME_SINCE_TURN_ON_LEN                               0x04
+#define BLE_MESH_DEVICE_RUNTIME_WARRANTY_LEN                                    0x04
+#define BLE_MESH_DEVICE_SERIAL_NUMBER_LEN                                       0x16
+#define BLE_MESH_DEVICE_SOFTWARE_REVISION_LEN                                   0x08
+#define BLE_MESH_DEVICE_UNDER_TEMPERATURE_EVENT_STATISTICS_LEN                  0x06
+#define BLE_MESH_INDOOR_AMBIENT_TEMPERATURE_STATISTICAL_VALUES_LEN              0x05
+#define BLE_MESH_INITIAL_CIE_1931_CHROMATICITY_COORDINATES_LEN                  0x04
+#define BLE_MESH_INITIAL_CORRELATED_COLOR_TEMPERATURE_LEN                       0x02
+#define BLE_MESH_INITIAL_LUMINOUS_FLUX_LEN                                      0x02
+#define BLE_MESH_INITIAL_PLANCKIAN_DISTANCE_LEN                                 0x02
+#define BLE_MESH_INPUT_CURRENT_RANGE_SPECIFICATION_LEN                          0x06
+#define BLE_MESH_INPUT_CURRENT_STATISTICS_LEN                                   0x09
+#define BLE_MESH_INPUT_OVER_CURRENT_EVENT_STATISTICS_LEN                        0x06
+#define BLE_MESH_INPUT_OVER_RIPPLE_VOLTAGE_EVENT_STATISTICS_LEN                 0x06
+#define BLE_MESH_INPUT_OVER_VOLTAGE_EVENT_STATISTICS_LEN                        0x06
+#define BLE_MESH_INPUT_UNDER_CURRENT_EVENT_STATISTICS_LEN                       0x06
+#define BLE_MESH_INPUT_UNDER_VOLTAGE_EVENT_STATISTICS_LEN                       0x06
+#define BLE_MESH_INPUT_VOLTAGE_RANGE_SPECIFICATION_LEN                          0x06
+#define BLE_MESH_INPUT_VOLTAGE_RIPPLE_SPECIFICATION_LEN                         0x01
+#define BLE_MESH_INPUT_VOLTAGE_STATISTICS_LEN                                   0x09
+#define BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_ON_LEN                          0x04
+#define BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_PROLONG_LEN                     0x04
+#define BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_STANDBY_LEN                     0x04
+#define BLE_MESH_LIGHT_CONTROL_LIGHTNESS_ON_LEN                                 0x02
+#define BLE_MESH_LIGHT_CONTROL_LIGHTNESS_PROLONG_LEN                            0x02
+#define BLE_MESH_LIGHT_CONTROL_LIGHTNESS_STANDBY_LEN                            0x02
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_ACCURACY_LEN                           0x01
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_KID_LEN                                0x04
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_KIU_LEN                                0x04
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_KPD_LEN                                0x04
+#define BLE_MESH_LIGHT_CONTROL_REGULATOR_KPU_LEN                                0x04
+#define BLE_MESH_LIGHT_CONTROL_TIME_FADE_LEN                                    0x03
+#define BLE_MESH_LIGHT_CONTROL_TIME_FADE_ON_LEN                                 0x03
+#define BLE_MESH_LIGHT_CONTROL_TIME_FADE_STANDBY_AUTO_LEN                       0x03
+#define BLE_MESH_LIGHT_CONTROL_TIME_FADE_STANDBY_MANUAL_LEN                     0x03
+#define BLE_MESH_LIGHT_CONTROL_TIME_OCCUPANCY_DELAY_LEN                         0x03
+#define BLE_MESH_LIGHT_CONTROL_TIME_PROLONG_LEN                                 0x03
+#define BLE_MESH_LIGHT_CONTROL_TIME_RUN_ON_LEN                                  0x03
+#define BLE_MESH_LUMEN_MAINTENANCE_FACTOR_LEN                                   0x01
+#define BLE_MESH_LUMINOUS_EFFICACY_LEN                                          0x02
+#define BLE_MESH_LUMINOUS_ENERGY_SINCE_TURN_ON_LEN                              0x04
+#define BLE_MESH_LUMINOUS_EXPOSURE_LEN                                          0x04
+#define BLE_MESH_LUMINOUS_FLUX_RANGE_LEN                                        0x04
+#define BLE_MESH_MOTION_SENSED_LEN                                              0x01
+#define BLE_MESH_MOTION_THRESHOLD_LEN                                           0x01
+#define BLE_MESH_OPEN_CIRCUIT_EVENT_STATISTICS_LEN                              0x06
+#define BLE_MESH_OUTDOOR_STATISTICAL_VALUES_LEN                                 0x05
+#define BLE_MESH_OUTPUT_CURRENT_RANGE_LEN                                       0x04
+#define BLE_MESH_OUTPUT_CURRENT_STATISTICS_LEN                                  0x09
+#define BLE_MESH_OUTPUT_RIPPLE_VOLTAGE_SPECIFICATION_LEN                        0x01
+#define BLE_MESH_OUTPUT_VOLTAGE_RANGE_LEN                                       0x06
+#define BLE_MESH_OUTPUT_VOLTAGE_STATISTICS_LEN                                  0x09
+#define BLE_MESH_OVER_OUTPUT_RIPPLE_VOLTAGE_EVENT_STATISTICS_LEN                0x06
+#define BLE_MESH_PEOPLE_COUNT_LEN                                               0x02
+#define BLE_MESH_PRESENCE_DETECTED_LEN                                          0x01
+#define BLE_MESH_PRESENT_AMBIENT_LIGHT_LEVEL_LEN                                0x04
+#define BLE_MESH_PRESENT_AMBIENT_TEMPERATURE_LEN                                0x01
+#define BLE_MESH_PRESENT_CIE_1931_CHROMATICITY_LEN                              0x04
+#define BLE_MESH_PRESENT_CORRELATED_COLOR_TEMPERATURE_LEN                       0x02
+#define BLE_MESH_PRESENT_DEVICE_INPUT_POWER_LEN                                 0x04
+#define BLE_MESH_PRESENT_DEVICE_OPERATING_EFFICIENCY_LEN                        0x01
+#define BLE_MESH_PRESENT_DEVICE_OPERATING_TEMPERATURE_LEN                       0x02
+#define BLE_MESH_PRESENT_ILLUMINANCE_LEN                                        0x04
+#define BLE_MESH_PRESENT_INDOOR_AMBIENT_TEMPERATURE_LEN                         0x01
+#define BLE_MESH_PRESENT_INPUT_CURRENT_LEN                                      0x02
+#define BLE_MESH_PRESENT_INPUT_RIPPLE_VOLTAGE_LEN                               0x01
+#define BLE_MESH_PRESENT_INPUT_VOLTAGE_LEN                                      0x02
+#define BLE_MESH_PRESENT_LUMINOUS_FLUX_LEN                                      0x02
+#define BLE_MESH_PRESENT_OUTDOOR_AMBIENT_TEMPERATURE_LEN                        0x01
+#define BLE_MESH_PRESENT_OUTPUT_CURRENT_LEN                                     0x02
+#define BLE_MESH_PRESENT_OUTPUT_VOLTAGE_LEN                                     0x02
+#define BLE_MESH_PRESENT_PLANCKIAN_DISTANCE_LEN                                 0x02
+#define BLE_MESH_PRESENT_RELATIVE_OUTPUT_RIPPLE_VOLTAGE_LEN                     0x01
+#define BLE_MESH_RELATIVE_DEVICE_ENERGY_USE_IN_A_PERIOD_OF_DAY_LEN              0x06
+#define BLE_MESH_RELATIVE_DEVICE_RUNTIME_IN_A_GENERIC_LEVEL_RANGE_LEN           0x05
+#define BLE_MESH_RELATIVE_EXPOSURE_TIME_IN_AN_ILLUMINANCE_RANGE_LEN             0x09
+#define BLE_MESH_RELATIVE_RUNTIME_IN_A_CORRELATED_COLOR_TEMPERATURE_RANGE_LEN   0x04
+#define BLE_MESH_RELATIVE_RUNTIME_IN_A_DEVICE_OPERATING_TEMPERATURE_RANGE_LEN   0x05
+#define BLE_MESH_RELATIVE_RUNTIME_IN_AN_INPUT_CURRENT_RANGE_LEN                 0x05
+#define BLE_MESH_RELATIVE_RUNTIME_IN_AN_INPUT_VOLTAGE_RANGE_LEN                 0x05
+#define BLE_MESH_SHORT_CIRCUIT_EVENT_STATISTICS_LEN                             0x06
+#define BLE_MESH_TIME_SINCE_MOTION_SENSED_LEN                                   0x02
+#define BLE_MESH_TIME_SINCE_PRESENCE_DETECTED_LEN                               0x02
+#define BLE_MESH_TOTAL_DEVICE_ENERGY_USE_LEN                                    0x04
+#define BLE_MESH_TOTAL_DEVICE_OFF_ON_CYCLES_LEN                                 0x04
+#define BLE_MESH_TOTAL_DEVICE_POWER_ON_CYCLES_LEN                               0x04
+#define BLE_MESH_TOTAL_DEVICE_POWER_ON_TIME_LEN                                 0x04
+#define BLE_MESH_TOTAL_DEVICE_RUNTIME_LEN                                       0x04
+#define BLE_MESH_TOTAL_LIGHT_EXPOSURE_TIME_LEN                                  0x04
+#define BLE_MESH_TOTAL_LUMINOUS_ENERGY_LEN                                      0x04
+
+/**
+ * @brief BLE Mesh Device Property referenced Characteristic UUIDs
+ */
+#define BLE_MESH_UUID_AVERAGE_CURRENT_VAL                               0x2AE0
+#define BLE_MESH_UUID_AVERAGE_VOLTAGE_VAL                               0x2AE1
+#define BLE_MESH_UUID_BOOLEAN_VAL                                       0x2AE2
+#define BLE_MESH_UUID_CHROMATIC_DISTANCE_FROM_PLANCKIAN_VAL             0x2AE3
+#define BLE_MESH_UUID_CHROMATICITY_COORDINATE_VAL                       0x2B1C
+#define BLE_MESH_UUID_CHROMATICITY_COORDINATES_VAL                      0x2AE4
+#define BLE_MESH_UUID_CHROMATICITY_IN_CCT_AND_DUV_VALUES_VAL            0x2AE5
+#define BLE_MESH_UUID_CHROMATICITY_TOLERANCE_VAL                        0x2AE6
+#define BLE_MESH_UUID_CIE_13_3_1995_COLOR_RENDERING_INDEX_VAL           0x2AE7
+#define BLE_MESH_UUID_COEFFICIENT_VAL                                   0x2AE8
+#define BLE_MESH_UUID_CORRELATED_COLOR_TEMPERATURE_VAL                  0x2AE9
+#define BLE_MESH_UUID_COUNT_16_VAL                                      0x2AEA
+#define BLE_MESH_UUID_COUNT_24_VAL                                      0x2AEB
+#define BLE_MESH_UUID_COUNTRY_CODE_VAL                                  0x2AEC
+#define BLE_MESH_UUID_DATE_UTC_VAL                                      0x2AED
+#define BLE_MESH_UUID_ELECTRIC_CURRENT_VAL                              0x2AEE
+#define BLE_MESH_UUID_ELECTRIC_CURRENT_RANGE_VAL                        0x2AEF
+#define BLE_MESH_UUID_ELECTRIC_CURRENT_SPECIFICATION_VAL                0x2AF0
+#define BLE_MESH_UUID_ELECTRIC_CURRENT_STATISTICS_VAL                   0x2AF1
+#define BLE_MESH_UUID_ENERGY_VAL                                        0x2AF2
+#define BLE_MESH_UUID_ENERGY_IN_A_PERIOD_OF_DAY_VAL                     0x2AF3
+#define BLE_MESH_UUID_EVENT_STATISTICS_VAL                              0x2AF4
+#define BLE_MESH_UUID_FIXED_STRING_16_VAL                               0x2AF5
+#define BLE_MESH_UUID_FIXED_STRING_24_VAL                               0x2AF6
+#define BLE_MESH_UUID_FIXED_STRING_36_VAL                               0x2AF7
+#define BLE_MESH_UUID_FIXED_STRING_8_VAL                                0x2AF8
+#define BLE_MESH_UUID_GENERIC_LEVEL_VAL                                 0x2AF9
+#define BLE_MESH_UUID_GLOBAL_TRADE_ITEM_NUMBER_VAL                      0x2AFA
+#define BLE_MESH_UUID_ILLUMINANCE_VAL                                   0x2AFB
+#define BLE_MESH_UUID_LUMINOUS_EFFICACY_VAL                             0x2AFC
+#define BLE_MESH_UUID_LUMINOUS_ENERGY_VAL                               0x2AFD
+#define BLE_MESH_UUID_LUMINOUS_EXPOSURE_VAL                             0x2AFE
+#define BLE_MESH_UUID_LUMINOUS_FLUX_VAL                                 0x2AFF
+#define BLE_MESH_UUID_LUMINOUS_FLUX_RANGE_VAL                           0x2B00
+#define BLE_MESH_UUID_LUMINOUS_INTENSITY_VAL                            0x2B01
+#define BLE_MESH_UUID_MASS_FLOW_VAL                                     0x2B02
+/**
+ * The following four have been defined in mesh_uuid.h
+ * #define BLE_MESH_UUID_MESH_PROV_DATA_IN_VAL                          0x2ADB
+ * #define BLE_MESH_UUID_MESH_PROV_DATA_OUT_VAL                         0x2ADC
+ * #define BLE_MESH_UUID_MESH_PROXY_DATA_IN_VAL                         0x2ADD
+ * #define BLE_MESH_UUID_MESH_PROXY_DATA_OUT_VAL                        0x2ADE
+ */
+#define BLE_MESH_UUID_PERCEIVED_LIGHTNESS_VAL                           0x2B03
+#define BLE_MESH_UUID_PERCENTAGE_8_VAL                                  0x2B04
+#define BLE_MESH_UUID_POWER_VAL                                         0x2B05
+#define BLE_MESH_UUID_POWER_SPECIFICATION_VAL                           0x2B06
+#define BLE_MESH_UUID_RELATIVE_RUNTIME_IN_A_CURRENT_RANGE_VAL           0x2B07
+#define BLE_MESH_UUID_RELATIVE_RUNTIME_IN_A_GENERIC_LEVEL_RANGE_VAL     0x2B08
+#define BLE_MESH_UUID_RELATIVE_VALUE_IN_A_PERIOD_OF_DAY_VAL             0x2B0B
+#define BLE_MESH_UUID_RELATIVE_VALUE_IN_A_TEMPERATURE_RANGE_VAL         0x2B0C
+#define BLE_MESH_UUID_RELATIVE_VALUE_IN_A_VOLTAGE_RANGE_VAL             0x2B09
+#define BLE_MESH_UUID_RELATIVE_VALUE_IN_AN_ILLUMINANCE_RANGE_VAL        0x2B0A
+#define BLE_MESH_UUID_TEMPERATURE_8_VAL                                 0x2B0D
+#define BLE_MESH_UUID_TEMPERATURE_8_IN_A_PERIOD_OF_DAY_VAL              0x2B0E
+#define BLE_MESH_UUID_TEMPERATURE_8_STATISTICS_VAL                      0x2B0F
+#define BLE_MESH_UUID_TEMPERATURE_RANGE_VAL                             0x2B10
+#define BLE_MESH_UUID_TEMPERATURE_STATISTICS_VAL                        0x2B11
+#define BLE_MESH_UUID_TIME_DECIHOUR_8_VAL                               0x2B12
+#define BLE_MESH_UUID_TIME_EXPONENTIAL_8_VAL                            0x2B13
+#define BLE_MESH_UUID_TIME_HOUR_24_VAL                                  0x2B14
+#define BLE_MESH_UUID_TIME_MILLISECOND_24_VAL                           0x2B15
+#define BLE_MESH_UUID_TIME_SECOND_16_VAL                                0x2B16
+#define BLE_MESH_UUID_TIME_SECOND_8_VAL                                 0x2B17
+#define BLE_MESH_UUID_VOLTAGE_VAL                                       0x2B18
+#define BLE_MESH_UUID_VOLTAGE_SPECIFICATION_VAL                         0x2B19
+#define BLE_MESH_UUID_VOLTAGE_STATISTICS_VAL                            0x2B1A
+#define BLE_MESH_UUID_VOLUME_FLOW_VAL                                   0x2B1B
+
+/**
+ * @brief BLE Mesh Device Property referenced Characteristic Type Definitions
+ */
+
+/* Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius. */
+typedef s16_t bt_mesh_temperature_t;
+
+typedef u16_t bt_mesh_gap_appearance_t;
+
+/* Mesh Characteristics Type Definitions  */
+
+/* This characteristic represents an electric current.
+ * Note: Unit is ampere with a resolution of 0.01.
+ *       Minimum value: 0, maximum value: 655.34;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_electric_current_t;
+
+/* The Time Exponential 8 characteristic is used to represent a measure of period of
+ * time in seconds.
+ * Note: The time duration is given by the value 1.1^(N-64) in seconds, with N being
+ *       the raw 8-bit value;
+ *       Minimum value: 0.0, maximum value: 73216705;
+ *       A raw value of 0x00 represents 0 seconds, and a raw value of 0xFF represents
+ *       the total life of the device.
+ */
+typedef u8_t bt_mesh_time_exponential_8_t;
+
+/* The Voltage characteristic is used to represent a measure of positive electric
+ * potential difference in units of volts.
+ * Note: Unit is volt with a resolution of 1/64V;
+ *       Minimum value: 0.0, maximum value: 1022.0;
+ *       A value of 0xFFFF represents 'value is not known'. The minimum representable
+ *       value represents the minimum value or lower, the maximum representable value
+ *       represents the maximum value or higher.
+ */
+typedef u16_t bt_mesh_voltage_t;
+
+/* This characteristic aggregates the Electric Current characteristic and instance of
+ * the Time Exponential 8 characteristic.
+ */
+typedef struct __packed average_current {
+    bt_mesh_electric_current_t   electric_current;
+    bt_mesh_time_exponential_8_t sensing_duration;
+} bt_mesh_average_current_t;
+
+/* This characteristic aggregates the Voltage characteristic and instance of the Time
+ * Exponential 8 characateristic.
+ */
+typedef struct __packed average_voltage {
+    bt_mesh_voltage_t            voltage;
+    bt_mesh_time_exponential_8_t sensing_duration;
+} bt_mesh_average_voltage_t;
+
+/* The Boolean characteristic defines the predefined Boolean values as an enumeration.
+ * Key      |   Value
+ * 0        |   False
+ * 1        |   True
+ * 2 to 255 |   Prohibited
+ */
+typedef u8_t bt_mesh_boolean_t;
+
+/* The Chromatic Distance From Planckian characteristic represents a distance of a
+ * chromaticity coordinate from the Planckian locus in the (u',2/3 v') diagram as
+ * defined by ANSI standard C78.377-2008. The distance is positive if the chromaticity
+ * coordinate is located above the Planckian locus (i.e. has as higher y value than the
+ * Planckian), and negative if it is located below. The distance is only valid within
+ * the range from -0.05 to 0.05.
+ * Note: Unit is unitless with a resolution of 0.00001;
+ *       Minimum value: -0.05, maximum value: 0.05;
+ *       A value of 0xFFFF represents 'value is not known';
+ *       A value of 0xFFFE represents 'value is not valid'.
+ */
+typedef s16_t bt_mesh_chromatic_distance_from_planckian_t;
+
+/* This characteristic represents a chromaticity coordinate in a color diagram such as
+ * the CIE1931 diagram. It can represent an x or y coordinate.
+ * Note: Unit is unitless with a resolution of 1/65535;
+ *       Minimum value: 0, maximum value: 1.0.
+ */
+typedef u16_t bt_mesh_chromaticity_coordinate_t;
+
+/* This characteristic represents a chromaticity coordinate as a tuple with an x and
+ * y coordinate.
+ */
+typedef struct __packed chromaticity_coordinates {
+    bt_mesh_chromaticity_coordinate_t chromaticity_x_coordinate;
+    bt_mesh_chromaticity_coordinate_t chromaticity_y_coordinate;
+} bt_mesh_chromaticity_coordinates_t;
+
+/* The Correlated Color Temperature characteristic is used to represent correlated color
+ * temperature in a range from 800 to 65534 Kelvin with a resolution of 1 Kelvin.
+ * Note: Unit is Kelvin with a resolution of 1;
+ *       Minimum value: 800, maximum value: 65534;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_correlated_color_temperature_t;
+
+/* The Chromaticity In CCT And Duv Values characteristic is a composite characteristic
+ * consisting of the Correlated Color Temperature characteristic and the Chromatic
+ * Distance From Planckian characteristic.
+ */
+typedef struct __packed chromaticity_in_cct_and_duv_values {
+    bt_mesh_correlated_color_temperature_t      correlated_color_temperature;
+    bt_mesh_chromatic_distance_from_planckian_t chromaticity_distance_from_planckian;
+} bt_mesh_chromaticity_in_cct_and_duv_values_t;
+
+/* The Chromaticity Tolerance characteristic is a tolerance of a tuple of chromaticity
+ * values represented as a value of a radius of a circle in the CIE 1976 (u',v') diagram;
+ * value corresponding to the 3-sigma values of the expected chromaticity deviations.
+ * Note: Unit is unitless with a resolution of 0.0001;
+ *       Minimum value: 0, maximum value: 0.0255.
+ */
+typedef u8_t bt_mesh_chromaticity_tolerance_t;
+
+/* The CIE 13.3-1995 Color Rendering Index characteristic is a color rendition index value
+ * for a color patch as calculated in accordance with the CIE 13.3-1995 standard.
+ * Note: Unit is unitless with a resolution of 1;
+ *       Minimum value: -128, maximum value: 100.
+ */
+typedef s8_t bt_mesh_cie_13_3_1995_color_rendering_index_t;
+
+/* The Coefficient characteristic is used to represent a general coefficient value. */
+typedef float bt_mesh_coefficient_t;
+
+/* The Count 16 characteristic is used to represent a general count value.
+ * Note: Unit is unitless with a resolution of 1;
+ *       Minimum value: 0, maximum value 65534;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_count_16_t;
+
+/* The Count 24 characteristic is used to represent a general count value.
+ * Note: Unit is unitless with a resolution of 1;
+ *       Minimum value: 0, maximum value 16777214;
+ *       A value of 0xFFFFFF represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_count_24_t[3];
+
+/* This characteristic represents a country or dependent areas in accordance with
+ * the ISO 3166-1 Numeric standard.
+ * Note: Unit is unitless with a resolution of 1;
+ *       Minimum value: 0, maximum value: 4095;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_country_code_t;
+
+/* Date as days elapsed since the Epoch (Jan 1, 1970) in the Coordinated Universal
+ * Time (UTC) time zone.
+ * Note: Unit is a day with a resolution of 1;
+ *       Minimum value: 1, maximum value: 16777214;
+ *       A value of 0x000000 represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_date_utc_t[3];
+
+/* This characteristic aggregates two instances of the Electric Current characteristic
+ * to represent a range of Electric Current values.
+ */
+typedef struct __packed electric_current_range {
+    bt_mesh_electric_current_t minimum_electric_current_value;
+    bt_mesh_electric_current_t maximum_electric_current_value;
+} bt_mesh_electric_current_range_t;
+
+/* This characteristic aggregates three instances of the Electric Current characteristic
+ * to represent a specification of electric current values.
+ */
+typedef struct __packed electric_current_specification {
+    bt_mesh_electric_current_t minimum_electric_current_value;
+    bt_mesh_electric_current_t typical_electric_current_value;
+    bt_mesh_electric_current_t maximum_electric_current_value;
+} bt_mesh_electric_current_specification_t;
+
+/* This characteristic aggregates four instances of the Electric Current characteristic
+ * with a Sensing Duration to represent a set of statistical electric current values.
+ */
+typedef struct __packed electric_current_statistics {
+    bt_mesh_electric_current_t   average_electric_current_value;
+    bt_mesh_electric_current_t   standard_electric_current_value;
+    bt_mesh_electric_current_t   minimum_electric_current_value;
+    bt_mesh_electric_current_t   maximum_electric_current_value;
+    bt_mesh_time_exponential_8_t sensing_duration;
+} bt_mesh_electric_current_statistics_t;
+
+/* The Energy characteristic is used to represent a measure of energy in units of
+ * kilowatt hours.
+ * Note: Unit is kilowatt-hour with a resolution of 1;
+ *       Minimum value: 0, maximum value: 16777214;
+ *       A value of 0xFFFFFF represents ‘value is not known’.
+ */
+typedef u8_t bt_mesh_energy_t[3];
+
+/* The Time Decihour 8 characteristic is used to represent a period of time in
+ * tenths of an hour.
+ * Note: Unit is hour with a resolution of 0.1;
+ *       Minimum value: 0.0, maximum value: 24.0;
+ *       A value of 0xFF represents 'value is not known'. All other values are Prohibited.
+ */
+typedef u8_t bt_mesh_time_decihour_8_t;
+
+/* This characteristic aggregates the Energy characteristic, and two instances of
+ * the Time Decihour 8 characteristic, to represent energy use in a period of day.
+ */
+typedef struct __packed energy_in_a_period_of_day {
+    bt_mesh_energy_t          energy_value;
+    bt_mesh_time_decihour_8_t start_time;
+    bt_mesh_time_decihour_8_t end_time;
+} bt_mesh_energy_in_a_period_of_day_t;
+
+/* The Time Second 16 characteristic is used to represent a period of time with a
+ * unit of 1 second.
+ * Note: Unit is second with a resolution of 1;
+ *       Minimum value: 0, maximum value: 65534;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_time_second_16_t;
+
+/* This characteristic aggregates the Count 16 characteristic, two instances of the
+ * Time Decihour 8 characteristic and an instance of the Sensing Duration characteristic,
+ * to represent statistical values of events.
+ */
+typedef struct __packed event_statistics {
+    bt_mesh_count_16_t           number_of_events;
+    bt_mesh_time_second_16_t     average_event_duration;
+    bt_mesh_time_exponential_8_t time_elapsed_since_last_event;
+    bt_mesh_time_exponential_8_t sensing_duration;
+} bt_mesh_event_statistics_t;
+
+/* The Fixed String 16 characteristic represents a 16-octet UTF-8 string. */
+typedef char bt_mesh_fixed_string_16_t[16];
+
+/* The Fixed String 24 characteristic represents a 24-octet UTF-8 string. */
+typedef char bt_mesh_fixed_string_24_t[24];
+
+/* The Fixed String 36 characteristic represents a 36-octet UTF-8 string. */
+typedef char bt_mesh_fixed_string_36_t[36];
+
+/* The Fixed String 8 characteristic represents an 8-octet UTF-8 string. */
+typedef char bt_mesh_fixed_string_8_t[8];
+
+/* The Generic Level characteristic represents a general level value of a
+ * setting of a device.
+ * Note: Unit is unitless with a resolution of 1;
+ *       Minimum value: 0, maximum value: 65535.
+ */
+typedef u16_t bt_mesh_generic_level_t;
+
+/* The Global Trade Item Number characteristic represents an identifier as
+ * issued by GS1 General Specifications, which may consist up to 14 digits,
+ * and is here represented as a 48-bit unsigned integer.
+ */
+typedef u8_t bt_mesh_global_trade_item_number_t[6];
+
+/* The Illuminance characteristic is used to represent a measure of illuminance
+ * in units of lux.
+ * Note: Unit is lux with a resolution of 0.01;
+ *       Minimum value: 0, maximum value: 167772.14;
+ *       A value of 0xFFFFFF represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_illuminance_t[3];
+
+/* The Luminous Efficacy characteristic is used to represent a measure of luminous
+ * efficacy in units of lumen per watt.
+ * Note: Unit is lumen per watt with a resolution of 0.1;
+ *       Minimum value: 0, maximum value: 1800;
+ *       A value of 0xFFFF represents 'value is not known'. All other values are Prohibited.
+ */
+typedef u16_t bt_mesh_luminous_efficacy_t;
+
+/* The Luminous Energy characteristic is used to represent a measure of luminous
+ * energy in units of lumen hour.
+ * Note: Unit is lumen hour with a resolution of 1000;
+ *       Minimum value: 0, maximum value: 16777214000;
+ *       A value of 0xFFFFFF represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_luminous_energy_t[3];
+
+/* The Luminous Exposure characteristic is used to represent a measure of luminous
+ * exposure in units of lux-hour.
+ * Note: Unit is lux hour with a resolution of 1000;
+ *       Minimum value: 0, maximum value: 16777214000;
+ *       A value of 0xFFFFFF represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_luminous_exposure_t[3];
+
+/* The Luminous Flux characteristic is used to represent a measure of luminous flux
+ * in units of lumen.
+ * Note: Unit is lumen with a resolution of 1;
+ *       Minimum value: 0, maximum value: 65534;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_luminous_flux_t;
+
+/* This characteristic aggregates two instances of the Luminous Flux characteristic
+ * to represent a luminous flux range.
+ */
+typedef struct __packed luminous_flux_range {
+    bt_mesh_luminous_flux_t minimum_luminous_flux;
+    bt_mesh_luminous_flux_t maximum_luminous_flux;
+} bt_mesh_luminous_flux_range_t;
+
+/* The Luminous Intensity characteristic is used to represent a luminous intensity of
+ * a beam of light in units of candela.
+ * Note: Unit is candela with a resolution of 1;
+ *       Minimum value: 0, maximum value: 65534;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_luminous_intensity_t;
+
+/* The Mass Flow characteristic is used to represent a flow of mass.
+ * Note: Unit is gram/second with a resolution of 1;
+ *       Minimum value: 0, maximum value: 65534;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_mass_flow_t;
+
+/* The Mesh Provisioning Data In characteristic can be written to send a Proxy PDU
+ * message containing Provisioning PDU to the Provisioning Server.
+ */
+struct mesh_provisioning_data_in {
+
+};
+
+/* The Mesh Provisioning Data Out characteristic can be notified to send a Proxy PDU
+ * message containing Provisioning PDU from a Provisioning Server to a Provisioning Client.
+ */
+struct mesh_provisioning_data_out {
+
+};
+
+/* The Mesh Proxy Data In characteristic is used by the client to send Proxy PDUs to
+ * the server.
+ */
+struct mesh_proxy_data_in {
+
+};
+
+/* The Mesh Proxy Data Out characteristic is used by the server to send Proxy PDUs to
+ * the client.
+ */
+struct mesh_proxy_data_out {
+
+};
+
+/* The Perceived Lightness characteristic is used to represent the perceived lightness
+ * of a light.
+ * Note: Unit is unitless with a resolution of 1;
+ *       Minimum value: 0, maximum value: 65535.
+ */
+typedef u16_t bt_mesh_perceived_lightness_t;
+
+/* The Percentage 8 characteristic is used to represent a measure of percentage.
+ * Note: Unit is a percentage with a resolution of 0.5;
+ *       Minimum value: 0, maximum value: 100;
+ *       A value of 0xFF represents 'value is not known'. All other values are Prohibited.
+ */
+typedef u8_t bt_mesh_percentage_8_t;
+
+/* The Power characteristic is used to represent a measure of power in units of watts.
+ * Note: Unit is watt with a resolution of 0.1;
+ *       Minimum value: 0, maximum value: 1677721.4;
+ *       A value of 0xFFFFFF represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_power_t[3];
+
+/* This characteristic aggregates three instances of the Power characteristic to
+ * represent a specification of Power values.
+ */
+typedef struct __packed power_specification {
+    bt_mesh_power_t minimum_power_value;
+    bt_mesh_power_t typical_power_value;
+    bt_mesh_power_t maximum_power_value;
+} bt_mesh_power_specification_t;
+
+/* This characteristic aggregates the Percentage 8 characteristic and two instances of
+ * the Electric Current characteristic to represent a relative value in an electric
+ * current range.
+ */
+typedef struct __packed relative_runtime_in_a_current_range {
+    bt_mesh_percentage_8_t     relative_runtime_value;
+    bt_mesh_electric_current_t minimum_current;
+    bt_mesh_electric_current_t maximum_current;
+} bt_mesh_relative_runtime_in_a_current_range_t;
+
+/* This characteristic aggregates the Percentage 8 characteristic and two instances of
+ * the Generic Level characteristic to represent a runtime in a generic level range.
+ */
+typedef struct __packed relative_runtime_in_a_generic_level_range {
+    bt_mesh_percentage_8_t  relative_value;
+    bt_mesh_generic_level_t minimum_generic_level;
+    bt_mesh_generic_level_t maximum_generic_level;
+} bt_mesh_relative_runtime_in_a_generic_level_range_t;
+
+/* This characteristic aggregates the Percentage 8 characteristic, and two instances of
+ * the Time Decihour 8 characteristic.
+ */
+typedef struct __packed relative_value_in_a_period_of_day {
+    bt_mesh_percentage_8_t    relative_value;
+    bt_mesh_time_decihour_8_t start_time;
+    bt_mesh_time_decihour_8_t end_time;
+} bt_mesh_relative_value_in_a_period_of_day_t;
+
+/* This characteristic aggregates the Percentage 8 characteristic, and two instances of
+ * the Temperature characteristic.
+ */
+typedef struct __packed relative_value_in_a_temperature_range {
+    bt_mesh_percentage_8_t relative_value;
+    bt_mesh_temperature_t  minimum_temperature_value;
+    bt_mesh_temperature_t  maximum_temperature_value;
+} bt_mesh_relative_value_in_a_temperature_range_t;
+
+/* This characteristic aggregates the Percentage 8 characteristic and two instances of
+ * the Voltage characteristic to represent a relative value in a voltage range.
+ */
+typedef struct __packed relative_value_in_a_voltage_range {
+    bt_mesh_percentage_8_t relative_value;
+    bt_mesh_voltage_t      minimum_voltage;
+    bt_mesh_voltage_t      maximum_voltage;
+} bt_mesh_relative_value_in_a_voltage_range_t;
+
+/* This characteristic aggregates the Percentage 8 characteristic and two instances of
+ * the Illuminance characteristic to represent a relative value in a illuminance range.
+ */
+typedef struct __packed relative_value_in_an_illuminance_range {
+    bt_mesh_percentage_8_t relative_value;
+    bt_mesh_illuminance_t  minimum_illuminance;
+    bt_mesh_illuminance_t  maximum_illuminance;
+} bt_mesh_relative_value_in_an_illuminance_range_t;
+
+/* The Temperature 8 characteristic is used to represent a measure of temperature with
+ * a unit of 0.5 degree Celsius.
+ * Note: Unit is degree Celsius with a resolution of 0.5;
+ *       Minimum value: -64.0, maximum value: 63.5;
+ *       A value of 0xFF represents 'value is not known'.
+ */
+typedef s8_t bt_mesh_temperature_8_t;
+
+/* This characteristic aggregates the Temperature 8 characteristic, and two instances
+ * of the Time Decihour 8 characteristic, to represent a temperature value in a period
+ * of day.
+ */
+typedef struct __packed temperature_8_in_a_period_of_day {
+    bt_mesh_temperature_8_t   temperature;
+    bt_mesh_time_decihour_8_t start_time;
+    bt_mesh_time_decihour_8_t end_time;
+} bt_mesh_temperature_8_in_a_period_of_day_t;
+
+/* This characteristic aggregates four instances of the Temperature 8 characteristic,
+ * and one instance of the Time Exponential 8 characteristic.
+ */
+typedef struct __packed temperature_8_statistics {
+    bt_mesh_temperature_8_t      average;
+    bt_mesh_temperature_8_t      standard_deviation_value;
+    bt_mesh_temperature_8_t      minimum_value;
+    bt_mesh_temperature_8_t      maximum_value;
+    bt_mesh_time_exponential_8_t sensing_duration;
+} bt_mesh_temperature_8_statistics_t;
+
+/* This characteristic aggregates two instances of the Temperature characteristic to
+ * represent a temperature range.
+ */
+typedef struct __packed temperature_range {
+    bt_mesh_temperature_t minimum_temperature;
+    bt_mesh_temperature_t maximum_temperature;
+} bt_mesh_temperature_range_t;
+
+/* This characteristic aggregates four instances of the Temperature characteristic,
+ * and one instance of the Time Exponential 8 characteristic.
+ */
+typedef struct __packed temperature_statistics {
+    bt_mesh_temperature_t        average_temperature;
+    bt_mesh_temperature_t        standard_deviation_temperature;
+    bt_mesh_temperature_t        minimum_temperature;
+    bt_mesh_temperature_t        maximum_temperature;
+    bt_mesh_time_exponential_8_t sensing_duration;
+} bt_mesh_temperature_statistics_t;
+
+/* The Time Hour 24 characteristic is used to represent a period of time in hours.
+ * Note: Unit is hour with a resolution of 1;
+ *       Minimum value: 0, maximum value: 16777214;
+ *       A value of 0xFFFFFF represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_time_hour_24_t[3];
+
+/* The Time Millisecond 24 characteristic is used to represent a period of time with
+ * a resolution of 1 millisecond.
+ * Note: Unit is second with a resolution of 0.001;
+ *       Minimum value: 0, maximum value: 16777.214;
+ *       A value of 0xFFFFFF represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_time_millisecond_24_t[3];
+
+/* The Time Second 8 characteristic is used to represent a period of time with a unit
+ * of 1 second.
+ * Note: Unit is second with a resolution of 1;
+ *       Minimum value: 0, maximum value: 254;
+ *       A value of 0xFF represents 'value is not known'.
+ */
+typedef u8_t bt_mesh_time_second_8_t;
+
+/* This characteristic aggregates three instances of the Voltage characteristic to
+ * represent a specification of voltage values.
+ */
+typedef struct __packed voltage_specification {
+    bt_mesh_voltage_t minimum_voltage_value;
+    bt_mesh_voltage_t typical_voltage_value;
+    bt_mesh_voltage_t maximum_voltage_value;
+} bt_mesh_voltage_specification_t;
+
+/* This characteristic aggregates four instances of the Voltage characteristic and an
+ * instance of the Time Exponential 8 characteristic to represent a set of statistical
+ * voltage values over a period of time.
+ */
+typedef struct __packed voltage_statistics {
+    bt_mesh_voltage_t            average_voltage_value;
+    bt_mesh_voltage_t            standard_deviation_voltage_value;
+    bt_mesh_voltage_t            minimum_voltage_value;
+    bt_mesh_voltage_t            maximum_voltage_value;
+    bt_mesh_time_exponential_8_t sensing_duration;
+} bt_mesh_voltage_statistics_t;
+
+/* The Volume Flow characteristic is used to represent a flow of a general volume such
+ * as a volume of material or gas.
+ * Note: Unit is liter/second with a resolution of 0.001 (1 milliliter);
+ *       Minimum value: 0, maximum value: 65534;
+ *       A value of 0xFFFF represents 'value is not known'.
+ */
+typedef u16_t bt_mesh_volume_flow_t;
+
+/* Mesh Device Property related function */
+
+u8_t bt_mesh_get_dev_prop_len(u16_t prop_id);
+
+#endif /* _DEVICE_PROPERTY_H_ */

+ 374 - 0
components/bt/esp_ble_mesh/mesh_models/server/include/generic_server.h

@@ -0,0 +1,374 @@
+/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
+ *
+ * Copyright (c) 2018 Vikrant More
+ * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _GENERIC_SERVER_H_
+#define _GENERIC_SERVER_H_
+
+#include "server_common.h"
+
+struct bt_mesh_gen_onoff_state {
+    u8_t onoff;
+    u8_t target_onoff;
+};
+
+struct bt_mesh_gen_onoff_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_onoff_state state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+};
+
+struct bt_mesh_gen_level_state {
+    s16_t level;
+    s16_t target_level;
+
+    s16_t last_level;
+    s32_t last_delta;
+
+    bool move_start;
+    bool positive;
+};
+
+struct bt_mesh_gen_level_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_level_state state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+    s32_t tt_delta_level;
+};
+
+struct bt_mesh_gen_def_trans_time_state {
+    u8_t trans_time;
+};
+
+struct bt_mesh_gen_def_trans_time_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_def_trans_time_state state;
+};
+
+struct bt_mesh_gen_onpowerup_state {
+    u8_t onpowerup;
+};
+
+struct bt_mesh_gen_power_onoff_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_onpowerup_state *state;
+};
+
+struct bt_mesh_gen_power_onoff_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_onpowerup_state *state;
+};
+
+struct bt_mesh_gen_power_level_state {
+    u16_t power_actual;
+    u16_t target_power_actual;
+
+    u16_t power_last;
+    u16_t power_default;
+
+    u8_t  status_code;
+    u16_t power_range_min;
+    u16_t power_range_max;
+};
+
+struct bt_mesh_gen_power_level_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_power_level_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+    s32_t tt_delta_level;
+};
+
+struct bt_mesh_gen_power_level_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_power_level_state *state;
+};
+
+struct bt_mesh_gen_battery_state {
+    u32_t battery_level : 8,
+          time_to_discharge : 24;
+    u32_t time_to_charge : 24,
+          battery_flags : 8;
+};
+
+struct bt_mesh_gen_battery_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_battery_state state;
+};
+
+struct bt_mesh_gen_location_state {
+    s32_t global_latitude;
+    s32_t global_longitude;
+    s16_t global_altitude;
+    s16_t local_north;
+    s16_t local_east;
+    s16_t local_altitude;
+    u8_t  floor_number;
+    u16_t uncertainty;
+};
+
+struct bt_mesh_gen_location_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_location_state *state;
+};
+
+struct bt_mesh_gen_location_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_gen_location_state *state;
+};
+
+/**
+ * According to the hierarchy of Generic Property states (Model Spec section 3.1.8),
+ * the Manufacturer Properties and Admin Properties may contain multiple Property
+ * states. User Properties just a collection of which can be accessed.
+ *
+ * property_count: Number of the properties contained in the table
+ * properties:     Table of the properties
+ *
+ * These variables need to be initialized in the application layer, the precise
+ * number of the properties should be set and memories used to store the property
+ * values should be allocated.
+ */
+
+enum bt_mesh_gen_user_prop_access {
+    USER_ACCESS_PROHIBIT,
+    USER_ACCESS_READ,
+    USER_ACCESS_WRITE,
+    USER_ACCESS_READ_WRITE,
+};
+
+enum bt_mesh_gen_admin_prop_access {
+    ADMIN_NOT_USER_PROP,
+    ADMIN_ACCESS_READ,
+    ADMIN_ACCESS_WRITE,
+    ADMIN_ACCESS_READ_WRITE,
+};
+
+enum bt_mesh_gen_manu_prop_access {
+    MANU_NOT_USER_PROP,
+    MANU_ACCESS_READ,
+};
+
+struct bt_mesh_generic_property {
+    u16_t id;
+    u8_t  user_access;
+    u8_t  admin_access;
+    u8_t  manu_access;
+    struct net_buf_simple *val;
+};
+
+struct bt_mesh_gen_user_prop_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    u8_t property_count;
+    struct bt_mesh_generic_property *properties;
+};
+
+struct bt_mesh_gen_admin_prop_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    u8_t property_count;
+    struct bt_mesh_generic_property *properties;
+};
+
+struct bt_mesh_gen_manu_prop_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    u8_t property_count;
+    struct bt_mesh_generic_property *properties;
+};
+
+struct bt_mesh_gen_client_prop_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    u8_t id_count;
+    u16_t *property_ids;
+};
+
+typedef union {
+    struct {
+        u8_t onoff;
+    } gen_onoff_set;
+    struct {
+        s16_t level;
+    } gen_level_set;
+    struct {
+        s16_t level;
+    } gen_delta_set;
+    struct {
+        s16_t level;
+    } gen_move_set;
+    struct {
+        u8_t trans_time;
+    } gen_def_trans_time_set;
+    struct {
+        u8_t onpowerup;
+    } gen_onpowerup_set;
+    struct {
+        u16_t power;
+    } gen_power_level_set;
+    struct {
+        u16_t power;
+    } gen_power_default_set;
+    struct {
+        u16_t range_min;
+        u16_t range_max;
+    } gen_power_range_set;
+    struct {
+        s32_t latitude;
+        s32_t longitude;
+        s16_t altitude;
+    } gen_loc_global_set;
+    struct {
+        s16_t north;
+        s16_t east;
+        s16_t altitude;
+        u8_t  floor_number;
+        u16_t uncertainty;
+    } gen_loc_local_set;
+    struct {
+        u16_t id;
+        struct net_buf_simple *value;
+    } gen_user_prop_set;
+    struct {
+        u16_t id;
+        u8_t access;
+        struct net_buf_simple *value;
+    } gen_admin_prop_set;
+    struct {
+        u16_t id;
+        u8_t access;
+    } gen_manu_prop_set;
+} bt_mesh_gen_server_state_change_t;
+
+typedef union {
+    struct {
+        u16_t id;
+    } user_property_get;
+    struct {
+        u16_t id;
+    } admin_property_get;
+    struct {
+        u16_t id;
+    } manu_property_get;
+    struct {
+        u16_t id;
+    } client_properties_get;
+} bt_mesh_gen_server_recv_get_msg_t;
+
+typedef union {
+    struct {
+        bool op_en;
+        u8_t onoff;
+        u8_t tid;
+        u8_t trans_time;
+        u8_t delay;
+    } onoff_set;
+    struct {
+        bool  op_en;
+        s16_t level;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } level_set;
+    struct {
+        bool  op_en;
+        s32_t delta_level;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } delta_set;
+    struct {
+        bool  op_en;
+        s16_t delta_level;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } move_set;
+    struct {
+        u8_t trans_time;
+    } def_trans_time_set;
+    struct {
+        u8_t onpowerup;
+    } onpowerup_set;
+    struct {
+        bool  op_en;
+        u16_t power;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } power_level_set;
+    struct {
+        u16_t power;
+    } power_default_set;
+    struct {
+        u16_t range_min;
+        u16_t range_max;
+    } power_range_set;
+    struct {
+        s32_t latitude;
+        s32_t longitude;
+        s16_t altitude;
+    } loc_global_set;
+    struct {
+        s16_t north;
+        s16_t east;
+        s16_t altitude;
+        u8_t  floor_number;
+        u16_t uncertainty;
+    } loc_local_set;
+    struct {
+        u16_t id;
+        struct net_buf_simple *value;
+    } user_property_set;
+    struct {
+        u16_t id;
+        u8_t  access;
+        struct net_buf_simple *value;
+    } admin_property_set;
+    struct {
+        u16_t id;
+        u8_t  access;
+    } manu_property_set;
+} bt_mesh_gen_server_recv_set_msg_t;
+
+void bt_mesh_generic_server_lock(void);
+void bt_mesh_generic_server_unlock(void);
+
+void gen_onoff_publish(struct bt_mesh_model *model);
+void gen_level_publish(struct bt_mesh_model *model);
+void gen_onpowerup_publish(struct bt_mesh_model *model);
+void gen_power_level_publish(struct bt_mesh_model *model, u16_t opcode);
+
+int bt_mesh_gen_onoff_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_level_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_def_trans_time_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_power_onoff_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_power_onoff_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_power_level_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_power_level_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_battery_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_location_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_location_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_user_prop_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_admin_prop_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_manu_prop_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_gen_client_prop_srv_init(struct bt_mesh_model *model, bool primary);
+
+#endif /* _GENERIC_SERVER_H_ */

+ 516 - 0
components/bt/esp_ble_mesh/mesh_models/server/include/lighting_server.h

@@ -0,0 +1,516 @@
+/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
+ *
+ * Copyright (c) 2018 Vikrant More
+ * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _LIGHTING_SERVER_H_
+#define _LIGHTING_SERVER_H_
+
+#include "server_common.h"
+
+struct bt_mesh_light_lightness_state {
+    u16_t lightness_linear;
+    u16_t target_lightness_linear;
+
+    u16_t lightness_actual;
+    u16_t target_lightness_actual;
+
+    u16_t lightness_last;
+    u16_t lightness_default;
+
+    u8_t  status_code;
+    u16_t lightness_range_min;
+    u16_t lightness_range_max;
+};
+
+struct bt_mesh_light_lightness_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_lightness_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition actual_transition;
+    struct bt_mesh_state_transition linear_transition;
+    s32_t tt_delta_lightness_actual;
+    s32_t tt_delta_lightness_linear;
+};
+
+struct bt_mesh_light_lightness_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_lightness_state *state;
+};
+
+struct bt_mesh_light_ctl_state {
+    u16_t lightness;
+    u16_t target_lightness;
+
+    u16_t temperature;
+    u16_t target_temperature;
+
+    s16_t delta_uv;
+    s16_t target_delta_uv;
+
+    u8_t  status_code;
+    u16_t temperature_range_min;
+    u16_t temperature_range_max;
+
+    u16_t lightness_default;
+    u16_t temperature_default;
+    s16_t delta_uv_default;
+};
+
+struct bt_mesh_light_ctl_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_ctl_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+    s32_t tt_delta_lightness;
+    s32_t tt_delta_temperature;
+    s32_t tt_delta_delta_uv;
+};
+
+struct bt_mesh_light_ctl_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_ctl_state *state;
+};
+
+struct bt_mesh_light_ctl_temp_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_ctl_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+    s32_t tt_delta_temperature;
+    s32_t tt_delta_delta_uv;
+};
+
+struct bt_mesh_light_hsl_state {
+    u16_t lightness;
+    u16_t target_lightness;
+
+    u16_t hue;
+    u16_t target_hue;
+
+    u16_t saturation;
+    u16_t target_saturation;
+
+    u16_t lightness_default;
+    u16_t hue_default;
+    u16_t saturation_default;
+
+    u8_t  status_code;
+    u16_t hue_range_min;
+    u16_t hue_range_max;
+    u16_t saturation_range_min;
+    u16_t saturation_range_max;
+};
+
+struct bt_mesh_light_hsl_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_hsl_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+    s32_t tt_delta_lightness;
+    s32_t tt_delta_hue;
+    s32_t tt_delta_saturation;
+};
+
+struct bt_mesh_light_hsl_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_hsl_state *state;
+};
+
+struct bt_mesh_light_hsl_hue_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_hsl_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+    s32_t tt_delta_hue;
+};
+
+struct bt_mesh_light_hsl_sat_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_hsl_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+    s32_t tt_delta_saturation;
+};
+
+struct bt_mesh_light_xyl_state {
+    u16_t lightness;
+    u16_t target_lightness;
+
+    u16_t x;
+    u16_t target_x;
+
+    u16_t y;
+    u16_t target_y;
+
+    u16_t lightness_default;
+    u16_t x_default;
+    u16_t y_default;
+
+    u8_t  status_code;
+    u16_t x_range_min;
+    u16_t x_range_max;
+    u16_t y_range_min;
+    u16_t y_range_max;
+};
+
+struct bt_mesh_light_xyl_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_xyl_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+    s32_t tt_delta_lightness;
+    s32_t tt_delta_x;
+    s32_t tt_delta_y;
+};
+
+struct bt_mesh_light_xyl_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_xyl_state *state;
+};
+
+struct bt_mesh_light_lc_state {
+    u32_t mode : 1,                 /* default 0 */
+          occupancy_mode : 1,       /* default 1 */
+          light_onoff : 1,
+          target_light_onoff : 1,
+          occupancy : 1,
+          ambient_luxlevel : 24;    /* 0x000000 ~ 0xFFFFFF */
+
+    u16_t linear_output;            /* 0x0000 ~ 0xFFFF */
+};
+
+struct bt_mesh_light_lc_property_state {
+    u32_t time_occupancy_delay;         /* 0x003A */
+    u32_t time_fade_on;                 /* 0x0037 */
+    u32_t time_run_on;                  /* 0x003C */
+    u32_t time_fade;                    /* 0x0036 */
+    u32_t time_prolong;                 /* 0x003B */
+    u32_t time_fade_standby_auto;       /* 0x0038 */
+    u32_t time_fade_standby_manual;     /* 0x0039 */
+
+    u16_t lightness_on;                 /* 0x002E */
+    u16_t lightness_prolong;            /* 0x002F */
+    u16_t lightness_standby;            /* 0x0030 */
+
+    u16_t ambient_luxlevel_on;          /* 0x002B, 0x0000 ~ 0xFFFF */
+    u16_t ambient_luxlevel_prolong;     /* 0x002C, 0x0000 ~ 0xFFFF */
+    u16_t ambient_luxlevel_standby;     /* 0x002D, 0x0000 ~ 0xFFFF */
+
+    float regulator_kiu;                /* 0x0033, 0.0 ~ 1000.0, default 250.0 */
+    float regulator_kid;                /* 0x0032, 0.0 ~ 1000.0, default 25.0 */
+    float regulator_kpu;                /* 0x0035, 0.0 ~ 1000.0, default 80.0 */
+    float regulator_kpd;                /* 0x0034, 0.0 ~ 1000.0, default 80.0 */
+    s8_t  regulator_accuracy;           /* 0x0031, 0.0 ~ 100.0, default 2.0 */
+
+    u32_t set_occupancy_to_1_delay;
+};
+
+typedef enum {
+    LC_OFF,
+    LC_STANDBY,
+    LC_FADE_ON,
+    LC_RUN,
+    LC_FADE,
+    LC_PROLONG,
+    LC_FADE_STANDBY_AUTO,
+    LC_FADE_STANDBY_MANUAL,
+} bt_mesh_lc_state;
+
+struct bt_mesh_light_lc_state_machine {
+    struct {
+        u8_t fade_on;
+        u8_t fade;
+        u8_t fade_standby_auto;
+        u8_t fade_standby_manual;
+    } trans_time;
+    bt_mesh_lc_state state;
+    struct k_delayed_work timer;
+};
+
+struct bt_mesh_light_control {
+    struct bt_mesh_light_lc_state          state;
+    struct bt_mesh_light_lc_property_state prop_state;
+    struct bt_mesh_light_lc_state_machine  state_machine;
+};
+
+struct bt_mesh_light_lc_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_control *lc;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+};
+
+struct bt_mesh_light_lc_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_light_control *lc;
+};
+
+typedef union {
+    struct {
+        u16_t lightness;
+    } lightness_set;
+    struct {
+        u16_t lightness;
+    } lightness_linear_set;
+    struct {
+        u16_t lightness;
+    } lightness_default_set;
+    struct {
+        u16_t range_min;
+        u16_t range_max;
+    } lightness_range_set;
+    struct {
+        u16_t lightness;
+        u16_t temperature;
+        s16_t delta_uv;
+    } ctl_set;
+    struct {
+        u16_t temperature;
+        s16_t delta_uv;
+    } ctl_temp_set;
+    struct {
+        u16_t range_min;
+        u16_t range_max;
+    } ctl_temp_range_set;
+    struct {
+        u16_t lightness;
+        u16_t temperature;
+        s16_t delta_uv;
+    } ctl_default_set;
+    struct {
+        u16_t lightness;
+        u16_t hue;
+        u16_t saturation;
+    } hsl_set;
+    struct {
+        u16_t hue;
+    } hsl_hue_set;
+    struct {
+        u16_t saturation;
+    } hsl_saturation_set;
+    struct {
+        u16_t lightness;
+        u16_t hue;
+        u16_t saturation;
+    } hsl_default_set;
+    struct {
+        u16_t hue_range_min;
+        u16_t hue_range_max;
+        u16_t sat_range_min;
+        u16_t sat_range_max;
+    } hsl_range_set;
+    struct {
+        u16_t lightness;
+        u16_t x;
+        u16_t y;
+    } xyl_set;
+    struct {
+        u16_t lightness;
+        u16_t x;
+        u16_t y;
+    } xyl_default_set;
+    struct {
+        u16_t x_range_min;
+        u16_t x_range_max;
+        u16_t y_range_min;
+        u16_t y_range_max;
+    } xyl_range_set;
+    struct {
+        u8_t mode;
+    } lc_mode_set;
+    struct {
+        u8_t mode;
+    } lc_om_set;
+    struct {
+        u8_t onoff;
+    } lc_light_onoff_set;
+    struct {
+        u16_t id;
+        struct net_buf_simple *value;
+    } lc_property_set;
+    struct {
+        u16_t property_id;
+        union {
+            u8_t  occupancy;
+            u32_t set_occupancy_to_1_delay;
+            u32_t ambient_luxlevel;
+        } state;
+    } sensor_status;
+} bt_mesh_light_server_state_change_t;
+
+typedef union {
+    struct {
+        u16_t id;
+    } lc_property_get;
+} bt_mesh_light_server_recv_get_msg_t;
+
+typedef union {
+    struct {
+        bool  op_en;
+        u16_t lightness;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } lightness_set;
+    struct {
+        bool  op_en;
+        u16_t lightness;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } lightness_linear_set;
+    struct {
+        u16_t lightness;
+    } lightness_default_set;
+    struct {
+        u16_t range_min;
+        u16_t range_max;
+    } lightness_range_set;
+    struct {
+        bool  op_en;
+        u16_t lightness;
+        u16_t temperature;
+        s16_t delta_uv;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } ctl_set;
+    struct {
+        bool  op_en;
+        u16_t temperature;
+        s16_t delta_uv;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } ctl_temp_set;
+    struct {
+        u16_t range_min;
+        u16_t range_max;
+    } ctl_temp_range_set;
+    struct {
+        u16_t lightness;
+        u16_t temperature;
+        s16_t delta_uv;
+    } ctl_default_set;
+    struct {
+        bool  op_en;
+        u16_t lightness;
+        u16_t hue;
+        u16_t saturation;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } hsl_set;
+    struct {
+        bool  op_en;
+        u16_t hue;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } hsl_hue_set;
+    struct {
+        bool  op_en;
+        u16_t saturation;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } hsl_saturation_set;
+    struct {
+        u16_t lightness;
+        u16_t hue;
+        u16_t saturation;
+    } hsl_default_set;
+    struct {
+        u16_t hue_range_min;
+        u16_t hue_range_max;
+        u16_t sat_range_min;
+        u16_t sat_range_max;
+    } hsl_range_set;
+    struct {
+        bool  op_en;
+        u16_t lightness;
+        u16_t x;
+        u16_t y;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } xyl_set;
+    struct {
+        u16_t lightness;
+        u16_t x;
+        u16_t y;
+    } xyl_default_set;
+    struct {
+        u16_t x_range_min;
+        u16_t x_range_max;
+        u16_t y_range_min;
+        u16_t y_range_max;
+    } xyl_range_set;
+    struct {
+        u8_t mode;
+    } lc_mode_set;
+    struct {
+        u8_t mode;
+    } lc_om_set;
+    struct {
+        bool op_en;
+        u8_t light_onoff;
+        u8_t tid;
+        u8_t trans_time;
+        u8_t delay;
+    } lc_light_onoff_set;
+    struct {
+        u16_t id;
+        struct net_buf_simple *value;
+    } lc_property_set;
+} bt_mesh_light_server_recv_set_msg_t;
+
+typedef union {
+    struct {
+        struct net_buf_simple *data;
+    } sensor_status;
+} bt_mesh_light_server_recv_status_msg_t;
+
+void bt_mesh_light_server_lock(void);
+void bt_mesh_light_server_unlock(void);
+
+u8_t *bt_mesh_get_lc_prop_value(struct bt_mesh_model *model, u16_t prop_id);
+
+void light_lightness_publish(struct bt_mesh_model *model, u16_t opcode);
+void light_ctl_publish(struct bt_mesh_model *model, u16_t opcode);
+void light_hsl_publish(struct bt_mesh_model *model, u16_t opcode);
+void light_xyl_publish(struct bt_mesh_model *model, u16_t opcode);
+void light_lc_publish(struct bt_mesh_model *model, u16_t opcode);
+
+int bt_mesh_light_lightness_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_lightness_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_ctl_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_ctl_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_ctl_temp_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_hsl_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_hsl_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_hsl_hue_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_hsl_sat_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_xyl_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_xyl_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_lc_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_light_lc_setup_srv_init(struct bt_mesh_model *model, bool primary);
+
+#endif /* _LIGHTING_SERVER_H_ */

+ 249 - 0
components/bt/esp_ble_mesh/mesh_models/server/include/sensor_server.h

@@ -0,0 +1,249 @@
+// Copyright 2017-2019 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.
+
+#ifndef _SENSOR_SERVER_H_
+#define _SENSOR_SERVER_H_
+
+#include "server_common.h"
+
+/* Sensor Property ID related */
+#define INVALID_SENSOR_PROPERTY_ID          0x0000
+
+#define SENSOR_PROPERTY_ID_LEN              0x02
+
+/* Sensor Descriptor state related */
+#define SENSOR_DESCRIPTOR_LEN               0x08
+
+#define SENSOR_UNSPECIFIED_POS_TOLERANCE    0x000
+#define SENSOR_UNSPECIFIED_NEG_TOLERANCE    0x000
+
+#define SENSOR_NOT_APPL_MEASURE_PERIOD      0x00
+
+#define SENSOR_NOT_APPL_UPDATE_INTERVAL     0x00
+
+/* Sensor Setting state related */
+#define INVALID_SENSOR_SETTING_PROPERTY_ID  0x0000
+
+#define SENSOR_SETTING_PROPERTY_ID_LEN      0x02
+#define SENSOR_SETTING_ACCESS_LEN           0x01
+
+#define SENSOR_SETTING_ACCESS_READ          0x01
+#define SENSOR_SETTING_ACCESS_READ_WRITE    0x03
+
+/* Sensor Cadence state related */
+#define SENSOR_DIVISOR_TRIGGER_TYPE_LEN     0x01
+#define SENSOR_STATUS_MIN_INTERVAL_LEN      0x01
+
+#define SENSOR_PERIOD_DIVISOR_MAX_VALUE     15
+
+#define SENSOR_STATUS_MIN_INTERVAL_MAX      26
+
+#define SENSOR_STATUS_TRIGGER_TYPE_CHAR     0
+#define SENSOR_STATUS_TRIGGER_TYPE_UINT16   1
+
+#define SENSOR_STATUS_TRIGGER_UINT16_LEN    0x02
+
+/* Sensor Data state related */
+#define SENSOR_DATA_FORMAT_A                0x00
+#define SENSOR_DATA_FORMAT_B                0x01
+
+#define SENSOR_DATA_FORMAT_A_MPID_LEN       0x02
+#define SENSOR_DATA_FORMAT_B_MPID_LEN       0x03
+
+#define SENSOR_DATA_ZERO_LEN                0x7F
+
+enum bt_mesh_sensor_sample_func {
+    UNSPECIFIED,
+    INSTANTANEOUS,
+    ARITHMETIC_MEAN,
+    RMS,
+    MAXIMUM,
+    MINIMUM,
+    ACCUMULATED,
+    COUNT,
+};
+
+struct sensor_descriptor {
+    u32_t positive_tolerance : 12,
+          negative_tolerance : 12,
+          sample_function : 8;
+    u8_t  measure_period;
+    u8_t  update_interval;
+};
+
+struct sensor_setting {
+    u16_t property_id;
+    u8_t  access;
+    /* Or use union to include all possible types */
+    struct net_buf_simple *raw;
+};
+
+struct sensor_cadence {
+    u8_t period_divisor : 7,
+         trigger_type : 1;
+    struct net_buf_simple *trigger_delta_down;
+    struct net_buf_simple *trigger_delta_up;
+    u8_t min_interval;
+    struct net_buf_simple *fast_cadence_low;
+    struct net_buf_simple *fast_cadence_high;
+};
+
+struct sensor_data {
+    /**
+     * Format A: The Length field is a 1-based uint4 value (valid range 0x0–0xF,
+     *           representing range of 1 – 16).
+     * Format B: The Length field is a 1-based uint7 value (valid range 0x0–0x7F,
+     *           representing range of 1 – 127). The value 0x7F represents a
+     *           length of zero.
+     */
+    u8_t format : 1,
+         length : 7;
+    struct net_buf_simple *raw_value;
+};
+
+struct sensor_series_column {
+    struct net_buf_simple *raw_value_x;
+    struct net_buf_simple *column_width;
+    struct net_buf_simple *raw_value_y;
+};
+
+struct bt_mesh_sensor_state {
+    u16_t sensor_property_id;
+
+    /* Constant throughout the lifetime of an element */
+    struct sensor_descriptor descriptor;
+
+    /* Multiple Sensor Setting states may be present for each sensor.
+     * The Sensor Setting Property ID values shall be unique for each
+     * Sensor Property ID that identifies a sensor within an element.
+     */
+    const u8_t setting_count;
+    struct sensor_setting *settings;
+
+    /* The Sensor Cadence state may be not supported by sensors based
+     * on device properties referencing "non-scalar characteristics"
+     * such as "histograms" or "composite characteristics".
+     */
+    struct sensor_cadence *cadence;
+
+    struct sensor_data sensor_data;
+
+    /* Values measured by sensors may be organized as arrays (and
+     * represented as series of columns, such as histograms).
+     * 1. The Sensor Raw Value X field has a size and representation
+     *    defined by the Sensor Property ID and represents the left
+     *    corner of the column on the X axis.
+     * 2. The Sensor Column Width field has a size and representation
+     *    defined by the Sensor Property ID and represents the width
+     *    of the column on the X axis.
+     * 3. The Sensor Raw Value Y field has a size and representation
+     *    defined by the Sensor Property ID and represents the height
+     *    of the column on the Y axis.
+     * Note: Values outside the bins defined by a Sensor Property are
+     * not included. For example, if the histogram is defined as 3 bins
+     * representing “lamp operating hours in a given temperature range”
+     * and the bins are [40,60), [60, 80), and [80,100], then any hours
+     * outside that [40, 100] range would not be included.
+     */
+    struct sensor_series_column series_column;
+};
+
+/* 1. Multiple instances of the Sensor states may be present within the
+ *    same model, provided that each instance has a unique value of the
+ *    Sensor Property ID to allow the instances to be differentiated.
+ * 2. Note: The number of sensors within a multisensor is limited by the
+ *    size of the message payload for the Sensor Descriptor Status message.
+ *    A single Sensor Descriptor may be sent using a single Unsegmented
+ *    Access message. Using Segmentation and Reassembly (SAR), up to 38
+ *    Sensor Descriptor states may be sent.
+ */
+
+struct bt_mesh_sensor_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    const u8_t state_count;
+    struct bt_mesh_sensor_state *states;
+};
+
+struct bt_mesh_sensor_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    const u8_t state_count;
+    struct bt_mesh_sensor_state *states;
+};
+
+typedef union {
+    struct {
+        u16_t id;
+        u8_t  period_divisor : 7,
+              trigger_type : 1;
+        struct net_buf_simple *trigger_delta_down;
+        struct net_buf_simple *trigger_delta_up;
+        u8_t min_interval;
+        struct net_buf_simple *fast_cadence_low;
+        struct net_buf_simple *fast_cadence_high;
+    } sensor_cadence_set;
+    struct {
+        u16_t id;
+        u16_t setting_id;
+        struct net_buf_simple *value;
+    } sensor_setting_set;
+} bt_mesh_sensor_server_state_change_t;
+
+typedef union {
+    struct {
+        bool  op_en;
+        u16_t id;
+    } sensor_descriptor_get;
+    struct {
+        u16_t id;
+    } sensor_cadence_get;
+    struct {
+        u16_t id;
+    } sensor_settings_get;
+    struct {
+        u16_t id;
+        u16_t setting_id;
+    } sensor_setting_get;
+    struct {
+        bool  op_en;
+        u16_t id;
+    } sensor_get;
+    struct {
+        u16_t id;
+        struct net_buf_simple *raw_x;
+    } sensor_column_get;
+    struct {
+        bool  op_en;
+        u16_t id;
+        struct net_buf_simple *raw;
+    } sensor_series_get;
+} bt_mesh_sensor_server_recv_get_msg_t;
+
+typedef union {
+    struct {
+        u16_t id;
+        struct net_buf_simple *cadence;
+    } sensor_cadence_set;
+    struct {
+        u16_t id;
+        u16_t setting_id;
+        struct net_buf_simple *raw;
+    } sensor_setting_set;
+} bt_mesh_sensor_server_recv_set_msg_t;
+
+int bt_mesh_sensor_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_sensor_setup_srv_init(struct bt_mesh_model *model, bool primary);
+
+#endif /* _SENSOR_SERVER_H_ */

+ 127 - 0
components/bt/esp_ble_mesh/mesh_models/server/include/server_common.h

@@ -0,0 +1,127 @@
+// Copyright 2017-2019 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.
+
+#ifndef _SERVER_COMMON_H_
+#define _SERVER_COMMON_H_
+
+#include <string.h>
+#include <stdint.h>
+
+#include "mesh_buf.h"
+#include "mesh_access.h"
+#include "mesh_kernel.h"
+
+#define BLE_MESH_SERVER_RSP_MAX_LEN         384
+
+#define BLE_MESH_SERVER_TRANS_MIC_SIZE      4
+
+#define BLE_MESH_CHECK_SEND_STATUS(_func) do {                      \
+        int __status = (_func);                                     \
+        if (__status) {                                             \
+            BT_ERR("%s, Send failed, err %d", __func__, __status);  \
+        }                                                           \
+    } while(0);
+
+#define BLE_MESH_STATE_OFF                      0x00
+#define BLE_MESH_STATE_ON                       0x01
+#define BLE_MESH_STATE_RESTORE                  0x02
+
+/* Following 4 values are as per Mesh Model specification */
+#define BLE_MESH_LIGHTNESS_MIN                  0x0001
+#define BLE_MESH_LIGHTNESS_MAX                  0xFFFF
+#define BLE_MESH_TEMPERATURE_MIN                0x0320
+#define BLE_MESH_TEMPERATURE_MAX                0x4E20
+#define BLE_MESH_TEMPERATURE_UNKNOWN            0xFFFF
+
+/* Refer 7.2 of Mesh Model Specification */
+#define BLE_MESH_RANGE_UPDATE_SUCCESS           0x00
+#define BLE_MESH_CANNOT_SET_RANGE_MIN           0x01
+#define BLE_MESH_CANNOT_SET_RANGE_MAX           0x02
+
+#define BLE_MESH_UNKNOWN_REMAIN_TIME            0x3F
+#define BLE_MESH_DEVICE_SPECIFIC_RESOLUTION     10
+
+#define BLE_MESH_INVALID_DEVICE_PROPERTY_ID     0x0000
+
+enum {
+    BLE_MESH_TRANS_TIMER_START,  /* Proper transition timer has been started */
+    BLE_MESH_TRANS_FLAG_MAX,
+};
+
+struct bt_mesh_state_transition {
+    bool just_started;
+
+    u8_t  trans_time;
+    u8_t  remain_time;
+    u8_t  delay;
+    u32_t quo_tt;
+    u32_t counter;
+    u32_t total_duration;
+    s64_t start_timestamp;
+
+    BLE_MESH_ATOMIC_DEFINE(flag, BLE_MESH_TRANS_FLAG_MAX);
+    struct k_delayed_work timer;
+};
+
+struct bt_mesh_last_msg_info {
+    u8_t  tid;
+    u16_t src;
+    u16_t dst;
+    s64_t timestamp;
+};
+
+#define BLE_MESH_SERVER_RSP_BY_APP  0
+#define BLE_MESH_SERVER_AUTO_RSP    1
+
+struct bt_mesh_server_rsp_ctrl {
+    /**
+     * @brief BLE Mesh Server Response Option
+     *        1. If get_auto_rsp is set to BLE_MESH_SERVER_RSP_BY_APP, then the response
+     *           of Client Get messages need to be replied by the application;
+     *        2. If get_auto_rsp is set to BLE_MESH_SERVER_AUTO_RSP, then the response
+     *           of Client Get messages will be replied by the server models;
+     *        3. If set_auto_rsp is set to BLE_MESH_SERVER_RSP_BY_APP, then the response
+     *           of Client Set messages need to be replied by the application;
+     *        4. If set_auto_rsp is set to BLE_MESH_SERVER_AUTO_RSP, then the response
+     *           of Client Set messages will be replied by the server models;
+     *        5. If status_auto_rsp is set to BLE_MESH_SERVER_RSP_BY_APP, then the response
+     *           of Server Status messages need to be replied by the application;
+     *        6. If status_auto_rsp is set to BLE_MESH_SERVER_AUTO_RSP, then the response
+     *           of Server status messages will be replied by the server models;
+     */
+    u8_t get_auto_rsp : 1, /* Response for Client Get messages */
+         set_auto_rsp : 1, /* Response for Client Set messages */
+         status_auto_rsp : 1; /* Response for Server Status messages */
+};
+
+u8_t bt_mesh_get_default_trans_time(struct bt_mesh_model *model);
+
+int bt_mesh_get_light_lc_trans_time(struct bt_mesh_model *model, u8_t *trans_time);
+
+int bt_mesh_server_get_optional(struct bt_mesh_model *model,
+                                struct net_buf_simple *buf,
+                                u8_t *trans_time, u8_t *delay,
+                                bool *optional);
+
+void bt_mesh_server_alloc_ctx(struct k_work *work);
+
+bool bt_mesh_is_server_recv_last_msg(struct bt_mesh_last_msg_info *last,
+                                     u8_t tid, u16_t src, u16_t dst, s64_t *now);
+
+void bt_mesh_server_update_last_msg(struct bt_mesh_last_msg_info *last,
+                                    u8_t tid, u16_t src, u16_t dst, s64_t *now);
+
+struct net_buf_simple *bt_mesh_server_get_pub_msg(struct bt_mesh_model *model, u16_t msg_len);
+
+#endif /* _SERVER_COMMON_H_ */

+ 92 - 0
components/bt/esp_ble_mesh/mesh_models/server/include/state_binding.h

@@ -0,0 +1,92 @@
+/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
+ *
+ * Copyright (c) 2018 Vikrant More
+ * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _STATE_BINDING_H_
+#define _STATE_BINDING_H_
+
+typedef enum {
+    GENERIC_ONOFF_STATE,
+    GENERIC_LEVEL_STATE,
+    GENERIC_ONPOWERUP_STATE,
+    GENERIC_POWER_ACTUAL_STATE,
+    LIGHT_LIGHTNESS_ACTUAL_STATE,
+    LIGHT_LIGHTNESS_LINEAR_STATE,
+    LIGHT_CTL_LIGHTNESS_STATE,
+    LIGHT_CTL_TEMP_DELTA_UV_STATE,
+    LIGHT_HSL_LIGHTNESS_STATE,
+    LIGHT_HSL_HUE_STATE,
+    LIGHT_HSL_SATURATION_STATE,
+    LIGHT_XYL_LIGHTNESS_STATE,
+    LIGHT_LC_LIGHT_ONOFF_STATE,
+    BIND_STATE_MAX,
+} bt_mesh_server_state_type_t;
+
+typedef union {
+    struct {
+        u8_t onoff;
+    } gen_onoff;
+    struct {
+        s16_t level;
+    } gen_level;
+    struct {
+        u8_t onpowerup;
+    } gen_onpowerup;
+    struct {
+        u16_t power;
+    } gen_power_actual;
+    struct {
+        u16_t lightness;
+    } light_lightness_actual;
+    struct {
+        u16_t lightness;
+    } light_lightness_linear;
+    struct {
+        u16_t lightness;
+    } light_ctl_lightness;
+    struct {
+        u16_t temperature;
+        s16_t delta_uv;
+    } light_ctl_temp_delta_uv;
+    struct {
+        u16_t lightness;
+    } light_hsl_lightness;
+    struct {
+        u16_t hue;
+    } light_hsl_hue;
+    struct {
+        u16_t saturation;
+    } light_hsl_saturation;
+    struct {
+        u16_t lightness;
+    } light_xyl_lightness;
+    struct {
+        u8_t onoff;
+    } light_lc_light_onoff;
+} bt_mesh_server_state_value_t;
+
+u16_t bt_mesh_convert_lightness_actual_to_linear(u16_t actual);
+
+u16_t bt_mesh_convert_lightness_linear_to_actual(u16_t linear);
+
+s16_t bt_mesh_convert_temperature_to_gen_level(u16_t temp, u16_t min, u16_t max);
+
+u16_t bt_mesh_covert_gen_level_to_temperature(s16_t level, u16_t min, u16_t max);
+
+s16_t bt_mesh_convert_hue_to_level(u16_t hue);
+
+u16_t bt_mesh_convert_level_to_hue(s16_t level);
+
+s16_t bt_mesh_convert_saturation_to_level(u16_t saturation);
+
+u16_t bt_mesh_convert_level_to_saturation(s16_t level);
+
+int bt_mesh_update_binding_state(struct bt_mesh_model *model,
+                                 bt_mesh_server_state_type_t type,
+                                 bt_mesh_server_state_value_t *value);
+
+#endif /* _STATE_BINDING_H_ */

+ 91 - 0
components/bt/esp_ble_mesh/mesh_models/server/include/state_transition.h

@@ -0,0 +1,91 @@
+/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
+ *
+ * Copyright (c) 2018 Vikrant More
+ * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _STATE_TRANSITION_H_
+#define _STATE_TRANSITION_H_
+
+#include "server_common.h"
+#include "generic_server.h"
+#include "lighting_server.h"
+#include "time_scene_server.h"
+
+void bt_mesh_server_calc_remain_time(struct bt_mesh_state_transition *transition);
+
+/* APIs used to get server model transtion time values */
+
+void generic_onoff_tt_values(struct bt_mesh_gen_onoff_srv *srv,
+                             u8_t trans_time, u8_t delay);
+
+void generic_level_tt_values(struct bt_mesh_gen_level_srv *srv,
+                             u8_t trans_time, u8_t delay);
+
+void generic_power_level_tt_values(struct bt_mesh_gen_power_level_srv *srv,
+                                   u8_t trans_time, u8_t delay);
+
+void light_lightness_actual_tt_values(struct bt_mesh_light_lightness_srv *srv,
+                                      u8_t trans_time, u8_t delay);
+
+void light_lightness_linear_tt_values(struct bt_mesh_light_lightness_srv *srv,
+                                      u8_t trans_time, u8_t delay);
+
+void light_ctl_tt_values(struct bt_mesh_light_ctl_srv *srv,
+                         u8_t trans_time, u8_t delay);
+
+void light_ctl_temp_tt_values(struct bt_mesh_light_ctl_temp_srv *srv,
+                              u8_t trans_time, u8_t delay);
+
+void light_hsl_tt_values(struct bt_mesh_light_hsl_srv *srv,
+                         u8_t trans_time, u8_t delay);
+
+void light_hsl_hue_tt_values(struct bt_mesh_light_hsl_hue_srv *srv,
+                             u8_t trans_time, u8_t delay);
+
+void light_hsl_sat_tt_values(struct bt_mesh_light_hsl_sat_srv *srv,
+                             u8_t trans_time, u8_t delay);
+
+void light_xyl_tt_values(struct bt_mesh_light_xyl_srv *srv,
+                         u8_t trans_time, u8_t delay);
+
+void light_lc_tt_values(struct bt_mesh_light_lc_srv *srv,
+                        u8_t trans_time, u8_t delay);
+
+void scene_tt_values(struct bt_mesh_scene_srv *srv, u8_t trans_time, u8_t delay);
+
+/* Server model transtion timer handlers */
+
+void generic_onoff_work_handler(struct k_work *work);
+
+void generic_level_work_handler(struct k_work *work);
+
+void generic_power_level_work_handler(struct k_work *work);
+
+void light_lightness_actual_work_handler(struct k_work *work);
+
+void light_lightness_linear_work_handler(struct k_work *work);
+
+void light_ctl_work_handler(struct k_work *work);
+
+void light_ctl_temp_work_handler(struct k_work *work);
+
+void light_hsl_work_handler(struct k_work *work);
+
+void light_hsl_hue_work_handler(struct k_work *work);
+
+void light_hsl_sat_work_handler(struct k_work *work);
+
+void light_xyl_work_handler(struct k_work *work);
+
+void light_lc_work_handler(struct k_work *work);
+
+void scene_recall_work_handler(struct k_work *work);
+
+void bt_mesh_server_stop_transition(struct bt_mesh_state_transition *transition);
+
+void bt_mesh_server_start_transition(struct bt_mesh_state_transition *transition);
+
+#endif /* _STATE_TRANSITION_H_ */

+ 393 - 0
components/bt/esp_ble_mesh/mesh_models/server/include/time_scene_server.h

@@ -0,0 +1,393 @@
+// Copyright 2017-2019 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.
+
+#ifndef _TIME_SCENE_SERVER_H_
+#define _TIME_SCENE_SERVER_H_
+
+#include "mesh_slist.h"
+#include "mesh_kernel.h"
+#include "server_common.h"
+
+/**
+ * 1. Mesh defines times based on International Atomic Time (TAI). The base
+ *    representation of times is the number of seconds after 00:00:00 TAI
+ *    on 2000-01-01 (that is, 1999-12-31 T23:59:28 UTC).
+ * 2. UTC: Coordinated Universal Time. For more information, please refer
+ *    to https://time.is/zh/UTC
+ * 3. For the algorithm used for the transfer between TAI and UTC, please
+ *    refer to Mesh Model Spec Section 5.1.1
+ */
+
+#define UNKNOWN_TAI_SECONDS         0x0000000000
+#define UNKNOWN_TAI_ZONE_CHANGE     0x0000000000
+#define UNKNOWN_TAI_DELTA_CHANGE    0x0000000000
+#define TAI_UTC_DELAT_MAX_VALUE     0x7FFF
+#define TAI_SECONDS_LEN             0x05
+#define TAI_OF_ZONE_CHANGE_LEN      0x05
+#define TAI_OF_DELTA_CHANGE_LEN     0x05
+
+#define INVALID_SCENE_NUMBER        0x0000
+#define SCENE_NUMBER_LEN            0x02
+
+#define SCHEDULE_YEAR_ANY_YEAR      0x64
+
+#define SCHEDULE_DAY_ANY_DAY        0x00
+
+#define SCHEDULE_HOUR_ANY_HOUR      0x18
+#define SCHEDULE_HOUR_ONCE_A_DAY    0x19
+
+#define SCHEDULE_SEC_ANY_OF_HOUR    0x3C
+#define SCHEDULE_SEC_EVERY_15_MIN   0x3D
+#define SCHEDULE_SEC_EVERY_20_MIN   0x3E
+#define SCHEDULE_SEC_ONCE_AN_HOUR   0x3F
+
+#define SCHEDULE_SEC_ANY_OF_MIN     0x3C
+#define SCHEDULE_SEC_EVERY_15_SEC   0x3D
+#define SCHEDULE_SEC_EVERY_20_SEC   0x3E
+#define SCHEDULE_SEC_ONCE_AN_MIN    0x3F
+
+#define SCHEDULE_ACT_TURN_OFF       0x00
+#define SCHEDULE_ACT_TURN_ON        0x01
+#define SCHEDULE_ACT_SCENE_RECALL   0x02
+#define SCHEDULE_ACT_NO_ACTION      0x0F
+
+#define SCHEDULE_SCENE_NO_SCENE     0x0000
+
+#define SCHEDULE_ENTRY_MAX_INDEX    0x0F
+
+#define TIME_NONE                   0x00
+#define TIME_AUTHORITY              0x01
+#define TIME_RELAY                  0x02
+#define TIME_CLINET                 0x03
+
+#define SCENE_SUCCESS               0x00
+#define SCENE_REG_FULL              0x01
+#define SCENE_NOT_FOUND             0x02
+
+/**
+ * The Time state represents the present TAI time, the current TAI-UTC Delta
+ * and local time zone offset, and the next change to each of the latter
+ * (e.g., because of a switch from winter to summer time or an announced leap
+ * second). It consists of 10 fields with a total size of 183 bits.
+ */
+struct bt_mesh_time_state {
+    struct {
+        u8_t  tai_seconds[5];
+        u8_t  subsecond;
+        u8_t  uncertainty;
+        u8_t  time_zone_offset_curr;
+        u8_t  time_zone_offset_new;
+        u8_t  tai_zone_change[5];
+        u16_t time_authority : 1,
+              tai_utc_delta_curr : 15;
+        u16_t tai_utc_delta_new : 15;
+        u8_t  tai_delta_change[5];
+    } time;
+    u8_t time_role;
+};
+
+struct bt_mesh_time_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_time_state *state;
+};
+
+struct bt_mesh_time_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_time_state *state;
+};
+
+struct scene_register {
+    u16_t scene_number;
+    u8_t  scene_type;   /* Indicate the type of scene value */
+    /**
+     * Scene value may use a union to represent later, the union contains
+     * structures of all the model states which can be stored in a scene.
+     */
+    struct net_buf_simple *scene_value;
+};
+
+/**
+ * Scenes serve as memory banks for storage of states (e.g., a power level
+ * or a light level/color). Values of states of an element can be stored
+ * as a scene and can be recalled later from the scene memory.
+ *
+ * A scene is represented by a Scene Number, which is a 16-bit non-zero,
+ * mesh-wide value. (There can be a maximum of 65535 scenes in a mesh
+ * network.) The meaning of a scene, as well as the state storage container
+ * associated with it, are determined by a model.
+ * 
+ * The Scenes state change may start numerous parallel model transitions.
+ * In that case, each individual model handles the transition internally.
+ *
+ * The scene transition is defined as a group of individual model transitions
+ * started by a Scene Recall operation. The scene transition is in progress
+ * when at least one transition from the group of individual model transitions
+ * is in progress.
+ */
+struct bt_mesh_scenes_state {
+    const u16_t scene_count;
+    struct scene_register *scenes;
+
+    /**
+     * The Current Scene state is a 16-bit value that contains either the Scene
+     * Number of the currently active scene or a value of 0x0000 when no scene
+     * is active.
+     *
+     * When a Scene Store operation or a Scene Recall operation completes with
+     * success, the Current Scene state value shall be to the Scene Number used
+     * during that operation.
+     *
+     * When the Current Scene Number is deleted from a Scene Register state as a
+     * result of Scene Delete operation, the Current Scene state shall be set to
+     * 0x0000.
+     *
+     * When any of the element's state that is marked as “Stored with Scene” has
+     * changed not as a result of a Scene Recall operation, the value of the
+     * Current Scene state shall be set to 0x0000.
+     *
+     * When a scene transition is in progress, the value of the Current Scene
+     * state shall be set to 0x0000.
+     */
+    u16_t current_scene;
+
+    /**
+     * The Target Scene state is a 16-bit value that contains the target Scene
+     * Number when a scene transition is in progress.
+     *
+     * When the scene transition is in progress and the target Scene Number is
+     * deleted from a Scene Register state as a result of Scene Delete operation,
+     * the Target Scene state shall be set to 0x0000.
+     *
+     * When the scene transition is in progress and a new Scene Number is stored
+     * in the Scene Register as a result of Scene Store operation, the Target
+     * Scene state shall be set to the new Scene Number.
+     *
+     * When the scene transition is not in progress, the value of the Target Scene
+     * state shall be set to 0x0000.
+     */
+    u16_t target_scene;
+
+    /* Indicate the status code for the last operation */
+    u8_t status_code;
+
+    /* Indicate if scene transition is in progress */
+    bool in_progress;
+};
+
+struct bt_mesh_scene_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_scenes_state *state;
+    struct bt_mesh_last_msg_info last;
+    struct bt_mesh_state_transition transition;
+};
+
+struct bt_mesh_scene_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_scenes_state *state;
+};
+
+struct schedule_register {
+    bool in_use;
+    u64_t year : 7,
+          month : 12,
+          day : 5,
+          hour : 5,
+          minute : 6,
+          second : 6,
+          day_of_week : 7,
+          action : 4,
+          trans_time : 8;
+    u16_t scene_number;
+};
+
+struct bt_mesh_scheduler_state {
+    const u8_t schedule_count;
+    struct schedule_register *schedules; /* Up to 16 scheduled entries */
+
+    /**
+     * A recommended implementation of the Scheduler should calculate the
+     * value of the TAI Seconds of the next scheduled event and put it in
+     * a queue of scheduled events sorted by time.
+     *
+     * Every second, the first event in the queue is compared with the value
+     * of the Time state. The first event is executed if it is less than or
+     * equal to the Time state and then removed from the queue. After
+     * execution, the Repeat Flag shall be checked, and the next occurrence
+     * of the scheduled event is calculated and put in the queue.
+     *
+     * One second timeout value, and compare the first event in queue with the
+     * Time state. If it is satisfied, then execute the first event. Also the
+     * Repeat Flag need to be checked, if it is set then the event needs to
+     * be put into the end of queue.
+     *
+     * sys_slist_t event_queue;
+     *
+     * For each event_queue item, it can use the following struct:
+     * struct schedule_event {
+     *     sys_snode_t node;
+     *     u8_t event_index;
+     * };
+     *
+     * Also we need a "struct k_delayed_work track_timer" which can be used to
+     * track the schedule timer and handle proper scheduled events.
+     */
+};
+
+struct bt_mesh_scheduler_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_scheduler_state *state;
+};
+
+struct bt_mesh_scheduler_setup_srv {
+    struct bt_mesh_model *model;
+    struct bt_mesh_server_rsp_ctrl rsp_ctrl;
+    struct bt_mesh_scheduler_state *state;
+};
+
+typedef union {
+    struct {
+        u8_t  tai_seconds[5];
+        u8_t  subsecond;
+        u8_t  uncertainty;
+        u16_t time_authority : 1;
+        u16_t tai_utc_delta_curr : 15;
+        u8_t  time_zone_offset_curr;
+    } time_set;
+    struct {
+        u8_t  tai_seconds[5];
+        u8_t  subsecond;
+        u8_t  uncertainty;
+        u16_t time_authority : 1;
+        u16_t tai_utc_delta_curr : 15;
+        u8_t  time_zone_offset_curr;
+    } time_status;
+    struct {
+        u8_t time_zone_offset_new;
+        u8_t tai_zone_change[5];
+    } time_zone_set;
+    struct {
+        u16_t tai_utc_delta_new : 15;
+        u8_t  tai_delta_change[5];
+    } tai_utc_delta_set;
+    struct {
+        u8_t role;
+    } time_role_set;
+    struct {
+        u16_t scene_number;
+    } scene_store;
+    struct {
+        u16_t scene_number;
+    } scene_recall;
+    struct {
+        u16_t scene_number;
+    } scene_delete;
+    struct {
+        u64_t index : 4,
+              year : 7,
+              month : 12,
+              day : 5,
+              hour : 5,
+              minute : 6,
+              second : 6,
+              day_of_week : 7,
+              action : 4,
+              trans_time : 8;
+        u16_t scene_number;
+    } scheduler_act_set;
+} bt_mesh_time_scene_server_state_change_t;
+
+typedef union {
+    struct {
+        u8_t index;
+    } scheduler_act_get;
+} bt_mesh_time_scene_server_recv_get_msg_t;
+
+typedef union {
+    struct {
+        u8_t  tai_seconds[5];
+        u8_t  subsecond;
+        u8_t  uncertainty;
+        u16_t time_authority : 1;
+        u16_t tai_utc_delta : 15;
+        u8_t  time_zone_offset;
+    } time_set;
+    struct {
+        u8_t time_zone_offset_new;
+        u8_t tai_zone_change[5];
+    } time_zone_set;
+    struct {
+        u16_t tai_utc_delta_new : 15;
+        u16_t padding : 1;
+        u8_t tai_delta_change[5];
+    } tai_utc_delta_set;
+    struct {
+        u8_t time_role;
+    } time_role_set;
+    struct {
+        u16_t scene_number;
+    } scene_store;
+    struct {
+        bool  op_en;
+        u16_t scene_number;
+        u8_t  tid;
+        u8_t  trans_time;
+        u8_t  delay;
+    } scene_recall;
+    struct {
+        u16_t scene_number;
+    } scene_delete;
+    struct {
+        u64_t index : 4,
+              year : 7,
+              month : 12,
+              day : 5,
+              hour : 5,
+              minute : 6,
+              second : 6,
+              day_of_week : 7,
+              action : 4,
+              trans_time : 8;
+        u16_t scene_number;
+    } scheduler_act_set;
+} bt_mesh_time_scene_server_recv_set_msg_t;
+
+typedef union {
+    struct {
+        u8_t  tai_seconds[5];
+        u8_t  subsecond;
+        u8_t  uncertainty;
+        u16_t time_authority : 1;
+        u16_t tai_utc_delta : 15;
+        u8_t  time_zone_offset;
+    } time_status;
+} bt_mesh_time_scene_server_recv_status_msg_t;
+
+void bt_mesh_time_scene_server_lock(void);
+void bt_mesh_time_scene_server_unlock(void);
+
+void scene_publish(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, u16_t opcode);
+
+int bt_mesh_time_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_time_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_scene_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_scene_setup_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_scheduler_srv_init(struct bt_mesh_model *model, bool primary);
+int bt_mesh_scheduler_setup_srv_init(struct bt_mesh_model *model, bool primary);
+
+#endif /* _TIME_SCENE_SERVER_H_ */

+ 3333 - 0
components/bt/esp_ble_mesh/mesh_models/server/lighting_server.c

@@ -0,0 +1,3333 @@
+/* Bluetooth: Mesh Lighting Server Models
+ *
+ * Copyright (c) 2018 Vikrant More
+ * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "osi/mutex.h"
+
+#include "mesh_types.h"
+#include "mesh_kernel.h"
+#include "mesh_trace.h"
+#include "mesh.h"
+#include "access.h"
+#include "model_opcode.h"
+
+#include "server_common.h"
+#include "state_binding.h"
+#include "state_transition.h"
+#include "device_property.h"
+
+#include "btc_ble_mesh_lighting_model.h"
+
+static osi_mutex_t light_server_mutex;
+
+static void bt_mesh_light_server_mutex_new(void)
+{
+    if (!light_server_mutex) {
+        osi_mutex_new(&light_server_mutex);
+        __ASSERT(light_server_mutex, "%s, fail", __func__);
+    }
+}
+
+void bt_mesh_light_server_lock(void)
+{
+    osi_mutex_lock(&light_server_mutex, OSI_MUTEX_MAX_TIMEOUT);
+}
+
+void bt_mesh_light_server_unlock(void)
+{
+    osi_mutex_unlock(&light_server_mutex);
+}
+
+/* message handlers (Start) */
+
+/* Light Lightness Server/Setup Server message handlers */
+
+static void send_light_lightness_status(struct bt_mesh_model *model,
+                                        struct bt_mesh_msg_ctx *ctx,
+                                        bool publish, u16_t opcode)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 5;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, opcode);
+    switch (opcode) {
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS: {
+        struct bt_mesh_light_lightness_srv *srv = model->user_data;
+        net_buf_simple_add_le16(msg, srv->state->lightness_actual);
+        if (srv->actual_transition.counter) {
+            bt_mesh_server_calc_remain_time(&srv->actual_transition);
+            net_buf_simple_add_le16(msg, srv->state->target_lightness_actual);
+            net_buf_simple_add_u8(msg, srv->actual_transition.remain_time);
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS: {
+        struct bt_mesh_light_lightness_srv *srv = model->user_data;
+        net_buf_simple_add_le16(msg, srv->state->lightness_linear);
+        if (srv->linear_transition.counter) {
+            bt_mesh_server_calc_remain_time(&srv->linear_transition);
+            net_buf_simple_add_le16(msg, srv->state->target_lightness_linear);
+            net_buf_simple_add_u8(msg, srv->linear_transition.remain_time);
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS: {
+        struct bt_mesh_light_lightness_srv *srv = model->user_data;
+        net_buf_simple_add_le16(msg, srv->state->lightness_last);
+        break;
+    }
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
+            struct bt_mesh_light_lightness_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->lightness_default);
+        } else if (model->id == BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV) {
+            struct bt_mesh_light_lightness_setup_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->lightness_default);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
+            struct bt_mesh_light_lightness_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->lightness_range_min);
+            net_buf_simple_add_le16(msg, srv->state->lightness_range_max);
+        } else if (model->id == BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV) {
+            struct bt_mesh_light_lightness_setup_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->lightness_range_min);
+            net_buf_simple_add_le16(msg, srv->state->lightness_range_max);
+        }
+        break;
+    default:
+        BT_WARN("%s, Unknown Light Lightness status opcode 0x%04x", __func__, opcode);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void light_lightness_get(struct bt_mesh_model *model,
+                                struct bt_mesh_msg_ctx *ctx,
+                                struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lightness_srv *srv = model->user_data;
+    u16_t opcode;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS;
+        break;
+    default:
+        BT_WARN("%s, Unknown Light Lightness Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    send_light_lightness_status(model, ctx, false, opcode);
+    return;
+}
+
+void light_lightness_publish(struct bt_mesh_model *model, u16_t opcode)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV: {
+        struct bt_mesh_light_lightness_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light Lightness Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV: {
+        struct bt_mesh_light_lightness_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light Lightness Setup Server state", __func__);
+            return;
+        }
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Light Lightness Server Model 0x%04x", __func__, model->id);
+        return;
+    }
+
+    send_light_lightness_status(model, NULL, true, opcode);
+    return;
+}
+
+static void light_lightness_set(struct bt_mesh_model *model,
+                                struct bt_mesh_msg_ctx *ctx,
+                                struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lightness_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    bool optional;
+    u16_t actual;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    actual = net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .lightness_set.op_en = optional,
+            .lightness_set.lightness = actual,
+            .lightness_set.tid = tid,
+            .lightness_set.trans_time = trans_time,
+            .lightness_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET) {
+            send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
+        }
+        send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->actual_transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    if (actual) {
+        if (srv->state->lightness_range_min && actual < srv->state->lightness_range_min) {
+            actual = srv->state->lightness_range_min;
+        } else if (srv->state->lightness_range_max && actual > srv->state->lightness_range_max) {
+            actual = srv->state->lightness_range_max;
+        }
+    }
+    srv->state->target_lightness_actual = actual;
+
+    /**
+     * If the target state is equal to the current state, the transition shall not be
+     * started and is considered complete.
+     */
+    if (srv->state->target_lightness_actual != srv->state->lightness_actual) {
+        light_lightness_actual_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .lightness_set.lightness = srv->state->lightness_actual,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET) {
+            send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
+        }
+        send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->actual_transition.timer.work._reserved) {
+        memcpy(srv->actual_transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->actual_transition.counter == 0U) {
+        srv->state->lightness_actual = srv->state->target_lightness_actual;
+        /**
+         * Whenever the Light Lightness Actual state is changed with a non-transactional
+         * message or a completed sequence of transactional messages to a non-zero value,
+         * the value of the Light Lightness Last shall be set to the value of the Light
+         * Lightness Actual.
+         */
+        if (srv->state->lightness_actual) {
+            srv->state->lightness_last = srv->state->lightness_actual;
+        }
+    }
+
+    srv->actual_transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET) {
+        send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
+    }
+    send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->actual_transition);
+    return;
+}
+
+static void light_lightness_linear_set(struct bt_mesh_model *model,
+                                       struct bt_mesh_msg_ctx *ctx,
+                                       struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lightness_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    bool optional;
+    u16_t linear;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    linear = net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .lightness_linear_set.op_en = optional,
+            .lightness_linear_set.lightness = linear,
+            .lightness_linear_set.tid = tid,
+            .lightness_linear_set.trans_time = trans_time,
+            .lightness_linear_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET) {
+            send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
+        }
+        send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->linear_transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state->target_lightness_linear = linear;
+
+    /**
+     * If the target state is equal to the current state, the transition shall not
+     * be started and is considered complete.
+     */
+    if (srv->state->target_lightness_linear != srv->state->lightness_linear) {
+        light_lightness_linear_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .lightness_linear_set.lightness = srv->state->lightness_actual,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET) {
+            send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
+        }
+        send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->linear_transition.timer.work._reserved) {
+        memcpy(srv->linear_transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->linear_transition.counter == 0U) {
+        srv->state->lightness_linear = srv->state->target_lightness_linear;
+    }
+
+    srv->linear_transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET) {
+        send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
+    }
+    send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->linear_transition);
+    return;
+}
+
+static void light_lightness_default_set(struct bt_mesh_model *model,
+                                        struct bt_mesh_msg_ctx *ctx,
+                                        struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lightness_setup_srv *srv = model->user_data;
+    u16_t lightness;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    lightness = net_buf_simple_pull_le16(buf);
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .lightness_default_set.lightness = lightness,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (srv->state->lightness_default != lightness) {
+        srv->state->lightness_default = lightness;
+
+        bt_mesh_light_server_state_change_t change = {
+            .lightness_default_set.lightness = lightness,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+    }
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET) {
+        send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS);
+    }
+    send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_STATUS);
+
+    return;
+}
+
+static void light_lightness_range_set(struct bt_mesh_model *model,
+                                      struct bt_mesh_msg_ctx *ctx,
+                                      struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lightness_setup_srv *srv = model->user_data;
+    u16_t range_min, range_max;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    range_min = net_buf_simple_pull_le16(buf);
+    range_max = net_buf_simple_pull_le16(buf);
+
+    if (range_min > range_max) {
+        BT_ERR("%s, Range Min 0x%04x is greater than Range Max 0x%04x",
+            __func__, range_min, range_max);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .lightness_range_set.range_min = range_min,
+            .lightness_range_set.range_max = range_max,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    /**
+     * When a Light Lightness Setup Server receives a Light Lightness Range Set
+     * message or a Light Lightness Range Set Unacknowledged message with values
+     * that cannot be accepted, it shall set the status of the operation to a
+     * value representing the reason why the values cannot be accepted.
+     *
+     * TODO: 0x0000 for Light Range Min/Max is prohibited, but BQB test case
+     * MMDL/SR/LLNS/BI-01-C requires 'SUCCESS' when it sends a set message with
+     * Light Range Min set to 0x0000.
+     */
+#if 0
+    srv->state->status_code = BLE_MESH_RANGE_UPDATE_SUCCESS;
+#else
+    if (range_min == 0x0000) {
+        srv->state->status_code = BLE_MESH_CANNOT_SET_RANGE_MIN;
+    } else if (range_max == 0x0000) {
+        srv->state->status_code = BLE_MESH_CANNOT_SET_RANGE_MAX;
+    } else {
+        srv->state->status_code = BLE_MESH_RANGE_UPDATE_SUCCESS;
+    }
+#endif
+
+    if (range_min && srv->state->lightness_range_min != range_min) {
+        srv->state->lightness_range_min = range_min;
+    }
+
+    if (range_max && srv->state->lightness_range_max != range_max) {
+        srv->state->lightness_range_max = range_max;
+    }
+
+    bt_mesh_light_server_state_change_t change = {
+        .lightness_range_set.range_min = srv->state->lightness_range_min,
+        .lightness_range_set.range_max = srv->state->lightness_range_max,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET) {
+        send_light_lightness_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS);
+    }
+    send_light_lightness_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_STATUS);
+
+    return;
+}
+
+/* Light CTL Server/Temperature Server/Setup Server message handlers */
+
+static void send_light_ctl_status(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  bool publish, u16_t opcode)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 9;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, opcode);
+    switch (opcode) {
+    case BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS: {
+        struct bt_mesh_light_ctl_srv *srv = model->user_data;
+        net_buf_simple_add_le16(msg, srv->state->lightness);
+        net_buf_simple_add_le16(msg, srv->state->temperature);
+        if (srv->transition.counter) {
+            bt_mesh_server_calc_remain_time(&srv->transition);
+            net_buf_simple_add_le16(msg, srv->state->target_lightness);
+            net_buf_simple_add_le16(msg, srv->state->target_temperature);
+            net_buf_simple_add_u8(msg, srv->transition.remain_time);
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_CTL_SRV) {
+            struct bt_mesh_light_ctl_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->temperature_range_min);
+            net_buf_simple_add_le16(msg, srv->state->temperature_range_max);
+        } else if (model->id == BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV) {
+            struct bt_mesh_light_ctl_setup_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->temperature_range_min);
+            net_buf_simple_add_le16(msg, srv->state->temperature_range_max);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS: {
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_CTL_SRV) {
+            struct bt_mesh_light_ctl_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->lightness_default);
+            net_buf_simple_add_le16(msg, srv->state->temperature_default);
+            net_buf_simple_add_le16(msg, srv->state->delta_uv_default);
+        } else if (model->id == BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV) {
+            struct bt_mesh_light_ctl_setup_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->lightness_default);
+            net_buf_simple_add_le16(msg, srv->state->temperature_default);
+            net_buf_simple_add_le16(msg, srv->state->delta_uv_default);
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS: {
+        struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
+        net_buf_simple_add_le16(msg, srv->state->temperature);
+        net_buf_simple_add_le16(msg, srv->state->delta_uv);
+        if (srv->transition.counter) {
+            bt_mesh_server_calc_remain_time(&srv->transition);
+            net_buf_simple_add_le16(msg, srv->state->target_temperature);
+            net_buf_simple_add_le16(msg, srv->state->target_delta_uv);
+            net_buf_simple_add_u8(msg, srv->transition.remain_time);
+        }
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown Light CTL status opcode 0x%04x", __func__, opcode);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void light_ctl_get(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_server_rsp_ctrl *rsp_ctrl = NULL;
+    u16_t opcode;
+
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_SRV: {
+        struct bt_mesh_light_ctl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light CTL Server state", __func__);
+            return;
+        }
+        rsp_ctrl = &srv->rsp_ctrl;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV: {
+        struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light CTL Temperature Server state", __func__);
+            return;
+        }
+        rsp_ctrl = &srv->rsp_ctrl;
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Light CTL Server Model 0x%04x", __func__, model->id);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (rsp_ctrl->get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_LIGHT_CTL_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS;
+        break;
+    default:
+        BT_WARN("%s, Unknown Light CTL Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    send_light_ctl_status(model, ctx, false, opcode);
+    return;
+}
+
+void light_ctl_publish(struct bt_mesh_model *model, u16_t opcode)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_SRV: {
+        struct bt_mesh_light_ctl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light CTL Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV: {
+        struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light CTL Temperature Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV: {
+        struct bt_mesh_light_ctl_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light CTL Setup Server state", __func__);
+            return;
+        }
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Light CTL Server Model 0x%04x", __func__, model->id);
+        return;
+    }
+
+    send_light_ctl_status(model, NULL, true, opcode);
+    return;
+}
+
+static void light_ctl_set(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_ctl_srv *srv = model->user_data;
+    u16_t lightness, temperature;
+    u8_t tid, trans_time, delay;
+    s16_t delta_uv;
+    bool optional;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    lightness = net_buf_simple_pull_le16(buf);
+    temperature = net_buf_simple_pull_le16(buf);
+    delta_uv = (s16_t) net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (temperature < BLE_MESH_TEMPERATURE_MIN || temperature > BLE_MESH_TEMPERATURE_MAX) {
+        BT_ERR("%s, Invalid temperature 0x%04x", __func__, temperature);
+        return;
+    }
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .ctl_set.op_en = optional,
+            .ctl_set.lightness = lightness,
+            .ctl_set.temperature = temperature,
+            .ctl_set.delta_uv = delta_uv,
+            .ctl_set.tid = tid,
+            .ctl_set.trans_time = trans_time,
+            .ctl_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_SET) {
+            send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
+        }
+        send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state->target_lightness = lightness;
+    if (srv->state->temperature_range_min &&
+        srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN &&
+        temperature < srv->state->temperature_range_min) {
+        temperature = srv->state->temperature_range_min;
+    } else if (srv->state->temperature_range_max &&
+        srv->state->temperature_range_max != BLE_MESH_TEMPERATURE_UNKNOWN &&
+        temperature > srv->state->temperature_range_max) {
+        temperature = srv->state->temperature_range_max;
+    }
+    srv->state->target_temperature = temperature;
+    srv->state->target_delta_uv = delta_uv;
+
+    if (srv->state->target_lightness != srv->state->lightness ||
+        srv->state->target_temperature != srv->state->temperature ||
+        srv->state->target_delta_uv != srv->state->delta_uv) {
+        light_ctl_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .ctl_set.lightness = srv->state->lightness,
+            .ctl_set.temperature = srv->state->temperature,
+            .ctl_set.delta_uv = srv->state->delta_uv,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_SET) {
+            send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
+        }
+        send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state->lightness = srv->state->target_lightness;
+        srv->state->temperature = srv->state->target_temperature;
+        srv->state->delta_uv = srv->state->target_delta_uv;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_SET) {
+        send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
+    }
+    send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+static void light_ctl_default_set(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_ctl_setup_srv *srv = model->user_data;
+    u16_t lightness, temperature;
+    s16_t delta_uv;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    lightness = net_buf_simple_pull_le16(buf);
+    temperature = net_buf_simple_pull_le16(buf);
+    delta_uv = (s16_t) net_buf_simple_pull_le16(buf);
+
+    if (temperature < BLE_MESH_TEMPERATURE_MIN || temperature > BLE_MESH_TEMPERATURE_MAX) {
+        BT_ERR("%s, Invalid temperature 0x%04x", __func__, temperature);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .ctl_default_set.lightness = lightness,
+            .ctl_default_set.temperature = temperature,
+            .ctl_default_set.delta_uv = delta_uv,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (srv->state->temperature_range_min &&
+        srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN &&
+        temperature < srv->state->temperature_range_min) {
+        temperature = srv->state->temperature_range_min;
+    } else if (srv->state->temperature_range_max &&
+        srv->state->temperature_range_max != BLE_MESH_TEMPERATURE_UNKNOWN &&
+        temperature > srv->state->temperature_range_max) {
+        temperature = srv->state->temperature_range_max;
+    }
+
+    srv->state->lightness_default = lightness;
+    srv->state->temperature_default = temperature;
+    srv->state->delta_uv_default = delta_uv;
+
+    bt_mesh_light_server_state_change_t change = {
+        .ctl_default_set.lightness = srv->state->lightness_default,
+        .ctl_default_set.temperature = srv->state->temperature_default,
+        .ctl_default_set.delta_uv = srv->state->delta_uv_default,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET) {
+        send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS);
+    }
+    send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_STATUS);
+
+    return;
+}
+
+static void light_ctl_temp_range_set(struct bt_mesh_model *model,
+                                     struct bt_mesh_msg_ctx *ctx,
+                                     struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_ctl_setup_srv *srv = model->user_data;
+    u16_t min, max;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    min = net_buf_simple_pull_le16(buf);
+    max = net_buf_simple_pull_le16(buf);
+
+    /* This is as per 6.1.3.1 in Mesh Model Specification */
+    if (min > max ||
+        min < BLE_MESH_TEMPERATURE_MIN || (min != BLE_MESH_TEMPERATURE_UNKNOWN && min > BLE_MESH_TEMPERATURE_MAX) ||
+        max < BLE_MESH_TEMPERATURE_MIN || (max != BLE_MESH_TEMPERATURE_UNKNOWN && max > BLE_MESH_TEMPERATURE_MAX)) {
+        BT_ERR("%s, Invalid parameter, range Min 0x%04x, range max 0x%04x",
+            __func__, min, max);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .ctl_temp_range_set.range_min = min,
+            .ctl_temp_range_set.range_max = max,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (min == BLE_MESH_TEMPERATURE_UNKNOWN) {
+        srv->state->status_code = BLE_MESH_CANNOT_SET_RANGE_MIN;
+    } else if (max == BLE_MESH_TEMPERATURE_UNKNOWN ) {
+        srv->state->status_code = BLE_MESH_CANNOT_SET_RANGE_MAX;
+    } else {
+        srv->state->status_code = BLE_MESH_RANGE_UPDATE_SUCCESS;
+    }
+
+    if (min != BLE_MESH_TEMPERATURE_UNKNOWN && srv->state->temperature_range_min != min) {
+        srv->state->temperature_range_min = min;
+    }
+
+    if (max != BLE_MESH_TEMPERATURE_UNKNOWN && srv->state->temperature_range_max != max) {
+        srv->state->temperature_range_max = max;
+    }
+
+    bt_mesh_light_server_state_change_t change = {
+        .ctl_temp_range_set.range_min = srv->state->temperature_range_min,
+        .ctl_temp_range_set.range_max = srv->state->temperature_range_max,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET) {
+        send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS);
+    }
+    send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_STATUS);
+
+    return;
+}
+
+static void light_ctl_temp_set(struct bt_mesh_model *model,
+                               struct bt_mesh_msg_ctx *ctx,
+                               struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    u16_t temperature;
+    s16_t delta_uv;
+    bool optional;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    temperature = net_buf_simple_pull_le16(buf);
+    delta_uv = (s16_t) net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (temperature < BLE_MESH_TEMPERATURE_MIN || temperature > BLE_MESH_TEMPERATURE_MAX) {
+        BT_ERR("%s, Invalid temperature 0x%04x", __func__, temperature);
+        return;
+    }
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .ctl_temp_set.op_en = optional,
+            .ctl_temp_set.temperature = temperature,
+            .ctl_temp_set.delta_uv = delta_uv,
+            .ctl_temp_set.tid = tid,
+            .ctl_temp_set.trans_time = trans_time,
+            .ctl_temp_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET) {
+            send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
+        }
+        send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    if (srv->state->temperature_range_min &&
+        srv->state->temperature_range_min != BLE_MESH_TEMPERATURE_UNKNOWN &&
+        temperature < srv->state->temperature_range_min) {
+        temperature = srv->state->temperature_range_min;
+    } else if (srv->state->temperature_range_max &&
+        srv->state->temperature_range_max != BLE_MESH_TEMPERATURE_UNKNOWN &&
+        temperature > srv->state->temperature_range_max) {
+        temperature = srv->state->temperature_range_max;
+    }
+    srv->state->target_temperature = temperature;
+    srv->state->target_delta_uv = delta_uv;
+
+    if (srv->state->target_temperature != srv->state->temperature ||
+        srv->state->target_delta_uv != srv->state->delta_uv) {
+        light_ctl_temp_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .ctl_temp_set.temperature = srv->state->temperature,
+            .ctl_temp_set.delta_uv = srv->state->delta_uv,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET) {
+            send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
+        }
+        send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state->temperature = srv->state->target_temperature;
+        srv->state->delta_uv = srv->state->target_delta_uv;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET) {
+        send_light_ctl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
+    }
+    send_light_ctl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+/* Light HSL Server/Hue Server/Saturation Server/Setup Server message handlers */
+
+static void send_light_hsl_status(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  bool publish, u16_t opcode)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 9;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, opcode);
+    switch (opcode) {
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS:
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS: {
+        struct bt_mesh_light_hsl_srv *srv = model->user_data;
+        if (opcode == BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS) {
+            net_buf_simple_add_le16(msg, srv->state->lightness);
+            net_buf_simple_add_le16(msg, srv->state->hue);
+            net_buf_simple_add_le16(msg, srv->state->saturation);
+            if (srv->transition.counter) {
+                bt_mesh_server_calc_remain_time(&srv->transition);
+                net_buf_simple_add_u8(msg, srv->transition.remain_time);
+            }
+        } else if (opcode == BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS) {
+            net_buf_simple_add_le16(msg, srv->state->target_lightness);
+            net_buf_simple_add_le16(msg, srv->state->target_hue);
+            net_buf_simple_add_le16(msg, srv->state->target_saturation);
+            if (srv->transition.counter) {
+                bt_mesh_server_calc_remain_time(&srv->transition);
+                net_buf_simple_add_u8(msg, srv->transition.remain_time);
+            }
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_HSL_SRV) {
+            struct bt_mesh_light_hsl_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->lightness_default);
+            net_buf_simple_add_le16(msg, srv->state->hue_default);
+            net_buf_simple_add_le16(msg, srv->state->saturation_default);
+        } else if (model->id == BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV) {
+            struct bt_mesh_light_hsl_setup_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->lightness_default);
+            net_buf_simple_add_le16(msg, srv->state->hue_default);
+            net_buf_simple_add_le16(msg, srv->state->saturation_default);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_HSL_SRV) {
+            struct bt_mesh_light_hsl_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->hue_range_min);
+            net_buf_simple_add_le16(msg, srv->state->hue_range_max);
+            net_buf_simple_add_le16(msg, srv->state->saturation_range_min);
+            net_buf_simple_add_le16(msg, srv->state->saturation_range_max);
+        } else if (model->id == BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV) {
+            struct bt_mesh_light_hsl_setup_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->hue_range_min);
+            net_buf_simple_add_le16(msg, srv->state->hue_range_max);
+            net_buf_simple_add_le16(msg, srv->state->saturation_range_min);
+            net_buf_simple_add_le16(msg, srv->state->saturation_range_max);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS: {
+        struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
+        net_buf_simple_add_le16(msg, srv->state->hue);
+        if (srv->transition.counter) {
+            bt_mesh_server_calc_remain_time(&srv->transition);
+            net_buf_simple_add_le16(msg, srv->state->target_hue);
+            net_buf_simple_add_u8(msg, srv->transition.remain_time);
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS: {
+        struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
+        net_buf_simple_add_le16(msg, srv->state->saturation);
+        if (srv->transition.counter) {
+            bt_mesh_server_calc_remain_time(&srv->transition);
+            net_buf_simple_add_le16(msg, srv->state->target_saturation);
+            net_buf_simple_add_u8(msg, srv->transition.remain_time);
+        }
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown Light HSL status opcode 0x%04x", __func__, opcode);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void light_hsl_get(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_server_rsp_ctrl *rsp_ctrl = NULL;
+    u16_t opcode;
+
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SRV: {
+        struct bt_mesh_light_hsl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Server state", __func__);
+            return;
+        }
+        rsp_ctrl = &srv->rsp_ctrl;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV: {
+        struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Hue Server state", __func__);
+            return;
+        }
+        rsp_ctrl = &srv->rsp_ctrl;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV: {
+        struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Saturation Server state", __func__);
+            return;
+        }
+        rsp_ctrl = &srv->rsp_ctrl;
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Light HSL Server Model 0x%04x", __func__, model->id);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (rsp_ctrl->get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS;
+        break;
+    default:
+        BT_WARN("%s, Unknown Light HSL Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    send_light_hsl_status(model, ctx, false, opcode);
+    return;
+}
+
+void light_hsl_publish(struct bt_mesh_model *model, u16_t opcode)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SRV: {
+        struct bt_mesh_light_hsl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV: {
+        struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Hue Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV: {
+        struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Saturation Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV: {
+        struct bt_mesh_light_hsl_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Setup Server state", __func__);
+            return;
+        }
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Light HSL Server Model 0x%04x", __func__, model->id);
+        return;
+    }
+
+    send_light_hsl_status(model, NULL, true, opcode);
+    return;
+}
+
+static void light_hsl_set(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_hsl_srv *srv = model->user_data;
+    u16_t lightness, hue, saturation;
+    u8_t tid, trans_time, delay;
+    bool optional;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    lightness = net_buf_simple_pull_le16(buf);
+    hue = net_buf_simple_pull_le16(buf);
+    saturation = net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .hsl_set.op_en = optional,
+            .hsl_set.lightness = lightness,
+            .hsl_set.hue = hue,
+            .hsl_set.saturation = saturation,
+            .hsl_set.tid = tid,
+            .hsl_set.trans_time = trans_time,
+            .hsl_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_SET) {
+            send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
+        }
+        send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state->target_lightness = lightness;
+    if (srv->state->hue_range_min && hue < srv->state->hue_range_min) {
+        hue = srv->state->hue_range_min;
+    } else if (srv->state->hue_range_max && hue > srv->state->hue_range_max) {
+        hue = srv->state->hue_range_max;
+    }
+    srv->state->target_hue = hue;
+    if (srv->state->saturation_range_min && saturation < srv->state->saturation_range_min) {
+        saturation = srv->state->saturation_range_min;
+    } else if (srv->state->saturation_range_max && saturation > srv->state->saturation_range_max) {
+        saturation = srv->state->saturation_range_max;
+    }
+    srv->state->target_saturation = saturation;
+
+    /**
+     * If the target state is equal to the current state, the transition shall not
+     * be started and is considered complete.
+     */
+    if (srv->state->target_lightness != srv->state->lightness ||
+        srv->state->target_hue != srv->state->hue ||
+        srv->state->target_saturation != srv->state->saturation) {
+        light_hsl_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .hsl_set.lightness = srv->state->lightness,
+            .hsl_set.hue = srv->state->hue,
+            .hsl_set.saturation = srv->state->saturation,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_SET) {
+            send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
+        }
+        send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state->lightness = srv->state->target_lightness;
+        srv->state->hue = srv->state->target_hue;
+        srv->state->saturation = srv->state->target_saturation;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_SET) {
+        send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
+    }
+    send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+static void light_hsl_default_set(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_hsl_setup_srv *srv = model->user_data;
+    u16_t lightness, hue, saturation;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    lightness = net_buf_simple_pull_le16(buf);
+    hue = net_buf_simple_pull_le16(buf);
+    saturation = net_buf_simple_pull_le16(buf);
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .hsl_default_set.lightness = lightness,
+            .hsl_default_set.hue = hue,
+            .hsl_default_set.saturation = saturation,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (srv->state->hue_range_min && hue < srv->state->hue_range_min) {
+        hue = srv->state->hue_range_min;
+    } else if (srv->state->hue_range_max && hue > srv->state->hue_range_max) {
+        hue = srv->state->hue_range_max;
+    }
+
+    if (srv->state->saturation_range_min && saturation < srv->state->saturation_range_min) {
+        saturation = srv->state->saturation_range_min;
+    } else if (srv->state->saturation_range_max && saturation > srv->state->saturation_range_max) {
+        saturation = srv->state->saturation_range_max;
+    }
+
+    srv->state->lightness_default = lightness;
+    srv->state->hue_default = hue;
+    srv->state->saturation_default = saturation;
+
+    bt_mesh_light_server_state_change_t change = {
+        .hsl_default_set.lightness = srv->state->lightness_default,
+        .hsl_default_set.hue = srv->state->hue_default,
+        .hsl_default_set.saturation = srv->state->saturation_default,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET) {
+        send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS);
+    }
+    send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_STATUS);
+
+    return;
+}
+
+static void light_hsl_range_set(struct bt_mesh_model *model,
+                                struct bt_mesh_msg_ctx *ctx,
+                                struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_hsl_setup_srv *srv = model->user_data;
+    u16_t hue_min, hue_max, saturation_min, saturation_max;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    hue_min = net_buf_simple_pull_le16(buf);
+    hue_max = net_buf_simple_pull_le16(buf);
+    saturation_min = net_buf_simple_pull_le16(buf);
+    saturation_max = net_buf_simple_pull_le16(buf);
+
+    if (hue_min > hue_max) {
+        BT_ERR("%s, Invalid parameter, Hue min 0x%04x, Hue max 0x%04x",
+            __func__, hue_min, hue_max);
+        return;
+    }
+
+    if (saturation_min > saturation_max) {
+        BT_ERR("%s, Invalid parameter, Saturation min 0x%04x, Saturation max 0x%04x",
+            __func__, hue_min, hue_max);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .hsl_range_set.hue_range_min = hue_min,
+            .hsl_range_set.hue_range_max = hue_max,
+            .hsl_range_set.sat_range_min = saturation_min,
+            .hsl_range_set.sat_range_max = saturation_max,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    srv->state->status_code = BLE_MESH_RANGE_UPDATE_SUCCESS;
+    srv->state->hue_range_min = hue_min;
+    srv->state->hue_range_max = hue_max;
+    srv->state->saturation_range_min = saturation_min;
+    srv->state->saturation_range_max = saturation_max;
+
+    bt_mesh_light_server_state_change_t change = {
+        .hsl_range_set.hue_range_min = srv->state->hue_range_min,
+        .hsl_range_set.hue_range_max = srv->state->hue_range_max,
+        .hsl_range_set.sat_range_min = srv->state->saturation_range_min,
+        .hsl_range_set.sat_range_max = srv->state->saturation_range_max,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET) {
+        send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS);
+    }
+    send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_STATUS);
+
+    return;
+}
+
+static void light_hsl_hue_set(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    bool optional;
+    u16_t hue;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    hue = net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .hsl_hue_set.op_en = optional,
+            .hsl_hue_set.hue = hue,
+            .hsl_hue_set.tid = tid,
+            .hsl_hue_set.trans_time = trans_time,
+            .hsl_hue_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET) {
+            send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
+        }
+        send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    if (srv->state->hue_range_min && hue < srv->state->hue_range_min) {
+        hue = srv->state->hue_range_min;
+    } else if (srv->state->hue_range_max && hue > srv->state->hue_range_max) {
+        hue = srv->state->hue_range_max;
+    }
+    srv->state->target_hue = hue;
+
+    /**
+     * If the target state is equal to the current state, the transition shall not
+     * be started and is considered complete.
+     */
+    if (srv->state->target_hue != srv->state->hue) {
+        light_hsl_hue_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .hsl_hue_set.hue = srv->state->hue,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET) {
+            send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
+        }
+        send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state->hue = srv->state->target_hue;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET) {
+        send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
+    }
+    send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+static void light_hsl_sat_set(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    u16_t saturation;
+    bool optional;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    saturation = net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .hsl_saturation_set.op_en = optional,
+            .hsl_saturation_set.saturation = saturation,
+            .hsl_saturation_set.tid = tid,
+            .hsl_saturation_set.trans_time = trans_time,
+            .hsl_saturation_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET) {
+            send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
+        }
+        send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    if (srv->state->saturation_range_min && saturation < srv->state->saturation_range_min) {
+        saturation = srv->state->saturation_range_min;
+    } else if (srv->state->saturation_range_max && saturation > srv->state->saturation_range_max) {
+        saturation = srv->state->saturation_range_max;
+    }
+    srv->state->target_saturation = saturation;
+
+    /**
+     * If the target state is equal to the current state, the transition shall not
+     * be started and is considered complete.
+     */
+    if (srv->state->target_saturation != srv->state->saturation) {
+        light_hsl_sat_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .hsl_saturation_set.saturation = srv->state->saturation,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET) {
+            send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
+        }
+        send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state->saturation = srv->state->target_saturation;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET) {
+        send_light_hsl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
+    }
+    send_light_hsl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+/* Light xyL Server/Setup Server message handlers */
+
+static void send_light_xyl_status(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  bool publish, u16_t opcode)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 9;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, opcode);
+    switch (opcode) {
+    case BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS:
+    case BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS: {
+        struct bt_mesh_light_xyl_srv *srv = model->user_data;
+        if (opcode == BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS) {
+            net_buf_simple_add_le16(msg, srv->state->lightness);
+            net_buf_simple_add_le16(msg, srv->state->x);
+            net_buf_simple_add_le16(msg, srv->state->y);
+            if (srv->transition.counter) {
+                bt_mesh_server_calc_remain_time(&srv->transition);
+                net_buf_simple_add_u8(msg, srv->transition.remain_time);
+            }
+        } else if (opcode == BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS) {
+            net_buf_simple_add_le16(msg, srv->state->target_lightness);
+            net_buf_simple_add_le16(msg, srv->state->target_x);
+            net_buf_simple_add_le16(msg, srv->state->target_y);
+            if (srv->transition.counter) {
+                bt_mesh_server_calc_remain_time(&srv->transition);
+                net_buf_simple_add_u8(msg, srv->transition.remain_time);
+            }
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_XYL_SRV) {
+            struct bt_mesh_light_xyl_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->lightness_default);
+            net_buf_simple_add_le16(msg, srv->state->x_default);
+            net_buf_simple_add_le16(msg, srv->state->y_default);
+        } else if (model->id == BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV) {
+            struct bt_mesh_light_xyl_setup_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->lightness_default);
+            net_buf_simple_add_le16(msg, srv->state->x_default);
+            net_buf_simple_add_le16(msg, srv->state->y_default);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_XYL_SRV) {
+            struct bt_mesh_light_xyl_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->x_range_min);
+            net_buf_simple_add_le16(msg, srv->state->x_range_max);
+            net_buf_simple_add_le16(msg, srv->state->y_range_min);
+            net_buf_simple_add_le16(msg, srv->state->y_range_max);
+        } else if (model->id == BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV) {
+            struct bt_mesh_light_xyl_setup_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->status_code);
+            net_buf_simple_add_le16(msg, srv->state->x_range_min);
+            net_buf_simple_add_le16(msg, srv->state->x_range_max);
+            net_buf_simple_add_le16(msg, srv->state->y_range_min);
+            net_buf_simple_add_le16(msg, srv->state->y_range_max);
+        }
+        break;
+    default:
+        BT_WARN("%s, Unknown Light xyL status opcode 0x%04x", __func__, opcode);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void light_xyl_get(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_xyl_srv *srv = model->user_data;
+    u16_t opcode;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_LIGHT_XYL_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS;
+        break;
+    default:
+        BT_WARN("%s, Unknown Light xyL Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    send_light_xyl_status(model, ctx, false, opcode);
+    return;
+}
+
+void light_xyl_publish(struct bt_mesh_model *model, u16_t opcode)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_LIGHT_XYL_SRV: {
+        struct bt_mesh_light_xyl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light xyL Server state", __func__);
+            return;
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV: {
+        struct bt_mesh_light_xyl_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light xyL Setup Server state", __func__);
+            return;
+        }
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Light xyL Server Model 0x%04x", __func__, model->id);
+        return;
+    }
+
+    send_light_xyl_status(model, NULL, true, opcode);
+    return;
+}
+
+static void light_xyl_set(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_xyl_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    u16_t lightness, x, y;
+    bool optional;
+    s64_t now;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    lightness = net_buf_simple_pull_le16(buf);
+    x = net_buf_simple_pull_le16(buf);
+    y = net_buf_simple_pull_le16(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .xyl_set.op_en = optional,
+            .xyl_set.lightness = lightness,
+            .xyl_set.x = x,
+            .xyl_set.y = y,
+            .xyl_set.tid = tid,
+            .xyl_set.trans_time = trans_time,
+            .xyl_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_XYL_SET) {
+            send_light_xyl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
+        }
+        send_light_xyl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state->target_lightness = lightness;
+    if (srv->state->x_range_min && x < srv->state->x_range_min) {
+        x = srv->state->x_range_min;
+    } else if (srv->state->x_range_max && x > srv->state->x_range_max) {
+        x = srv->state->x_range_max;
+    }
+    srv->state->target_x = x;
+    if (srv->state->y_range_min && y < srv->state->y_range_min) {
+        y = srv->state->y_range_min;
+    } else if (srv->state->y_range_max && y > srv->state->y_range_max) {
+        y = srv->state->y_range_max;
+    }
+    srv->state->target_y = y;
+
+    /**
+     * If the target state is equal to the current state, the transition shall not
+     * be started and is considered complete.
+     */
+    if (srv->state->target_lightness != srv->state->lightness ||
+        srv->state->target_x != srv->state->x ||
+        srv->state->target_y != srv->state->y) {
+        light_xyl_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .xyl_set.lightness = srv->state->lightness,
+            .xyl_set.x = srv->state->x,
+            .xyl_set.y = srv->state->y,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_XYL_SET) {
+            send_light_xyl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
+        }
+        send_light_xyl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state->lightness = srv->state->target_lightness;
+        srv->state->x = srv->state->target_x;
+        srv->state->y = srv->state->target_y;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_XYL_SET) {
+        send_light_xyl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
+    }
+    send_light_xyl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+static void light_xyl_default_set(struct bt_mesh_model *model,
+                                  struct bt_mesh_msg_ctx *ctx,
+                                  struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_xyl_setup_srv *srv = model->user_data;
+    u16_t lightness, x, y;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    lightness = net_buf_simple_pull_le16(buf);
+    x = net_buf_simple_pull_le16(buf);
+    y = net_buf_simple_pull_le16(buf);
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .xyl_default_set.lightness = lightness,
+            .xyl_default_set.x = x,
+            .xyl_default_set.y = y,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (srv->state->x_range_min && x < srv->state->x_range_min) {
+        x = srv->state->x_range_min;
+    } else if (srv->state->x_range_max && x > srv->state->x_range_max) {
+        x = srv->state->x_range_max;
+    }
+
+    if (srv->state->y_range_min && y < srv->state->y_range_min) {
+        y = srv->state->y_range_min;
+    } else if (srv->state->y_range_max && y > srv->state->y_range_max) {
+        y = srv->state->y_range_max;
+    }
+
+    srv->state->lightness_default = lightness;
+    srv->state->x_default = x;
+    srv->state->y_default = y;
+
+    bt_mesh_light_server_state_change_t change = {
+        .xyl_default_set.lightness = srv->state->lightness_default,
+        .xyl_default_set.x = srv->state->x_default,
+        .xyl_default_set.y = srv->state->y_default,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET) {
+        send_light_xyl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS);
+    }
+    send_light_xyl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_STATUS);
+
+    return;
+}
+
+static void light_xyl_range_set(struct bt_mesh_model *model,
+                                struct bt_mesh_msg_ctx *ctx,
+                                struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_xyl_setup_srv *srv = model->user_data;
+    u16_t x_min, x_max, y_min, y_max;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    x_min = net_buf_simple_pull_le16(buf);
+    x_max = net_buf_simple_pull_le16(buf);
+    y_min = net_buf_simple_pull_le16(buf);
+    y_max = net_buf_simple_pull_le16(buf);
+
+    if (x_min > x_max) {
+        BT_ERR("%s, Invalid parameter, xyL x min 0x%04x, xyL x max 0x%04x",
+            __func__, x_min, x_max);
+        return;
+    }
+
+    if (y_min > y_max) {
+        BT_ERR("%s, Invalid parameter, xyL y min 0x%04x, xyL y max 0x%04x",
+            __func__, y_min, y_max);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .xyl_range_set.x_range_min = x_min,
+            .xyl_range_set.x_range_max = x_max,
+            .xyl_range_set.y_range_min = y_min,
+            .xyl_range_set.y_range_max = y_max,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    srv->state->status_code = BLE_MESH_RANGE_UPDATE_SUCCESS;
+    srv->state->x_range_min = x_min;
+    srv->state->x_range_max = x_max;
+    srv->state->y_range_min = y_min;
+    srv->state->y_range_max = y_max;
+
+    bt_mesh_light_server_state_change_t change = {
+        .xyl_range_set.x_range_min = srv->state->x_range_min,
+        .xyl_range_set.x_range_max = srv->state->x_range_max,
+        .xyl_range_set.y_range_min = srv->state->y_range_min,
+        .xyl_range_set.y_range_max = srv->state->y_range_max,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET) {
+        send_light_xyl_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS);
+    }
+    send_light_xyl_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_STATUS);
+
+    return;
+}
+
+/* Light LC Server/Setup Server message handlers */
+static void send_light_lc_status(struct bt_mesh_model *model,
+                                 struct bt_mesh_msg_ctx *ctx,
+                                 bool publish, u16_t opcode)
+{
+    struct bt_mesh_light_lc_srv *srv = model->user_data;
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 2 + 3;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, opcode);
+    switch (opcode) {
+    case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS:
+        net_buf_simple_add_u8(msg, srv->lc->state.mode);
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS:
+        net_buf_simple_add_u8(msg, srv->lc->state.occupancy_mode);
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS:
+        net_buf_simple_add_u8(msg, srv->lc->state.light_onoff);
+        if (srv->transition.counter) {
+            bt_mesh_server_calc_remain_time(&srv->transition);
+            net_buf_simple_add_u8(msg, srv->lc->state.target_light_onoff);
+            net_buf_simple_add_u8(msg, srv->transition.remain_time);
+        }
+        break;
+    default:
+        BT_WARN("%s, Unknown Light LC status opcode 0x%04x", __func__, opcode);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void light_lc_get(struct bt_mesh_model *model,
+                         struct bt_mesh_msg_ctx *ctx,
+                         struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lc_srv *srv = model->user_data;
+    u16_t opcode;
+
+    if (srv == NULL || srv->lc == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET:
+        opcode = BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS;
+        break;
+    default:
+        BT_WARN("%s, Unknown Light LC Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    send_light_lc_status(model, ctx, false, opcode);
+    return;
+}
+
+void light_lc_publish(struct bt_mesh_model *model, u16_t opcode)
+{
+    struct bt_mesh_light_lc_srv *srv = model->user_data;
+
+    if (srv == NULL || srv->lc == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    send_light_lc_status(model, NULL, true, opcode);
+    return;
+}
+
+static void light_lc_mode_set(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lc_srv *srv = model->user_data;
+    u8_t mode;
+
+    if (srv == NULL || srv->lc == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    mode = net_buf_simple_pull_u8(buf);
+    if (mode > BLE_MESH_STATE_ON) {
+        BT_ERR("%s, Invalid LC Mode 0x%02x", __func__, mode);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .lc_mode_set.mode = mode,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    srv->lc->state.mode = mode;
+
+    bt_mesh_light_server_state_change_t change = {
+        .lc_mode_set.mode = srv->lc->state.mode,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET) {
+        send_light_lc_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS);
+    }
+    send_light_lc_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LC_MODE_STATUS);
+
+    return;
+}
+
+static void light_lc_om_set(struct bt_mesh_model *model,
+                            struct bt_mesh_msg_ctx *ctx,
+                            struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lc_srv *srv = model->user_data;
+    u8_t om;
+
+    if (srv == NULL || srv->lc == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    om = net_buf_simple_pull_u8(buf);
+    if (om > BLE_MESH_STATE_ON) {
+        BT_ERR("%s, Invalid LC Occupancy Mode 0x%02x", __func__, om);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .lc_om_set.mode = om,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    srv->lc->state.occupancy_mode = om;
+
+    bt_mesh_light_server_state_change_t change = {
+        .lc_om_set.mode = srv->lc->state.occupancy_mode,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET) {
+        send_light_lc_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS);
+    }
+    send_light_lc_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LC_OM_STATUS);
+
+    return;
+}
+
+static void light_lc_light_onoff_set(struct bt_mesh_model *model,
+                                     struct bt_mesh_msg_ctx *ctx,
+                                     struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lc_srv *srv = model->user_data;
+    u8_t tid, trans_time, delay;
+    bool optional;
+    u8_t onoff;
+    s64_t now;
+
+    if (srv == NULL || srv->lc == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    onoff = net_buf_simple_pull_u8(buf);
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .lc_light_onoff_set.op_en = optional,
+            .lc_light_onoff_set.light_onoff = onoff,
+            .lc_light_onoff_set.tid = tid,
+            .lc_light_onoff_set.trans_time = trans_time,
+            .lc_light_onoff_set.delay = delay,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET) {
+            send_light_lc_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
+        }
+        send_light_lc_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->lc->state.target_light_onoff = onoff;
+
+    if (srv->lc->state.target_light_onoff != srv->lc->state.light_onoff) {
+        light_lc_tt_values(srv, trans_time, delay);
+    } else {
+        bt_mesh_light_server_state_change_t change = {
+            .lc_light_onoff_set.onoff = srv->lc->state.light_onoff,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET) {
+            send_light_lc_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
+        }
+        send_light_lc_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->lc->state.light_onoff = srv->lc->state.target_light_onoff;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET) {
+        send_light_lc_status(model, ctx, false, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
+    }
+    send_light_lc_status(model, NULL, true, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
+
+    bt_mesh_light_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+static void light_lc_sensor_status(struct bt_mesh_model *model,
+                                   struct bt_mesh_msg_ctx *ctx,
+                                   struct net_buf_simple *buf)
+{
+    /**
+     * When a Light LC Server receives a Sensor Status message, and if the message
+     * Raw field contains a Raw Value for the Motion Sensed Property, and the value
+     * is greater than 0, or a Raw Value for the People Count Property, and the
+     * value is greater than 0, or a Raw Value for the Presence Detected Property,
+     * and the value is greater than 0, then it shall set the Light LC Occupancy
+     * state to 0b1.
+     * If the message Raw field contains a Raw Value for the Time Since Motion Sensed
+     * device property, which represents a value less than or equal to the value of
+     * the Light LC Occupancy Delay state, it shall delay setting the Light LC Occupancy
+     * state to 0b1 by the difference between the value of the Light LC Occupancy Delay
+     * state and the received Time Since Motion value.
+     * When a Light LC Server receives a Sensor Status message, and if the message Raw
+     * field contains a Raw Value for the Present Ambient Light Level device property,
+     * it shall set the Light LC Ambient LuxLevel state to the Represented Value of the
+     * received Present Ambient Light Level.
+     * 
+     * Motion Sensed: 1 octet, 0x0042
+     * People Count: 2 octets, 0x004C
+     * Presence Detected: 1 octet, 0x004D
+     * 
+     * Time Since Motion Sensed: 2 octets, 0x0068
+     * 
+     * Present Ambient Light Level: 4 octets, 0x004E
+     */
+    struct bt_mesh_light_lc_srv *srv = model->user_data;
+    bt_mesh_light_server_state_change_t change = {0};
+    u16_t mpid, prop_id;
+    u8_t length;
+
+    if (srv == NULL || srv->lc == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    if (srv->rsp_ctrl.status_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_status_msg_t status = {
+            .sensor_status.data = buf,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_STATUS_MSG, model, ctx, (const u8_t *)&status, sizeof(status));
+        return;
+    }
+
+    mpid = net_buf_simple_pull_le16(buf);
+    if (mpid & BIT(0)) {
+        length = (u8_t)((mpid & 0xff) >> 1);
+        u8_t msb = net_buf_simple_pull_u8(buf);
+        prop_id = (u16_t)(msb << 8) | (u16_t)(mpid >> 8);
+    } else {
+        length = (u8_t)((mpid & 0x1f) >> 1);
+        prop_id = (u16_t)(mpid >> 5);
+    }
+
+    change.sensor_status.property_id = prop_id;
+
+    switch (prop_id) {
+    case BLE_MESH_MOTION_SENSED: {
+        if (length != BLE_MESH_MOTION_SENSED_LEN || length != buf->len) {
+            BT_WARN("%s, Invalid Motion Sensed Property length", __func__);
+            return;
+        }
+        u8_t val = net_buf_simple_pull_u8(buf);
+        if (val > 0) {
+            srv->lc->state.occupancy = BLE_MESH_STATE_ON;
+
+            change.sensor_status.state.occupancy = srv->lc->state.occupancy;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        }
+        break;
+    }
+    case BLE_MESH_PEOPLE_COUNT: {
+        if (length != BLE_MESH_PEOPLE_COUNT_LEN || length != buf->len) {
+            BT_WARN("%s, Invalid Motion Sensed Property length", __func__);
+            return;
+        }
+        u16_t val = net_buf_simple_pull_le16(buf);
+        if (val > 0) {
+            srv->lc->state.occupancy = BLE_MESH_STATE_ON;
+
+            change.sensor_status.state.occupancy = srv->lc->state.occupancy;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        }
+        break;
+    }
+    case BLE_MESH_PRESENCE_DETECTED: {
+        if (length != BLE_MESH_PRESENCE_DETECTED_LEN || length != buf->len) {
+            BT_WARN("%s, Invalid Motion Sensed Property length", __func__);
+            return;
+        }
+        u8_t val = net_buf_simple_pull_u8(buf);
+        if (val > 0) {
+            srv->lc->state.occupancy = BLE_MESH_STATE_ON;
+
+            change.sensor_status.state.occupancy = srv->lc->state.occupancy;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        }
+        break;
+    }
+    case BLE_MESH_TIME_SINCE_MOTION_SENSED: {
+        if (length != BLE_MESH_TIME_SINCE_MOTION_SENSED_LEN || length != buf->len) {
+            BT_WARN("%s, Invalid Motion Sensed Property length", __func__);
+            return;
+        }
+        u16_t val = net_buf_simple_pull_le16(buf);
+        if (val <= srv->lc->prop_state.time_occupancy_delay) {
+            srv->lc->prop_state.set_occupancy_to_1_delay =
+                srv->lc->prop_state.time_occupancy_delay - val;
+
+            change.sensor_status.state.set_occupancy_to_1_delay = srv->lc->prop_state.set_occupancy_to_1_delay;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        }
+        break;
+    }
+    case BLE_MESH_PRESENT_AMBIENT_LIGHT_LEVEL: {
+        /**
+         * Present Ambient Light Level device property is 4 octets, but ambient
+         * luxlevel length is 3 octets, and other devices may send Sensor Status
+         * which only contains 3 octets just for Light LC Server.
+         * Here we just check if the length is larger than 3.
+         */
+        if (buf->len < 3) {
+            BT_WARN("%s, Invalid Motion Sensed Property length", __func__);
+            return;
+        }
+        u16_t lsb = net_buf_simple_pull_le16(buf);
+        u8_t msb = net_buf_simple_pull_u8(buf);
+        srv->lc->state.ambient_luxlevel = (msb << 16) | lsb;
+
+        change.sensor_status.state.ambient_luxlevel = srv->lc->state.ambient_luxlevel;
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        break;
+    }
+    default:
+        break;
+    }
+}
+
+static u8_t *get_light_lc_prop_val(struct bt_mesh_model *model, u16_t prop_id)
+{
+    struct bt_mesh_light_lc_setup_srv *srv = model->user_data;
+    u8_t *val = NULL;
+
+    switch (prop_id) {
+    case BLE_MESH_LIGHT_CONTROL_TIME_OCCUPANCY_DELAY:
+        val = (u8_t *)&srv->lc->prop_state.time_occupancy_delay;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_TIME_FADE_ON:
+        val = (u8_t *)&srv->lc->prop_state.time_fade_on;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_TIME_RUN_ON:
+        val = (u8_t *)&srv->lc->prop_state.time_run_on;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_TIME_FADE:
+        val = (u8_t *)&srv->lc->prop_state.time_fade;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_TIME_PROLONG:
+        val = (u8_t *)&srv->lc->prop_state.time_prolong;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_TIME_FADE_STANDBY_AUTO:
+        val = (u8_t *)&srv->lc->prop_state.time_fade_standby_auto;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_TIME_FADE_STANDBY_MANUAL:
+        val = (u8_t *)&srv->lc->prop_state.time_fade_standby_manual;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_LIGHTNESS_ON:
+        val = (u8_t *)&srv->lc->prop_state.lightness_on;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_LIGHTNESS_PROLONG:
+        val = (u8_t *)&srv->lc->prop_state.lightness_prolong;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_LIGHTNESS_STANDBY:
+        val = (u8_t *)&srv->lc->prop_state.lightness_standby;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_ON:
+        val = (u8_t *)&srv->lc->prop_state.ambient_luxlevel_on;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_PROLONG:
+        val = (u8_t *)&srv->lc->prop_state.ambient_luxlevel_prolong;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_AMBIENT_LUXLEVEL_STANDBY:
+        val = (u8_t *)&srv->lc->prop_state.ambient_luxlevel_standby;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_REGULATOR_KIU:
+        val = (u8_t *)&srv->lc->prop_state.regulator_kiu;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_REGULATOR_KID:
+        val = (u8_t *)&srv->lc->prop_state.regulator_kid;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_REGULATOR_KPU:
+        val = (u8_t *)&srv->lc->prop_state.regulator_kpu;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_REGULATOR_KPD:
+        val = (u8_t *)&srv->lc->prop_state.regulator_kpd;
+        break;
+    case BLE_MESH_LIGHT_CONTROL_REGULATOR_ACCURACY:
+        val = (u8_t *)&srv->lc->prop_state.regulator_accuracy;
+        break;
+    }
+
+    return val;
+}
+
+u8_t *bt_mesh_get_lc_prop_value(struct bt_mesh_model *model, u16_t prop_id)
+{
+    if (model == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return NULL;
+    }
+
+    return get_light_lc_prop_val(model, prop_id);
+}
+
+static void send_light_lc_prop_status(struct bt_mesh_model *model,
+                                      struct bt_mesh_msg_ctx *ctx,
+                                      u16_t prop_id, bool publish)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 1 + 2 + 4;
+    u8_t *prop_val;
+
+    prop_val = get_light_lc_prop_val(model, prop_id);
+    if (prop_val == NULL) {
+        BT_ERR("%s, Failed to get Light LC Property value", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_STATUS);
+    net_buf_simple_add_le16(msg, prop_id);
+    net_buf_simple_add_mem(msg, prop_val, bt_mesh_get_dev_prop_len(prop_id));
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void light_lc_prop_get(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lc_setup_srv *srv = model->user_data;
+    u16_t prop_id;
+
+    if (srv == NULL || srv->lc == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    prop_id = net_buf_simple_pull_le16(buf);
+    if (prop_id < 0x002B || prop_id > 0x003C) {
+        BT_ERR("%s, Invalid Light LC Property ID 0x%04x", __func__, prop_id);
+        return;
+    }
+
+    /* Callback the received message to the application layer */
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_get_msg_t get = {
+            .lc_property_get.id = net_buf_simple_pull_le16(buf),
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+        return;
+    }
+
+    send_light_lc_prop_status(model, ctx, prop_id, false);
+    return;
+}
+
+static void light_lc_prop_set(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    struct bt_mesh_light_lc_setup_srv *srv = model->user_data;
+    u8_t *prop_val, expect_len;
+    u16_t prop_id;
+
+    if (srv == NULL || srv->lc == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    prop_id = net_buf_simple_pull_le16(buf);
+    if (prop_id < 0x002B || prop_id > 0x003C) {
+        BT_ERR("%s, Invalid Light LC Property ID 0x%04x", __func__, prop_id);
+        return;
+    }
+
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_light_server_recv_set_msg_t set = {
+            .lc_property_set.id = net_buf_simple_pull_le16(buf),
+            .lc_property_set.value = buf,
+        };
+        bt_mesh_lighting_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_LIGHTING_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    expect_len = bt_mesh_get_dev_prop_len(prop_id);
+    if (buf->len != expect_len) {
+        BT_ERR("%s, Invalid Light LC Property length, ID 0x%04x, expect %d, actual %d",
+            __func__, prop_id, expect_len, buf->len);
+        return;
+    }
+
+    prop_val = get_light_lc_prop_val(model, prop_id);
+    if (prop_val == NULL) {
+        BT_ERR("%s, Failed to get Light LC Property value", __func__);
+        return;
+    }
+
+    memcpy(prop_val, buf->data, buf->len);
+
+    bt_mesh_light_server_state_change_t change = {
+        .lc_property_set.id = prop_id,
+        .lc_property_set.value = buf,
+    };
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET) {
+        send_light_lc_prop_status(model, ctx, prop_id, false);
+    }
+    send_light_lc_prop_status(model, ctx, prop_id, true);
+
+    return;
+}
+
+/* message handlers (End) */
+
+/* Mapping of message handlers for Light Lightness Server (0x1300) */
+const struct bt_mesh_model_op light_lightness_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_GET,              0, light_lightness_get        },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET,              3, light_lightness_set        },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET_UNACK,        3, light_lightness_set        },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_GET,       0, light_lightness_get        },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET,       3, light_lightness_linear_set },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_SET_UNACK, 3, light_lightness_linear_set },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LAST_GET,         0, light_lightness_get        },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_GET,      0, light_lightness_get        },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_GET,        0, light_lightness_get        },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light Lightness Setup Server (0x1301) */
+const struct bt_mesh_model_op light_lightness_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET,       2, light_lightness_default_set },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_DEFAULT_SET_UNACK, 2, light_lightness_default_set },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET,         4, light_lightness_range_set   },
+    { BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_RANGE_SET_UNACK,   4, light_lightness_range_set   },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light CTL Server (0x1303) */
+const struct bt_mesh_model_op light_ctl_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_GET,                   0, light_ctl_get },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_SET,                   7, light_ctl_set },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_SET_UNACK,             7, light_ctl_set },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_GET, 0, light_ctl_get },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_GET,           0, light_ctl_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light CTL Setup Server (0x1304) */
+const struct bt_mesh_model_op light_ctl_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET,                 6, light_ctl_default_set    },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_DEFAULT_SET_UNACK,           6, light_ctl_default_set    },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET,       4, light_ctl_temp_range_set },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_RANGE_SET_UNACK, 4, light_ctl_temp_range_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light CTL Temperature Server (0x1306) */
+const struct bt_mesh_model_op light_ctl_temp_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_GET,       0, light_ctl_get      },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET,       5, light_ctl_temp_set },
+    { BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_SET_UNACK, 5, light_ctl_temp_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light HSL Server (0x1307) */
+const struct bt_mesh_model_op light_hsl_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_GET,         0, light_hsl_get },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_SET,         7, light_hsl_set },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_SET_UNACK,   7, light_hsl_set },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_TARGET_GET,  0, light_hsl_get },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_GET, 0, light_hsl_get },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_GET,   0, light_hsl_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light HSL Setup Server (0x1308) */
+const struct bt_mesh_model_op light_hsl_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET,       6, light_hsl_default_set },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_DEFAULT_SET_UNACK, 6, light_hsl_default_set },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET,         8, light_hsl_range_set   },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_RANGE_SET_UNACK,   8, light_hsl_range_set   },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light HSL Hue Server (0x130A) */
+const struct bt_mesh_model_op light_hsl_hue_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_GET,       0, light_hsl_get     },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET,       3, light_hsl_hue_set },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_SET_UNACK, 3, light_hsl_hue_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light HSL Saturation Server (0x130B) */
+const struct bt_mesh_model_op light_hsl_sat_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_GET,       0, light_hsl_get     },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET,       3, light_hsl_sat_set },
+    { BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_SET_UNACK, 3, light_hsl_sat_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light xyL Server (0x130C) */
+const struct bt_mesh_model_op light_xyl_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_GET,         0, light_xyl_get },
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_SET,         7, light_xyl_set },
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_SET_UNACK,   7, light_xyl_set },
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_TARGET_GET,  0, light_xyl_get },
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_GET, 0, light_xyl_get },
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_GET,   0, light_xyl_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light xyL Setup Server (0x130D) */
+const struct bt_mesh_model_op light_xyl_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET,       6, light_xyl_default_set },
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_DEFAULT_SET_UNACK, 6, light_xyl_default_set },
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET,         8, light_xyl_range_set   },
+    { BLE_MESH_MODEL_OP_LIGHT_XYL_RANGE_SET_UNACK,   8, light_xyl_range_set   },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light LC Server (0x130F) */
+const struct bt_mesh_model_op light_lc_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_GET,              0, light_lc_get             },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET,              1, light_lc_mode_set        },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_MODE_SET_UNACK,        1, light_lc_mode_set        },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_OM_GET,                0, light_lc_get             },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET,                1, light_lc_om_set          },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_OM_SET_UNACK,          1, light_lc_om_set          },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_GET,       0, light_lc_get             },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET,       2, light_lc_light_onoff_set },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_SET_UNACK, 2, light_lc_light_onoff_set },
+    { BLE_MESH_MODEL_OP_SENSOR_STATUS,                  3, light_lc_sensor_status   },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Light LC Setup Server (0x1310) */
+const struct bt_mesh_model_op light_lc_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_GET,       2, light_lc_prop_get },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET,       3, light_lc_prop_set },
+    { BLE_MESH_MODEL_OP_LIGHT_LC_PROPERTY_SET_UNACK, 3, light_lc_prop_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+static int light_server_init(struct bt_mesh_model *model)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, No Light Server context provided, model_id 0x%04x", __func__, model->id);
+        return -EINVAL;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV: {
+        struct bt_mesh_light_lightness_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light Lightness State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->actual_transition.timer.work);
+            bt_mesh_server_alloc_ctx(&srv->linear_transition.timer.work);
+            k_delayed_work_init(&srv->actual_transition.timer, light_lightness_actual_work_handler);
+            k_delayed_work_init(&srv->linear_transition.timer, light_lightness_linear_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV: {
+        struct bt_mesh_light_lightness_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light Lightness State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_SRV: {
+        struct bt_mesh_light_ctl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light CTL State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, light_ctl_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV: {
+        struct bt_mesh_light_ctl_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light CTL State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV: {
+        struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light CTL State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, light_ctl_temp_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SRV: {
+        struct bt_mesh_light_hsl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light HSL State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, light_hsl_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV: {
+        struct bt_mesh_light_hsl_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light HSL State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV: {
+        struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light HSL State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, light_hsl_hue_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV: {
+        struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light HSL State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, light_hsl_sat_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_XYL_SRV: {
+        struct bt_mesh_light_xyl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light xyL State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, light_xyl_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV: {
+        struct bt_mesh_light_xyl_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Light xyL State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_LC_SRV: {
+        struct bt_mesh_light_lc_srv *srv = model->user_data;
+        if (srv->lc == NULL) {
+            BT_ERR("%s, NULL Light LC State", __func__);
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, light_lc_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV: {
+        struct bt_mesh_light_lc_setup_srv *srv = model->user_data;
+        if (srv->lc == NULL) {
+            BT_ERR("%s, NULL Light LC State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown Light Server Model, model_id 0x%04x", __func__, model->id);
+        return -EINVAL;
+    }
+
+    bt_mesh_light_server_mutex_new();
+
+    return 0;
+}
+
+int bt_mesh_light_lightness_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light Lightness Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /* When this model is present on an Element, the corresponding Light Lightness
+     * Setup Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Light Lightness Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return light_server_init(model);
+}
+
+int bt_mesh_light_lightness_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    return light_server_init(model);
+}
+
+int bt_mesh_light_ctl_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light CTL Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /**
+     * When this model is present on an Element, the corresponding Light CTL
+     * Temperature Server model and the corresponding Light CTL Setup Server
+     * model shall also be present.
+     * The model requires two elements: the main element and the Temperature
+     * element. The Temperature element contains the corresponding Light CTL
+     * Temperature Server model.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Light CTL Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    if (bt_mesh_elem_count() < 2) {
+        BT_WARN("%s, Light CTL Server requires two elements", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return light_server_init(model);
+}
+
+int bt_mesh_light_ctl_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    return light_server_init(model);
+}
+
+int bt_mesh_light_ctl_temp_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light CTL Temperature Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return light_server_init(model);
+}
+
+int bt_mesh_light_hsl_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light HSL Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /**
+     * When this model is present on an Element, the corresponding Light HSL Hue
+     * Server model and the corresponding Light HSL Saturation Server model and
+     * the corresponding Light HSL Setup Server model shall also be present.
+     * The model requires three elements: the main element and the Hue element
+     * and the Saturation element. The Hue element contains the corresponding
+     * Light HSL Hue Server model, and the Saturation element contains the corr-
+     * esponding Light HSL Saturation Server model.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Light HSL Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    if (bt_mesh_elem_count() < 3) {
+        BT_WARN("%s, Light HSL Server requires three elements", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return light_server_init(model);
+}
+
+int bt_mesh_light_hsl_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    return light_server_init(model);
+}
+
+int bt_mesh_light_hsl_hue_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light HSL Hue Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return light_server_init(model);
+}
+
+int bt_mesh_light_hsl_sat_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light HSL Saturation Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return light_server_init(model);
+}
+
+int bt_mesh_light_xyl_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light xyL Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /**
+     * When this model is present on an Element, the corresponding Light xyL
+     * Setup Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Light xyL Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return light_server_init(model);
+}
+
+int bt_mesh_light_xyl_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    return light_server_init(model);
+}
+
+int bt_mesh_light_lc_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light LC Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return light_server_init(model);
+}
+
+int bt_mesh_light_lc_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Light LC Setup Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /**
+     * When this model is present on an Element, the corresponding Light LC
+     * Setup Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Light LC Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return light_server_init(model);
+}

+ 1088 - 0
components/bt/esp_ble_mesh/mesh_models/server/sensor_server.c

@@ -0,0 +1,1088 @@
+// Copyright 2017-2019 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.
+
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "mesh_types.h"
+#include "mesh_kernel.h"
+#include "mesh_trace.h"
+#include "mesh.h"
+#include "access.h"
+#include "model_opcode.h"
+#include "transport.h"
+
+#include "server_common.h"
+#include "state_binding.h"
+#include "state_transition.h"
+#include "sensor_server.h"
+#include "device_property.h"
+
+#include "btc_ble_mesh_sensor_model.h"
+
+static void update_sensor_periodic_pub(struct bt_mesh_model *model, u16_t prop_id);
+
+/* message handlers (Start) */
+
+/* Sensor Server & Sensor Setup Server message handlers */
+static void send_sensor_descriptor_status(struct bt_mesh_model *model,
+                                          struct bt_mesh_msg_ctx *ctx,
+                                          u16_t prop_id, bool get_all)
+{
+    struct bt_mesh_sensor_srv *srv = model->user_data;
+    struct bt_mesh_sensor_state *state = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t total_len = 5;
+    u8_t i;
+
+    msg = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN));
+    if (msg == NULL) {
+        BT_ERR("%s, Failed to allocate memory", __func__);
+        return;
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS);
+
+    if (get_all == true) {
+        for (i = 0U; i < srv->state_count; i++) {
+            state = &srv->states[i];
+            if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID) {
+                total_len += SENSOR_DESCRIPTOR_LEN;
+                if (total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) {
+                    /* Add this in case the message is too long */
+                    break;
+                }
+                net_buf_simple_add_le16(msg, state->sensor_property_id);
+                net_buf_simple_add_le32(msg, (state->descriptor.sample_function << 24) |
+                                             (state->descriptor.negative_tolerance << 12) |
+                                             (state->descriptor.positive_tolerance));
+                net_buf_simple_add_u8(msg, state->descriptor.measure_period);
+                net_buf_simple_add_u8(msg, state->descriptor.update_interval);
+            }
+        }
+    } else {
+        for (i = 0U; i < srv->state_count; i++) {
+            state = &srv->states[i];
+            if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+                state->sensor_property_id == prop_id) {
+                net_buf_simple_add_le16(msg, state->sensor_property_id);
+                net_buf_simple_add_le32(msg, (state->descriptor.sample_function << 24) |
+                                             (state->descriptor.negative_tolerance << 12) |
+                                             (state->descriptor.positive_tolerance));
+                net_buf_simple_add_u8(msg, state->descriptor.measure_period);
+                net_buf_simple_add_u8(msg, state->descriptor.update_interval);
+                break;
+            }
+        }
+        if (i == srv->state_count) {
+            BT_WARN("%s, Sensor Property ID 0x%04x does not exist", __func__, prop_id);
+            net_buf_simple_add_le16(msg, prop_id);
+        }
+    }
+
+    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+    bt_mesh_free_buf(msg);
+    return;
+}
+
+static void send_sensor_data_status(struct bt_mesh_model *model,
+                                    struct bt_mesh_msg_ctx *ctx,
+                                    u16_t prop_id, bool get_all)
+{
+    struct bt_mesh_sensor_srv *srv = model->user_data;
+    struct bt_mesh_sensor_state *state = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t total_len = 5;
+    u8_t i;
+
+    msg = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN));
+    if (msg == NULL) {
+        BT_ERR("%s, Failed to allocate memory", __func__);
+        return;
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SENSOR_STATUS);
+
+    if (get_all == true) {
+        for (i = 0U; i < srv->state_count; i++) {
+            state = &srv->states[i];
+            if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID) {
+                u8_t mpid_len = (state->sensor_data.format == SENSOR_DATA_FORMAT_A) ?
+                                SENSOR_DATA_FORMAT_A_MPID_LEN : SENSOR_DATA_FORMAT_B_MPID_LEN;
+                total_len += (mpid_len + (state->sensor_data.raw_value ?
+                    state->sensor_data.raw_value->len : 0));
+                if (total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) {
+                    /* Add this in case the message is too long */
+                    break;
+                }
+                if (state->sensor_data.format == SENSOR_DATA_FORMAT_A) {
+                    u16_t mpid = ((state->sensor_property_id & BIT_MASK(11)) << 5) |
+                                 ((state->sensor_data.length & BIT_MASK(4)) << 1) | state->sensor_data.format;
+                    net_buf_simple_add_le16(msg, mpid);
+                } else if (state->sensor_data.format == SENSOR_DATA_FORMAT_B) {
+                    u8_t mpid = (state->sensor_data.length << 1) | state->sensor_data.format;
+                    net_buf_simple_add_u8(msg, mpid);
+                    net_buf_simple_add_le16(msg, state->sensor_property_id);
+                }
+                if (state->sensor_data.raw_value) {
+                    net_buf_simple_add_mem(msg, state->sensor_data.raw_value->data, state->sensor_data.raw_value->len);
+                }
+            }
+        }
+    } else {
+        for (i = 0U; i < srv->state_count; i++) {
+            state = &srv->states[i];
+            if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+                state->sensor_property_id == prop_id) {
+                if (state->sensor_data.format == SENSOR_DATA_FORMAT_A) {
+                    u16_t mpid = ((state->sensor_property_id & BIT_MASK(11)) << 5) |
+                                 ((state->sensor_data.length & BIT_MASK(4)) << 1) |
+                                 state->sensor_data.format;
+                    net_buf_simple_add_le16(msg, mpid);
+                } else if (state->sensor_data.format == SENSOR_DATA_FORMAT_B) {
+                    u8_t mpid = (state->sensor_data.length << 1) | state->sensor_data.format;
+                    net_buf_simple_add_u8(msg, mpid);
+                    net_buf_simple_add_le16(msg, state->sensor_property_id);
+                }
+                if (state->sensor_data.raw_value) {
+                    net_buf_simple_add_mem(msg, state->sensor_data.raw_value->data,
+                        state->sensor_data.raw_value->len);
+                }
+                break;
+            }
+        }
+        if (i == srv->state_count) {
+            BT_WARN("%s, Sensor Property ID 0x%04x does not exist", __func__, prop_id);
+            u8_t mpid = (SENSOR_DATA_ZERO_LEN << 1) | SENSOR_DATA_FORMAT_B;
+            net_buf_simple_add_u8(msg, mpid);
+            net_buf_simple_add_le16(msg, prop_id);
+        }
+    }
+
+    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+    bt_mesh_free_buf(msg);
+    return;
+}
+
+static void send_sensor_cadence_status(struct bt_mesh_model *model,
+                                       struct bt_mesh_msg_ctx *ctx,
+                                       u16_t prop_id, bool publish)
+{
+    struct bt_mesh_sensor_setup_srv *srv = model->user_data;
+    struct bt_mesh_sensor_state *state = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t length = 0;
+    u8_t i;
+
+    for (i = 0U; i < srv->state_count; i++) {
+        state = &srv->states[i];
+        if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+            state->sensor_property_id == prop_id && state->cadence) {
+            length = SENSOR_PROPERTY_ID_LEN + 1 + 1;
+            if (state->cadence->trigger_delta_down) {
+                if (state->cadence->trigger_type == SENSOR_STATUS_TRIGGER_TYPE_CHAR) {
+                    length += state->cadence->trigger_delta_down->len;
+                } else {
+                    length += SENSOR_STATUS_TRIGGER_UINT16_LEN;
+                }
+            }
+            if (state->cadence->trigger_delta_up) {
+                if (state->cadence->trigger_type == SENSOR_STATUS_TRIGGER_TYPE_CHAR) {
+                    length += state->cadence->trigger_delta_up->len;
+                } else {
+                    length += SENSOR_STATUS_TRIGGER_UINT16_LEN;
+                }
+            }
+            if (state->cadence->fast_cadence_low) {
+                length += state->cadence->fast_cadence_low->len;
+            }
+            if (state->cadence->fast_cadence_high) {
+                length += state->cadence->fast_cadence_high->len;
+            }
+            break;
+        }
+    }
+    if (i == srv->state_count) {
+        BT_WARN("%s, Sensor Property ID 0x%04x does not exist", __func__, prop_id);
+        length = SENSOR_PROPERTY_ID_LEN;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, 1 + length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS);
+    net_buf_simple_add_le16(msg, prop_id);
+    if (i != srv->state_count) {
+        if (state->cadence) {
+            net_buf_simple_add_u8(msg, (state->cadence->trigger_type << 7) |
+                state->cadence->period_divisor);
+            if (state->cadence->trigger_delta_down) {
+                if (state->cadence->trigger_type == SENSOR_STATUS_TRIGGER_TYPE_CHAR) {
+                    net_buf_simple_add_mem(msg, state->cadence->trigger_delta_down->data,
+                        state->cadence->trigger_delta_down->len);
+                } else {
+                    net_buf_simple_add_mem(msg, state->cadence->trigger_delta_down->data,
+                        SENSOR_STATUS_TRIGGER_UINT16_LEN);
+                }
+            }
+            if (state->cadence->trigger_delta_up) {
+                if (state->cadence->trigger_type == SENSOR_STATUS_TRIGGER_TYPE_CHAR) {
+                    net_buf_simple_add_mem(msg, state->cadence->trigger_delta_up->data,
+                        state->cadence->trigger_delta_up->len);
+                } else {
+                    net_buf_simple_add_mem(msg, state->cadence->trigger_delta_up->data,
+                        SENSOR_STATUS_TRIGGER_UINT16_LEN);
+                }
+            }
+            net_buf_simple_add_u8(msg, state->cadence->min_interval);
+            if (state->cadence->fast_cadence_low) {
+                net_buf_simple_add_mem(msg, state->cadence->fast_cadence_low->data,
+                    state->cadence->fast_cadence_low->len);
+            }
+            if (state->cadence->fast_cadence_high) {
+                net_buf_simple_add_mem(msg, state->cadence->fast_cadence_high->data,
+                    state->cadence->fast_cadence_high->len);
+            }
+        }
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void send_sensor_settings_status(struct bt_mesh_model *model,
+                                        struct bt_mesh_msg_ctx *ctx,
+                                        u16_t prop_id)
+{
+    struct bt_mesh_sensor_setup_srv *srv = model->user_data;
+    struct bt_mesh_sensor_state *state = NULL;
+    struct sensor_setting *item = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t total_len = 7;
+    u8_t i, j;
+
+    msg = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN));
+    if (msg == NULL) {
+        BT_ERR("%s, Failed to allocate memory", __func__);
+        return;
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS);
+    net_buf_simple_add_le16(msg, prop_id);
+
+    for (i = 0U; i < srv->state_count; i++) {
+        state = &srv->states[i];
+        if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+            state->sensor_property_id == prop_id) {
+            for (j = 0U; j < state->setting_count; j++) {
+                item = &state->settings[j];
+                if (item->property_id != INVALID_SENSOR_SETTING_PROPERTY_ID) {
+                    total_len += SENSOR_SETTING_PROPERTY_ID_LEN;
+                    if (total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) {
+                        /* Add this in case the message is too long */
+                        break;
+                    }
+                    net_buf_simple_add_le16(msg, item->property_id);
+                }
+            }
+            break;
+        }
+    }
+    if (i == srv->state_count) {
+        BT_WARN("%s, Sensor Property ID 0x%04x does not exist", __func__, prop_id);
+    }
+
+    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+    bt_mesh_free_buf(msg);
+    return;
+}
+
+static struct sensor_setting *find_sensor_setting(struct bt_mesh_model *model,
+                                u16_t prop_id, u16_t set_prop_id)
+{
+    struct bt_mesh_sensor_setup_srv *srv = model->user_data;
+    struct bt_mesh_sensor_state *state = NULL;
+    struct sensor_setting *item = NULL;
+    u8_t i, j;
+
+    for (i = 0U; i < srv->state_count; i++) {
+        state = &srv->states[i];
+        if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+            state->sensor_property_id == prop_id) {
+            for (j = 0U; j < state->setting_count; j++) {
+                item = &state->settings[j];
+                if (item->property_id != INVALID_SENSOR_SETTING_PROPERTY_ID &&
+                    item->property_id == set_prop_id) {
+                    return item;
+                }
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static void send_sensor_setting_status(struct bt_mesh_model *model,
+                                       struct bt_mesh_msg_ctx *ctx, u16_t prop_id,
+                                       u16_t set_prop_id, bool publish)
+{
+    struct sensor_setting *item = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t length;
+
+    item = find_sensor_setting(model, prop_id, set_prop_id);
+    if (item) {
+        length = SENSOR_PROPERTY_ID_LEN + SENSOR_SETTING_PROPERTY_ID_LEN +
+            SENSOR_SETTING_ACCESS_LEN + (item->raw ? item->raw->len : 0);
+    } else {
+        /* If the message is sent as a response to the Sensor Setting Get message or
+         * a Sensor Setting Set message with an unknown Sensor Property ID field or
+         * an unknown Sensor Setting Property ID field, the Sensor Setting Access
+         * field and the Sensor Setting Raw field shall be omitted.
+         */
+        BT_WARN("%s, Sensor Setting not found, 0x%04x, 0x%04x", __func__, prop_id, set_prop_id);
+        length = SENSOR_PROPERTY_ID_LEN + SENSOR_SETTING_PROPERTY_ID_LEN;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, 1 + length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS);
+    net_buf_simple_add_le16(msg, prop_id);
+    net_buf_simple_add_le16(msg, set_prop_id);
+    if (item) {
+        /**
+         * If the message is sent as a response to the Sensor Setting Set message with
+         * a Sensor Setting Property ID field that identifies an existing Sensor Setting,
+         * and the value of the Sensor Setting Access state is 0x01 (can be read), the
+         * Sensor Setting Property ID field shall be set to the value of the Sensor
+         * Setting Property ID field of the incoming message, the Sensor Setting Access
+         * field shall be set to the value of the Sensor Setting Access state field, and
+         * the Sensor Setting Raw field shall be omitted.
+         *
+         * TODO: What if the Sensor Setting Access is Prohibited?
+         */
+        net_buf_simple_add_u8(msg, item->access);
+        if (ctx->recv_op != BLE_MESH_MODEL_OP_SENSOR_SETTING_SET ||
+            item->access == SENSOR_SETTING_ACCESS_READ_WRITE) {
+            if (item->raw) {
+                net_buf_simple_add_mem(msg, item->raw->data, item->raw->len);
+            }
+        }
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void send_sensor_column_status(struct bt_mesh_model *model,
+                                      struct bt_mesh_msg_ctx *ctx,
+                                      struct net_buf_simple *buf, u16_t prop_id)
+{
+    struct bt_mesh_sensor_srv *srv = model->user_data;
+    struct bt_mesh_sensor_state *state = NULL;
+    struct net_buf_simple *msg = NULL;
+    bool optional = false;
+    u16_t length = 0;
+    u8_t i;
+
+    for (i = 0U; i < srv->state_count; i++) {
+        state = &srv->states[i];
+        if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+            state->sensor_property_id == prop_id) {
+            length = SENSOR_PROPERTY_ID_LEN + state->series_column.raw_value_x->len;
+            /**
+             * TODO: column width & raw value y in Sensor Column Status are optional,
+             * here we need to add some conditions to decide whether put these two
+             * in the status message.
+             */
+            if (optional) {
+                length += state->series_column.column_width->len + state->series_column.raw_value_y->len;
+            }
+            break;
+        }
+    }
+    if (i == srv->state_count) {
+        BT_WARN("%s, Sensor Property ID 0x%04x does not exist", __func__, prop_id);
+        length = SENSOR_PROPERTY_ID_LEN;
+    }
+
+    msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+    if (msg == NULL) {
+        BT_ERR("%s, Failed to allocate memory", __func__);
+        return;
+    }
+
+    /**
+     * TODO: Sensor Column Get contains Raw Value X which identifies a column,
+     * we need to use this value to decide the column.
+     */
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS);
+    net_buf_simple_add_le16(msg, prop_id);
+    if (i != srv->state_count) {
+        net_buf_simple_add_mem(msg, state->series_column.raw_value_x->data,
+            state->series_column.raw_value_x->len);
+        if (optional) {
+            net_buf_simple_add_mem(msg, state->series_column.column_width->data,
+                state->series_column.column_width->len);
+            net_buf_simple_add_mem(msg, state->series_column.raw_value_y->data,
+                state->series_column.raw_value_y->len);
+        }
+    }
+
+    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+    bt_mesh_free_buf(msg);
+    return;
+}
+
+static void send_sensor_series_status(struct bt_mesh_model *model,
+                                      struct bt_mesh_msg_ctx *ctx,
+                                      struct net_buf_simple *buf, u16_t prop_id)
+{
+    struct bt_mesh_sensor_srv *srv = model->user_data;
+    struct bt_mesh_sensor_state *state = NULL;
+    struct net_buf_simple *msg = NULL;
+    bool optional = false;
+    u16_t length;
+    u8_t i;
+
+    for (i = 0U; i < srv->state_count; i++) {
+        state = &srv->states[i];
+        if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+            state->sensor_property_id == prop_id) {
+            length = SENSOR_PROPERTY_ID_LEN;
+            /* TODO: raw value x, column width & raw value y in Sensor Series
+             * Status are optional, here we need to add some conditions to
+             * decide whether put these three in the status message.
+             */
+            if (optional) {
+                length += state->series_column.raw_value_x->len +
+                        state->series_column.column_width->len +
+                        state->series_column.raw_value_y->len;
+            }
+            break;
+        }
+    }
+    if (i == srv->state_count) {
+        BT_WARN("%s, Sensor Property ID 0x%04x does not exist", __func__, prop_id);
+        length = SENSOR_PROPERTY_ID_LEN;
+    }
+
+    msg = bt_mesh_alloc_buf(1 + length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+    if (msg == NULL) {
+        BT_ERR("%s, Failed to allocate memory", __func__);
+        return;
+    }
+
+    /**
+     * TODO: Sensor Series Get may contain Raw Value X1 and Raw Value X2 which
+     * identifies a starting column and a ending column, we need to use these
+     * values to decide the columns.
+     */
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS);
+    net_buf_simple_add_le16(msg, prop_id);
+    if (i != srv->state_count) {
+        if (optional) {
+            net_buf_simple_add_mem(msg, state->series_column.raw_value_x->data,
+                state->series_column.raw_value_x->len);
+            net_buf_simple_add_mem(msg, state->series_column.column_width->data,
+                state->series_column.column_width->len);
+            net_buf_simple_add_mem(msg, state->series_column.raw_value_y->data,
+                state->series_column.raw_value_y->len);
+        }
+    }
+
+    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+    bt_mesh_free_buf(msg);
+    return;
+}
+
+static void sensor_get(struct bt_mesh_model *model,
+                       struct bt_mesh_msg_ctx *ctx,
+                       struct net_buf_simple *buf)
+{
+    u16_t set_prop_id = INVALID_SENSOR_PROPERTY_ID;
+    u16_t prop_id = INVALID_SENSOR_PROPERTY_ID;
+
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET:
+    case BLE_MESH_MODEL_OP_SENSOR_GET:
+    case BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET:
+    case BLE_MESH_MODEL_OP_SENSOR_SERIES_GET: {
+        struct bt_mesh_sensor_srv *srv = model->user_data;
+        if (srv->state_count == 0U || srv->states == NULL) {
+            BT_ERR("%s, Invalid Sensor Server state", __func__);
+            return;
+        }
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET ||
+            ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_GET) {
+            bool get_all = buf->len ? false : true;
+            if (buf->len) {
+                prop_id = net_buf_simple_pull_le16(buf);
+                if (prop_id == INVALID_SENSOR_PROPERTY_ID) {
+                    BT_ERR("%s, Prohibited Sensor Property ID 0x0000", __func__);
+                    return;
+                }
+            }
+            if (ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET) {
+                if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+                    bt_mesh_sensor_server_recv_get_msg_t get = {
+                        .sensor_descriptor_get.op_en = !get_all,
+                        .sensor_descriptor_get.id = prop_id,
+                    };
+                    bt_mesh_sensor_server_cb_evt_to_btc(
+                        BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+                } else {
+                    send_sensor_descriptor_status(model, ctx, prop_id, get_all);
+                }
+            } else {
+                if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+                    bt_mesh_sensor_server_recv_get_msg_t get = {
+                        .sensor_get.op_en = !get_all,
+                        .sensor_get.id = prop_id,
+                    };
+                    bt_mesh_sensor_server_cb_evt_to_btc(
+                        BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+                } else {
+                    send_sensor_data_status(model, ctx, prop_id, get_all);
+                }
+            }
+        } else {
+            prop_id = net_buf_simple_pull_le16(buf);
+            if (prop_id == INVALID_SENSOR_PROPERTY_ID) {
+                BT_ERR("%s, Prohibited Sensor Property ID 0x0000", __func__);
+                return;
+            }
+            if (ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET) {
+                if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+                    bt_mesh_sensor_server_recv_get_msg_t get = {
+                        .sensor_column_get.id = prop_id,
+                        .sensor_column_get.raw_x = buf,
+                    };
+                    bt_mesh_sensor_server_cb_evt_to_btc(
+                        BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+                } else {
+                    send_sensor_column_status(model, ctx, buf, prop_id);
+                }
+            } else {
+                if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+                    bt_mesh_sensor_server_recv_get_msg_t get = {
+                        .sensor_series_get.id = prop_id,
+                        .sensor_series_get.raw = buf,
+                    };
+                    bt_mesh_sensor_server_cb_evt_to_btc(
+                        BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+                } else {
+                    send_sensor_series_status(model, ctx, buf, prop_id);
+                }
+            }
+        }
+        return;
+    }
+    case BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET:
+    case BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET:
+    case BLE_MESH_MODEL_OP_SENSOR_SETTING_GET: {
+        struct bt_mesh_sensor_setup_srv *srv = model->user_data;
+        if (srv->state_count == 0U || srv->states == NULL) {
+            BT_ERR("%s, Invalid Sensor Setup Server state", __func__);
+            return;
+        }
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET ||
+            ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET) {
+            prop_id = net_buf_simple_pull_le16(buf);
+            if (prop_id == INVALID_SENSOR_PROPERTY_ID) {
+                BT_ERR("%s, Prohibited Sensor Property ID 0x0000", __func__);
+                return;
+            }
+            if (ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET) {
+                if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+                    bt_mesh_sensor_server_recv_get_msg_t get = {
+                        .sensor_cadence_get.id = prop_id,
+                    };
+                    bt_mesh_sensor_server_cb_evt_to_btc(
+                        BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+                } else {
+                    send_sensor_cadence_status(model, ctx, prop_id, false);
+                }
+            } else {
+                if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+                    bt_mesh_sensor_server_recv_get_msg_t get = {
+                        .sensor_settings_get.id = prop_id,
+                    };
+                    bt_mesh_sensor_server_cb_evt_to_btc(
+                        BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+                } else {
+                    send_sensor_settings_status(model, ctx, prop_id);
+                }
+            }
+        } else {
+            prop_id = net_buf_simple_pull_le16(buf);
+            if (prop_id == INVALID_SENSOR_PROPERTY_ID) {
+                BT_ERR("%s, Prohibited Sensor Property ID 0x0000", __func__);
+                return;
+            }
+            set_prop_id = net_buf_simple_pull_le16(buf);
+            if (set_prop_id == INVALID_SENSOR_PROPERTY_ID) {
+                BT_ERR("%s, Prohibited Sensor Setting Property ID 0x0000", __func__);
+                return;
+            }
+
+            if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+                bt_mesh_sensor_server_recv_get_msg_t get = {
+                    .sensor_setting_get.id = prop_id,
+                    .sensor_setting_get.setting_id = set_prop_id,
+                };
+                bt_mesh_sensor_server_cb_evt_to_btc(
+                    BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+            } else {
+                send_sensor_setting_status(model, ctx, prop_id, set_prop_id, false);
+            }
+        }
+        return;
+    }
+    default:
+        BT_WARN("%s, Unknown Sensor Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+}
+
+static void sensor_cadence_set(struct bt_mesh_model *model,
+                               struct bt_mesh_msg_ctx *ctx,
+                               struct net_buf_simple *buf)
+{
+    struct bt_mesh_sensor_setup_srv *srv = model->user_data;
+    bt_mesh_sensor_server_state_change_t change = {0};
+    struct bt_mesh_sensor_state *state = NULL;
+    struct bt_mesh_model *sensor_model = NULL;
+    struct bt_mesh_elem *element = NULL;
+    u16_t prop_id, trigger_len;
+    u8_t val, divisor;
+    u8_t i;
+
+    if (srv == NULL || srv->state_count == 0U || srv->states == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    prop_id = net_buf_simple_pull_le16(buf);
+    if (prop_id == INVALID_SENSOR_PROPERTY_ID) {
+        BT_ERR("%s, Prohibited Sensor Property ID 0x0000", __func__);
+        return;
+    }
+
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_sensor_server_recv_set_msg_t set = {
+            .sensor_cadence_set.id = prop_id,
+            .sensor_cadence_set.cadence = buf,
+        };
+        bt_mesh_sensor_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    for (i = 0U; i < srv->state_count; i++) {
+        state = &srv->states[i];
+        if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+            state->sensor_property_id == prop_id) {
+            break;
+        }
+    }
+    if (i == srv->state_count || state->cadence == NULL) {
+        /* When the message is sent as a response to the Sensor Cadence Get message or
+         * a Sensor Cadence Set message with an unknown Property ID field or the Sensor
+         * Server does not support the Sensor Cadence state for the sensor referred by
+         * the Property ID, the following fields shall be omitted:
+         * • Fast Cadence Period Divisor
+         * • Status Trigger Type
+         * • Status Trigger Delta Down
+         * • Status Trigger Delta Up
+         * • Status Min Interval
+         * • Fast Cadence Low
+         * • Fast Cadence High
+         */
+        send_sensor_cadence_status(model, ctx, prop_id, false);
+        return;
+    }
+
+    val = net_buf_simple_pull_u8(buf);
+    divisor = val & BIT_MASK(7);
+    if (divisor > SENSOR_PERIOD_DIVISOR_MAX_VALUE) {
+        BT_ERR("%s, Prohibited Fast Cadence Period Divisor 0x%02x", __func__, divisor);
+        return;
+    }
+    state->cadence->period_divisor = divisor;
+    state->cadence->trigger_type = (val >> 7) & BIT_MASK(1);
+
+    if (state->cadence->trigger_type == SENSOR_STATUS_TRIGGER_TYPE_CHAR) {
+        trigger_len = bt_mesh_get_dev_prop_len(prop_id);
+    } else {
+        trigger_len = SENSOR_STATUS_TRIGGER_UINT16_LEN;
+    }
+    if (buf->len < (trigger_len << 1) + SENSOR_STATUS_MIN_INTERVAL_LEN) {
+        BT_ERR("%s, Invalid Sensor Cadence Set length %d, trigger type %d",
+            __func__, buf->len + 3, state->cadence->trigger_type);
+        return;
+    }
+
+    if (state->cadence->trigger_delta_down) {
+        net_buf_simple_reset(state->cadence->trigger_delta_down);
+        net_buf_simple_add_mem(state->cadence->trigger_delta_down, buf->data, trigger_len);
+        net_buf_simple_pull_mem(buf, trigger_len);
+    }
+    if (state->cadence->trigger_delta_up) {
+        net_buf_simple_reset(state->cadence->trigger_delta_up);
+        net_buf_simple_add_mem(state->cadence->trigger_delta_up, buf->data, trigger_len);
+        net_buf_simple_pull_mem(buf, trigger_len);
+    }
+
+    /* The valid range for the Status Min Interval is 0–26 and other values are Prohibited. */
+    val = net_buf_simple_pull_u8(buf);
+    if (val > SENSOR_STATUS_MIN_INTERVAL_MAX) {
+        BT_ERR("%s, Invalid Status Min Interval %d", __func__, val);
+        return;
+    }
+    state->cadence->min_interval = val;
+
+    if (buf->len % 2) {
+        BT_ERR("%s, Different length of Fast Cadence Low & High, length %d", __func__, buf->len);
+        return;
+    }
+    if (buf->len) {
+        u8_t range_len = buf->len / 2;
+        if (state->cadence->fast_cadence_low) {
+            net_buf_simple_reset(state->cadence->fast_cadence_low);
+            net_buf_simple_add_mem(state->cadence->fast_cadence_low, buf->data, range_len);
+            net_buf_simple_pull_mem(buf, range_len);
+        }
+        if (state->cadence->fast_cadence_high) {
+            net_buf_simple_reset(state->cadence->fast_cadence_high);
+            net_buf_simple_add_mem(state->cadence->fast_cadence_high, buf->data, range_len);
+            net_buf_simple_pull_mem(buf, range_len);
+        }
+    }
+
+    change.sensor_cadence_set.id = prop_id;
+    change.sensor_cadence_set.period_divisor = state->cadence->period_divisor;
+    change.sensor_cadence_set.trigger_type = state->cadence->trigger_type;
+    change.sensor_cadence_set.trigger_delta_down = state->cadence->trigger_delta_down;
+    change.sensor_cadence_set.trigger_delta_up = state->cadence->trigger_delta_up;
+    change.sensor_cadence_set.min_interval = state->cadence->min_interval;
+    change.sensor_cadence_set.fast_cadence_low = state->cadence->fast_cadence_low;
+    change.sensor_cadence_set.fast_cadence_high = state->cadence->fast_cadence_high;
+    bt_mesh_sensor_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_SENSOR_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET) {
+        send_sensor_cadence_status(model, ctx, prop_id, false);
+    }
+    send_sensor_cadence_status(model, ctx, prop_id, true);
+
+    /* Try to find the corresponding Sensor Server Model */
+    element = bt_mesh_model_elem(model);
+    sensor_model = bt_mesh_model_find(element, BLE_MESH_MODEL_ID_SENSOR_SRV);
+    if (sensor_model == NULL) {
+        BT_WARN("%s, Sensor Server Model does not exist in the element", __func__);
+        return;
+    }
+
+    /**
+     * Based on the configured Sensor Cadence state, change Periodic Sensor
+     * status publication mechanism.
+     */
+    update_sensor_periodic_pub(sensor_model, prop_id);
+    return;
+}
+
+static void update_sensor_periodic_pub(struct bt_mesh_model *model, u16_t prop_id)
+{
+    struct bt_mesh_sensor_state *state = NULL;
+    struct bt_mesh_sensor_srv *srv = NULL;
+    u8_t i;
+
+    if (model->id != BLE_MESH_MODEL_ID_SENSOR_SRV) {
+        BT_ERR("%s, Not a Sensor Server Model", __func__);
+        return;
+    }
+
+    srv = (struct bt_mesh_sensor_srv *)model->user_data;
+    if (srv == NULL || srv->state_count == 0U || srv->states == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    for (i = 0U; i < srv->state_count; i++) {
+        state = &srv->states[i];
+        if (state->sensor_property_id != INVALID_SENSOR_PROPERTY_ID &&
+            state->sensor_property_id == prop_id) {
+            break;
+        }
+    }
+    if (i == srv->state_count) {
+        BT_ERR("%s, Sensor Property ID 0x%04x does not exist", __func__, prop_id);
+        return;
+    }
+
+    if (state->cadence == NULL) {
+        BT_WARN("%s, Sensor Cadence state does not exist", __func__);
+        return;
+    }
+
+    /**
+     * Currently when the device receives a Sensor Cadence Set message,
+     * a event will be callback to the application layer, and users can
+     * change the Sensor Data publication period in the event. And this
+     * is exactly what we do for the BQB test.
+     */
+}
+
+static void sensor_setting_set(struct bt_mesh_model *model,
+                               struct bt_mesh_msg_ctx *ctx,
+                               struct net_buf_simple *buf)
+{
+    struct bt_mesh_sensor_setup_srv *srv = model->user_data;
+    bt_mesh_sensor_server_state_change_t change = {0};
+    struct sensor_setting *item = NULL;
+    u16_t prop_id, set_prop_id;
+
+    if (srv == NULL || srv->state_count == 0U || srv->states == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    prop_id = net_buf_simple_pull_le16(buf);
+    if (prop_id == INVALID_SENSOR_PROPERTY_ID) {
+        BT_ERR("%s, Prohibited Sensor Property ID 0x0000", __func__);
+        return;
+    }
+
+    set_prop_id = net_buf_simple_pull_le16(buf);
+    if (set_prop_id == INVALID_SENSOR_PROPERTY_ID) {
+        BT_ERR("%s, Prohibited Sensor Setting Property ID 0x0000", __func__);
+        return;
+    }
+
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_sensor_server_recv_set_msg_t set = {
+            .sensor_setting_set.id = prop_id,
+            .sensor_setting_set.setting_id = set_prop_id,
+            .sensor_setting_set.raw = buf,
+        };
+        bt_mesh_sensor_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_SENSOR_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    item = find_sensor_setting(model, prop_id, set_prop_id);
+    if (item) {
+        if (item->access == SENSOR_SETTING_ACCESS_READ_WRITE && item->raw) {
+            net_buf_simple_reset(item->raw);
+            net_buf_simple_add_mem(item->raw, buf->data,
+                MIN(buf->len, item->raw->size));
+
+            change.sensor_setting_set.id = prop_id;
+            change.sensor_setting_set.setting_id = set_prop_id;
+            change.sensor_setting_set.value = item->raw;
+            bt_mesh_sensor_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_SENSOR_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        }
+    }
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_SENSOR_SETTING_SET) {
+        send_sensor_setting_status(model, ctx, prop_id, set_prop_id, false);
+    }
+    if (item) {
+        send_sensor_setting_status(model, ctx, prop_id, set_prop_id, true);
+    }
+
+    return;
+}
+
+/* message handlers (End) */
+
+/* Mapping of message handlers for Sensor Server (0x1100) */
+const struct bt_mesh_model_op sensor_srv_op[] = {
+    { BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET, 0, sensor_get },
+    { BLE_MESH_MODEL_OP_SENSOR_GET,            0, sensor_get },
+    { BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET,     2, sensor_get },
+    { BLE_MESH_MODEL_OP_SENSOR_SERIES_GET,     2, sensor_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Sensor Setup Server (0x1101) */
+const struct bt_mesh_model_op sensor_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET,       2, sensor_get         },
+    { BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET,       4, sensor_cadence_set },
+    { BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK, 4, sensor_cadence_set },
+    { BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET,      2, sensor_get         },
+    { BLE_MESH_MODEL_OP_SENSOR_SETTING_GET,       4, sensor_get         },
+    { BLE_MESH_MODEL_OP_SENSOR_SETTING_SET,       4, sensor_setting_set },
+    { BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK, 4, sensor_setting_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+static int check_sensor_server_init(struct bt_mesh_sensor_state *state_start,
+                                    const u8_t state_count)
+{
+    struct bt_mesh_sensor_state *state = NULL;
+    struct sensor_setting *setting = NULL;
+    u8_t i, j;
+
+    for (i = 0U; i < state_count; i++) {
+        state = &state_start[i];
+        if (state->sensor_property_id == INVALID_SENSOR_PROPERTY_ID) {
+            BT_ERR("%s, Invalid Sensor Property ID 0x%04x", __func__, state->sensor_property_id);
+            return -EINVAL;
+        }
+        if (state->setting_count == 0U || state->settings == NULL) {
+            BT_ERR("%s, Invalid Sensor Setting state", __func__);
+            return -EINVAL;
+        }
+        for (j = 0U; j < state->setting_count; j++) {
+            setting = &state->settings[j];
+            if (setting->property_id == INVALID_SENSOR_SETTING_PROPERTY_ID || setting->raw == NULL) {
+                BT_ERR("%s, Invalid Sensor Setting state internal parameter", __func__);
+                return -EINVAL;
+            }
+        }
+        if (state->cadence) {
+            if (state->cadence->trigger_delta_down == NULL ||
+                state->cadence->trigger_delta_up == NULL ||
+                state->cadence->fast_cadence_low == NULL ||
+                state->cadence->fast_cadence_high == NULL) {
+                BT_ERR("%s, Invalid Sensor Cadence state", __func__);
+                return -EINVAL;
+            }
+        }
+        if (state->sensor_data.raw_value == NULL) {
+            BT_ERR("%s, Invalid Sensor Data state", __func__);
+            return -EINVAL;
+        }
+        if (state->series_column.raw_value_x == NULL ||
+            state->series_column.column_width == NULL ||
+            state->series_column.raw_value_y == NULL) {
+            BT_ERR("%s, Invalid Sensor Series column state", __func__);
+            return -EINVAL;
+        }
+    }
+
+    return 0;
+}
+
+static int sensor_server_init(struct bt_mesh_model *model)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, No Sensor Server context provided, model_id 0x%04x", __func__, model->id);
+        return -EINVAL;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_SENSOR_SRV: {
+        struct bt_mesh_sensor_srv *srv = model->user_data;
+        if (srv->state_count == 0U || srv->states == NULL) {
+            BT_ERR("%s, Invalid Sensor state parameter, model_id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+        if (check_sensor_server_init(srv->states, srv->state_count)) {
+            BT_ERR("%s, Invalid Sensor Server init value", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV: {
+        struct bt_mesh_sensor_setup_srv *srv = model->user_data;
+        if (srv->state_count == 0U || srv->states == NULL) {
+            BT_ERR("%s, Invalid parameter, model_id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+        if (check_sensor_server_init(srv->states, srv->state_count)) {
+            BT_ERR("%s, Invalid Sensor Setup Server init value", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown Sensor Server Model, model_id 0x%04x", __func__, model->id);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int bt_mesh_sensor_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Sensor Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /* When this model is present on an element, the corresponding Sensor Setup
+     * Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Sensor Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return sensor_server_init(model);
+}
+
+int bt_mesh_sensor_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Sensor Setup Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    return sensor_server_init(model);
+}

+ 237 - 0
components/bt/esp_ble_mesh/mesh_models/server/server_common.c

@@ -0,0 +1,237 @@
+// Copyright 2017-2019 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.
+
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include "osi/allocator.h"
+
+#include "mesh_types.h"
+#include "mesh_kernel.h"
+#include "mesh_trace.h"
+#include "mesh.h"
+#include "access.h"
+#include "model_opcode.h"
+
+#include "server_common.h"
+#include "state_binding.h"
+#include "state_transition.h"
+
+/**
+ * According to Mesh Model Spec:
+ * If the Transition Time field is not present and the Generic Default Transition
+ * Time state is supported, the Generic Default Transition Time state shall be
+ * used. Otherwise the transition shall be instantaneous.
+ */
+#define INSTANTANEOUS_TRANS_TIME      0
+
+u8_t bt_mesh_get_default_trans_time(struct bt_mesh_model *model)
+{
+    /**
+     * 1. If a Generic Default Transition Time Server model is present on the
+     *    main element of the model, that model instance shall be used.
+     * 2. If a Generic Default Transition Time Server model is not present on
+     *    the main element of the model, then the Generic Default Transition
+     *    Time Server model instance that is present on the element with the
+     *    largest address that is smaller than the address of the main element
+     *    of the node shall be used; if no model instance is present on any
+     *    element with an address smaller than the address of the main element,
+     *    then the Generic Default Transition Time Server is not supported.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    struct bt_mesh_gen_def_trans_time_srv *state = NULL;
+    u16_t primary_addr = bt_mesh_primary_addr();
+    struct bt_mesh_model *srv = NULL;
+
+    for (u16_t addr = element->addr; addr >= primary_addr; addr--) {
+        element = bt_mesh_elem_find(addr);
+        if (element) {
+            srv = bt_mesh_model_find(element, BLE_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV);
+            if (srv) {
+                state = (struct bt_mesh_gen_def_trans_time_srv *)srv->user_data;
+                if (state) {
+                    return state->state.trans_time;
+                }
+            }
+        }
+    }
+
+    return INSTANTANEOUS_TRANS_TIME;
+}
+
+int bt_mesh_get_light_lc_trans_time(struct bt_mesh_model *model, u8_t *trans_time)
+{
+    struct bt_mesh_light_lc_srv *srv = NULL;
+    u32_t value;
+
+    if (model == NULL || trans_time == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return -EINVAL;
+    }
+
+    if (model->id != BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
+        BT_ERR("%s, Not a Light LC Server", __func__);
+        return -EINVAL;
+    }
+
+    srv = (struct bt_mesh_light_lc_srv *)model->user_data;
+    if (srv == NULL) {
+        BT_ERR("%s, Invalid Light LC Server user_data", __func__);
+        return -EINVAL;
+    }
+
+    /**
+     * 1. Set transition time to 0x54 for BQB test case MESH/SR/LLC/BV-04-C.
+     *    Light LC Property Set: 0x3C, 0x004E20 -> Light LC Time Run On
+     *    Light LC Property Set: 0x37, 0x004E20 -> Light LC Time Fade On
+     *    Light LC Property Set: 0x39, 0x004E20 -> Light LC Time Fade Standby Manual
+     * 
+     * 2. Set transition time to 0x0 for BQB test case MESH/SR/LLC/BV-08-C.
+     * 
+     * TODO: Based on Light LC state and choose property property value as the
+     * transition time. Currently directly use Light LC Time Run On property value.
+     * Unit: Millisecond, range: [0, 16777214(0xFFFFFE)]
+     */
+    value = srv->lc->prop_state.time_run_on & 0xFFFFFF;
+
+    /**
+     * Convert value into Default Transition Time state format.
+     * 0b00: 0 ~ 6.2s, 100 millisecond step resolution
+     * 0b01: 0 ~ 62s,  1 second step resolution
+     * 0b10: 0 ~ 620s, 10 seconds step resolution
+     * 0b11: 0 ~ 620m, 10 minutes step resolution
+     */
+    if (value <= 6200) {
+        *trans_time = (0 << 6) | (value / 100);
+    } else if (value <= 62000) {
+        *trans_time = (1 << 6) | (value / 1000);
+    } else if (value <= 620000) {
+        *trans_time = (2 << 6) | (value / 10000);
+    } else {
+        *trans_time = (3 << 6) | (value / 600000);
+    }
+
+    return 0;
+}
+
+int bt_mesh_server_get_optional(struct bt_mesh_model *model,
+                                struct net_buf_simple *buf,
+                                u8_t *trans_time, u8_t *delay,
+                                bool *optional)
+{
+    if (model == NULL || buf == NULL || trans_time == NULL ||
+        delay == NULL || optional == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return -EINVAL;
+    }
+
+    if (buf->len != 0x00 && buf->len != 0x02) {
+        BT_ERR("%s, Invalid optional message length %d", __func__, buf->len);
+        return -EINVAL;
+    }
+
+    /* No optional fields are available */
+    if (buf->len == 0x00) {
+        if (model->id == BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
+            /**
+             * Both messages(i.e. Light LC OnOff Set/Set Unack) may optionally include
+             * a Transition Time field indicating the transition time to the target state.
+             * If the Transition Time is not included, the Light LC Server shall use
+             * its appropriate transition times defined by the Light LC Property states.
+             */
+            if (bt_mesh_get_light_lc_trans_time(model, trans_time)) {
+                BT_ERR("%s, Failed to get Light LC transition time", __func__);
+                return -EIO;
+            }
+        } else {
+            *trans_time = bt_mesh_get_default_trans_time(model);
+        }
+        *delay = 0U;
+        *optional = false;
+        return 0;
+    }
+
+    /* Optional fields are available */
+    *trans_time = net_buf_simple_pull_u8(buf);
+    if ((*trans_time & 0x3F) == 0x3F) {
+        BT_ERR("%s, Invalid Transaction Number of Steps 0x3F", __func__);
+        return -EINVAL;
+    }
+
+    *delay = net_buf_simple_pull_u8(buf);
+    *optional = true;
+    return 0;
+}
+
+void bt_mesh_server_alloc_ctx(struct k_work *work)
+{
+    /**
+     * This function is used to allocate memory for storing "struct bt_mesh_msg_ctx"
+     * of the received messages, because some server models will callback the "struct
+     * bt_mesh_msg_ctx" info to the application layer after a certain delay.
+     * Here we use the allocated heap memory to store the "struct bt_mesh_msg_ctx".
+     */
+    __ASSERT(work, "%s, Invalid parameter", __func__);
+    work->_reserved = osi_calloc(sizeof(struct bt_mesh_msg_ctx));
+    __ASSERT(work->_reserved, "%s, Failed to allocate memory", __func__);
+}
+
+bool bt_mesh_is_server_recv_last_msg(struct bt_mesh_last_msg_info *last,
+                                     u8_t tid, u16_t src, u16_t dst, s64_t *now)
+{
+    *now = k_uptime_get();
+
+    if (last->tid == tid && last->src == src && last->dst == dst &&
+        (*now - last->timestamp <= K_SECONDS(6))) {
+        return true;
+    }
+
+    return false;
+}
+
+void bt_mesh_server_update_last_msg(struct bt_mesh_last_msg_info *last,
+                                    u8_t tid, u16_t src, u16_t dst, s64_t *now)
+{
+    last->tid = tid;
+    last->src = src;
+    last->dst = dst;
+    last->timestamp = *now;
+    return;
+}
+
+struct net_buf_simple *bt_mesh_server_get_pub_msg(struct bt_mesh_model *model, u16_t msg_len)
+{
+    struct net_buf_simple *buf = NULL;
+
+    if (model == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return NULL;
+    }
+
+    if (model->pub == NULL || model->pub->msg == NULL ||
+        model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) {
+        BT_DBG("%s, Model 0x%04x has no publication support", __func__, model->id);
+        return NULL;
+    }
+
+    buf = model->pub->msg;
+    if (buf->size < msg_len) {
+        BT_ERR("%s, Too small publication msg size %d, model 0x%04x",
+            __func__, buf->size, model->id);
+        return NULL;
+    }
+
+    return buf;
+}

+ 342 - 0
components/bt/esp_ble_mesh/mesh_models/server/state_binding.c

@@ -0,0 +1,342 @@
+/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
+ *
+ * Copyright (c) 2018 Vikrant More
+ * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include "mesh_types.h"
+#include "mesh_kernel.h"
+#include "mesh_trace.h"
+#include "mesh.h"
+
+#include "model_opcode.h"
+#include "server_common.h"
+#include "state_binding.h"
+#include "state_transition.h"
+#include "generic_server.h"
+#include "lighting_server.h"
+
+#define MINDIFF (2.25e-308)
+
+static float bt_mesh_sqrt(float square)
+{
+    float root, last, diff;
+
+    root = square / 3.0;
+    diff = 1;
+
+    if (square <= 0) {
+        return 0;
+    }
+
+    do {
+        last = root;
+        root = (root + square / root) / 2.0;
+        diff = root - last;
+    } while (diff > MINDIFF || diff < -MINDIFF);
+
+    return root;
+}
+
+static s32_t bt_mesh_ceiling(float num)
+{
+    s32_t inum = (s32_t)num;
+
+    if (num == (float)inum) {
+        return inum;
+    }
+
+    return inum + 1;
+}
+
+u16_t bt_mesh_convert_lightness_actual_to_linear(u16_t actual)
+{
+    float tmp = ((float) actual / UINT16_MAX);
+
+    return bt_mesh_ceiling(UINT16_MAX * tmp * tmp);
+}
+
+u16_t bt_mesh_convert_lightness_linear_to_actual(u16_t linear)
+{
+    return (u16_t) (UINT16_MAX * bt_mesh_sqrt(((float) linear / UINT16_MAX)));
+}
+
+s16_t bt_mesh_convert_temperature_to_gen_level(u16_t temp, u16_t min, u16_t max)
+{
+    float tmp = (temp - min) * UINT16_MAX / (max - min);
+    return (s16_t) (tmp + INT16_MIN);
+}
+
+u16_t bt_mesh_covert_gen_level_to_temperature(s16_t level, u16_t min, u16_t max)
+{
+    float diff = (float) (max - min) / UINT16_MAX;
+    u16_t tmp = (u16_t) ((level - INT16_MIN) * diff);
+    return (u16_t) (min + tmp);
+}
+
+s16_t bt_mesh_convert_hue_to_level(u16_t hue)
+{
+    return (s16_t) (hue + INT16_MIN);
+}
+
+u16_t bt_mesh_convert_level_to_hue(s16_t level)
+{
+    return (u16_t) (level - INT16_MIN);
+}
+
+s16_t bt_mesh_convert_saturation_to_level(u16_t saturation)
+{
+    return (s16_t) (saturation + INT16_MIN);
+}
+
+u16_t bt_mesh_convert_level_to_saturation(s16_t level)
+{
+    return (u16_t) (level - INT16_MIN);
+}
+
+int bt_mesh_update_binding_state(struct bt_mesh_model *model,
+                                 bt_mesh_server_state_type_t type,
+                                 bt_mesh_server_state_value_t *value)
+{
+    if (model == NULL || model->user_data == NULL ||
+        value == NULL || type > BIND_STATE_MAX) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return -EINVAL;
+    }
+
+    switch (type) {
+    case GENERIC_ONOFF_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_GEN_ONOFF_SRV) {
+            BT_ERR("%s, Not a Generic OnOff Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_gen_onoff_srv *srv = model->user_data;
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state.onoff = value->gen_onoff.onoff;
+        gen_onoff_publish(model);
+        break;
+    }
+    case GENERIC_LEVEL_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_GEN_LEVEL_SRV) {
+            BT_ERR("%s, Not a Generic Level Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_gen_level_srv *srv = model->user_data;
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state.level = value->gen_level.level;
+        gen_level_publish(model);
+        break;
+    }
+    case GENERIC_ONPOWERUP_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV) {
+            BT_ERR("%s, Not a Generic Power OnOff Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_gen_power_onoff_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Generic Power OnOff Server state", __func__);
+            return -EINVAL;
+        }
+
+        srv->state->onpowerup = value->gen_onpowerup.onpowerup;
+        gen_onpowerup_publish(model);
+        break;
+    }
+    case GENERIC_POWER_ACTUAL_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV) {
+            BT_ERR("%s, Not a Generic Power Level Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_gen_power_level_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Generic Power Level Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state->power_actual = value->gen_power_actual.power;
+        /**
+         * Whenever the Generic Power Actual state is changed to a non-zero value
+         * as a result of a non-transactional message or a completed sequence of
+         * transactional messages, the value of the Generic Power Last state shall
+         * be set to the value of the Generic Power Actual state.
+         */
+        if (srv->state->power_actual) {
+            srv->state->power_last = srv->state->power_actual;
+        }
+        gen_power_level_publish(model, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
+        break;
+    }
+    case LIGHT_LIGHTNESS_ACTUAL_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
+            BT_ERR("%s, Not a Light Lightness Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_lightness_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light Lightness Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->actual_transition);
+        srv->state->lightness_actual = value->light_lightness_actual.lightness;
+        light_lightness_publish(model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
+        break;
+    }
+    case LIGHT_LIGHTNESS_LINEAR_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV) {
+            BT_ERR("%s, Not a Light Lightness Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_lightness_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light Lightness Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->linear_transition);
+        srv->state->lightness_linear = value->light_lightness_linear.lightness;
+        light_lightness_publish(model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
+        break;
+    }
+    case LIGHT_CTL_LIGHTNESS_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_CTL_SRV) {
+            BT_ERR("%s, Not a Light CTL Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_ctl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light CTL Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state->lightness = value->light_ctl_lightness.lightness;
+        light_ctl_publish(model, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
+        break;
+    }
+    case LIGHT_CTL_TEMP_DELTA_UV_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV) {
+            BT_ERR("%s, Not a Light CTL Temperature Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_ctl_temp_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light CTL Temperature Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state->temperature = value->light_ctl_temp_delta_uv.temperature;
+        srv->state->delta_uv = value->light_ctl_temp_delta_uv.delta_uv;
+        light_ctl_publish(model, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
+        break;
+    }
+    case LIGHT_HSL_LIGHTNESS_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SRV) {
+            BT_ERR("%s, Not a Light HSL Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_hsl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state->lightness = value->light_hsl_lightness.lightness;
+        light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
+        break;
+    }
+    case LIGHT_HSL_HUE_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV) {
+            BT_ERR("%s, Not a Light HSL Hue Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_hsl_hue_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Hue Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state->hue = value->light_hsl_hue.hue;
+        light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
+        break;
+    }
+    case LIGHT_HSL_SATURATION_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV) {
+            BT_ERR("%s, Not a Light HSL Saturation Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_hsl_sat_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light HSL Saturation Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state->saturation = value->light_hsl_saturation.saturation;
+        light_hsl_publish(model, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
+        break;
+    }
+    case LIGHT_XYL_LIGHTNESS_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_XYL_SRV) {
+            BT_ERR("%s, Not a Light xyL Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_xyl_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Light xyL Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->state->lightness = value->light_xyl_lightness.lightness;
+        light_xyl_publish(model, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
+        break;
+    }
+    case LIGHT_LC_LIGHT_ONOFF_STATE: {
+        if (model->id != BLE_MESH_MODEL_ID_LIGHT_LC_SRV) {
+            BT_ERR("%s, Not a Light LC Server Model, id 0x%04x", __func__, model->id);
+            return -EINVAL;
+        }
+
+        struct bt_mesh_light_lc_srv *srv = model->user_data;
+        if (srv->lc == NULL) {
+            BT_ERR("%s, Invalid Light LC Server state", __func__);
+            return -EINVAL;
+        }
+
+        bt_mesh_server_stop_transition(&srv->transition);
+        srv->lc->state.light_onoff = value->light_lc_light_onoff.onoff;
+        light_lc_publish(model, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown binding state type 0x%02x", __func__, type);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+

+ 1034 - 0
components/bt/esp_ble_mesh/mesh_models/server/state_transition.c

@@ -0,0 +1,1034 @@
+/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
+ *
+ * Copyright (c) 2018 Vikrant More
+ * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include "mesh_types.h"
+#include "mesh_kernel.h"
+#include "mesh_trace.h"
+#include "mesh.h"
+#include "model_opcode.h"
+
+#include "server_common.h"
+#include "state_binding.h"
+#include "state_transition.h"
+#include "generic_server.h"
+#include "lighting_server.h"
+#include "time_scene_server.h"
+
+#include "btc_ble_mesh_generic_model.h"
+#include "btc_ble_mesh_lighting_model.h"
+#include "btc_ble_mesh_time_scene_model.h"
+#include "btc_ble_mesh_sensor_model.h"
+
+/* Function to calculate Remaining Time (Start) */
+
+void bt_mesh_server_calc_remain_time(struct bt_mesh_state_transition *transition)
+{
+    u8_t steps, resolution;
+    s32_t duration_remainder;
+    s64_t now;
+
+    if (transition->just_started) {
+        transition->remain_time = transition->trans_time;
+    } else {
+        now = k_uptime_get();
+        duration_remainder = transition->total_duration -
+                             (now - transition->start_timestamp);
+        if (duration_remainder > 620000) {
+            /* > 620 seconds -> resolution = 0b11 [10 minutes] */
+            resolution = 0x03;
+            steps = duration_remainder / 600000;
+        } else if (duration_remainder > 62000) {
+            /* > 62 seconds -> resolution = 0b10 [10 seconds] */
+            resolution = 0x02;
+            steps = duration_remainder / 10000;
+        } else if (duration_remainder > 6200) {
+            /* > 6.2 seconds -> resolution = 0b01 [1 seconds] */
+            resolution = 0x01;
+            steps = duration_remainder / 1000;
+        } else if (duration_remainder > 0) {
+            /* <= 6.2 seconds -> resolution = 0b00 [100 ms] */
+            resolution = 0x00;
+            steps = duration_remainder / 100;
+        } else {
+            resolution = 0x00;
+            steps = 0x00;
+        }
+
+        transition->remain_time = (resolution << 6) | steps;
+    }
+}
+
+/* Function to calculate Remaining Time (End) */
+
+static void tt_values_calculator(struct bt_mesh_state_transition *transition)
+{
+    u8_t steps_multiplier, resolution;
+
+    resolution = (transition->trans_time >> 6);
+    steps_multiplier = (transition->trans_time & 0x3F);
+
+    switch (resolution) {
+    case 0: /* 100ms */
+        transition->total_duration = steps_multiplier * 100;
+        break;
+    case 1: /* 1 second */
+        transition->total_duration = steps_multiplier * 1000;
+        break;
+    case 2: /* 10 seconds */
+        transition->total_duration = steps_multiplier * 10000;
+        break;
+    case 3: /* 10 minutes */
+        transition->total_duration = steps_multiplier * 600000;
+        break;
+    }
+
+    transition->counter = ((float) transition->total_duration / 100);
+
+    if (transition->counter > BLE_MESH_DEVICE_SPECIFIC_RESOLUTION) {
+        transition->counter = BLE_MESH_DEVICE_SPECIFIC_RESOLUTION;
+    }
+}
+
+static void transition_time_values(struct bt_mesh_state_transition *transition,
+                                   u8_t trans_time, u8_t delay)
+{
+    transition->trans_time = trans_time;
+    transition->delay = delay;
+
+    if (trans_time == 0U) {
+        return;
+    }
+
+    tt_values_calculator(transition);
+    transition->quo_tt = transition->total_duration / transition->counter;
+}
+
+void generic_onoff_tt_values(struct bt_mesh_gen_onoff_srv *srv,
+                             u8_t trans_time, u8_t delay)
+{
+    return transition_time_values(&srv->transition, trans_time, delay);
+}
+
+void generic_level_tt_values(struct bt_mesh_gen_level_srv *srv,
+                             u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+    srv->tt_delta_level =
+        ((float) (srv->state.level - srv->state.target_level) / srv->transition.counter);
+}
+
+void generic_power_level_tt_values(struct bt_mesh_gen_power_level_srv *srv,
+                                   u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+    srv->tt_delta_level =
+        ((float) (srv->state->power_actual - srv->state->target_power_actual) / srv->transition.counter);
+}
+
+void light_lightness_actual_tt_values(struct bt_mesh_light_lightness_srv *srv,
+                                      u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->actual_transition, trans_time, delay);
+    srv->tt_delta_lightness_actual =
+        ((float) (srv->state->lightness_actual - srv->state->target_lightness_actual) / srv->actual_transition.counter);
+}
+
+void light_lightness_linear_tt_values(struct bt_mesh_light_lightness_srv *srv,
+                                      u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->linear_transition, trans_time, delay);
+    srv->tt_delta_lightness_linear =
+        ((float) (srv->state->lightness_linear - srv->state->target_lightness_linear) / srv->linear_transition.counter);
+}
+
+void light_ctl_tt_values(struct bt_mesh_light_ctl_srv *srv,
+                         u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+    srv->tt_delta_lightness =
+        ((float) (srv->state->lightness - srv->state->target_lightness) / srv->transition.counter);
+    srv->tt_delta_temperature =
+        ((float) (srv->state->temperature - srv->state->target_temperature) / srv->transition.counter);
+    srv->tt_delta_delta_uv =
+        ((float) (srv->state->delta_uv - srv->state->target_delta_uv) / srv->transition.counter);
+}
+
+void light_ctl_temp_tt_values(struct bt_mesh_light_ctl_temp_srv *srv,
+                              u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+    srv->tt_delta_temperature =
+        ((float) (srv->state->temperature - srv->state->target_temperature) / srv->transition.counter);
+    srv->tt_delta_delta_uv =
+        ((float) (srv->state->delta_uv - srv->state->target_delta_uv) / srv->transition.counter);
+}
+
+void light_hsl_tt_values(struct bt_mesh_light_hsl_srv *srv,
+                         u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+    srv->tt_delta_lightness =
+        ((float) (srv->state->lightness - srv->state->target_lightness) / srv->transition.counter);
+    srv->tt_delta_hue =
+        ((float) (srv->state->hue - srv->state->target_hue) / srv->transition.counter);
+    srv->tt_delta_saturation =
+        ((float) (srv->state->saturation - srv->state->target_saturation) / srv->transition.counter);
+}
+
+void light_hsl_hue_tt_values(struct bt_mesh_light_hsl_hue_srv *srv,
+                             u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+    srv->tt_delta_hue =
+        ((float) (srv->state->hue - srv->state->target_hue) / srv->transition.counter);
+}
+
+void light_hsl_sat_tt_values(struct bt_mesh_light_hsl_sat_srv *srv,
+                             u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+    srv->tt_delta_saturation =
+        ((float) (srv->state->saturation - srv->state->target_saturation) / srv->transition.counter);
+}
+
+void light_xyl_tt_values(struct bt_mesh_light_xyl_srv *srv,
+                         u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+    srv->tt_delta_lightness =
+        ((float) (srv->state->lightness - srv->state->target_lightness) / srv->transition.counter);
+    srv->tt_delta_x =
+        ((float) (srv->state->x - srv->state->target_x) / srv->transition.counter);
+    srv->tt_delta_y =
+        ((float) (srv->state->y - srv->state->target_y) / srv->transition.counter);
+}
+
+void light_lc_tt_values(struct bt_mesh_light_lc_srv *srv,
+                        u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+}
+
+void scene_tt_values(struct bt_mesh_scene_srv *srv, u8_t trans_time, u8_t delay)
+{
+    transition_time_values(&srv->transition, trans_time, delay);
+}
+
+static void transition_timer_start(struct bt_mesh_state_transition *transition)
+{
+    transition->start_timestamp = k_uptime_get();
+    k_delayed_work_submit_periodic(&transition->timer, K_MSEC(transition->quo_tt));
+    bt_mesh_atomic_set_bit(transition->flag, BLE_MESH_TRANS_TIMER_START);
+}
+
+static void transition_timer_stop(struct bt_mesh_state_transition *transition)
+{
+    k_delayed_work_cancel(&transition->timer);
+    bt_mesh_atomic_clear_bit(transition->flag, BLE_MESH_TRANS_TIMER_START);
+}
+
+/* Timers related handlers & threads (Start) */
+void generic_onoff_work_handler(struct k_work *work)
+{
+    struct bt_mesh_gen_onoff_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_gen_onoff_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_gen_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_generic_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.gen_onoff_set.onoff = srv->state.onoff;
+            bt_mesh_generic_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            /**
+             * Because binary states cannot support transitions, when changing to
+             * 0x01 (On), the Generic OnOff state shall change immediately when
+             * the transition starts, and when changing to 0x00, the state shall
+             * change when the transition finishes.
+             */
+            if (srv->state.target_onoff == BLE_MESH_STATE_ON) {
+                srv->state.onoff = BLE_MESH_STATE_ON;
+                change.gen_onoff_set.onoff = srv->state.onoff;
+                bt_mesh_generic_server_cb_evt_to_btc(
+                    BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            }
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_generic_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state.onoff = srv->state.target_onoff;
+        if (srv->state.target_onoff != BLE_MESH_STATE_ON) {
+            change.gen_onoff_set.onoff = srv->state.onoff;
+            bt_mesh_generic_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+        }
+    }
+
+    gen_onoff_publish(srv->model);
+
+    bt_mesh_generic_server_unlock();
+    return;
+}
+
+void generic_level_work_handler(struct k_work *work)
+{
+    struct bt_mesh_gen_level_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_gen_level_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_gen_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_generic_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            switch (ctx->recv_op) {
+            case BLE_MESH_MODEL_OP_GEN_LEVEL_SET:
+            case BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK:
+                change.gen_level_set.level = srv->state.level;
+                break;
+            case BLE_MESH_MODEL_OP_GEN_DELTA_SET:
+            case BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK:
+                change.gen_delta_set.level = srv->state.level;
+                break;
+            case BLE_MESH_MODEL_OP_GEN_MOVE_SET:
+            case BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK:
+                change.gen_move_set.level = srv->state.level;
+                break;
+            }
+            bt_mesh_generic_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_generic_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+        srv->state.level -= srv->tt_delta_level;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state.level = srv->state.target_level;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_GEN_LEVEL_SET:
+    case BLE_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK:
+        change.gen_level_set.level = srv->state.level;
+        break;
+    case BLE_MESH_MODEL_OP_GEN_DELTA_SET:
+    case BLE_MESH_MODEL_OP_GEN_DELTA_SET_UNACK:
+        change.gen_delta_set.level = srv->state.level;
+        break;
+    case BLE_MESH_MODEL_OP_GEN_MOVE_SET:
+    case BLE_MESH_MODEL_OP_GEN_MOVE_SET_UNACK:
+        change.gen_move_set.level = srv->state.level;
+        break;
+    }
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    gen_level_publish(srv->model);
+
+    bt_mesh_generic_server_unlock();
+    return;
+}
+
+void generic_power_level_work_handler(struct k_work *work)
+{
+    struct bt_mesh_gen_power_level_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_gen_power_level_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_gen_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_generic_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.gen_power_level_set.power = srv->state->power_actual;
+            bt_mesh_generic_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_generic_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+        srv->state->power_actual -= srv->tt_delta_level;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+
+        srv->state->power_actual = srv->state->target_power_actual;
+        /**
+         * Whenever the Generic Power Actual state is changed to a non-zero value
+         * as a result of a non-transactional message or a completed sequence of
+         * transactional messages, the value of the Generic Power Last state shall
+         * be set to the value of the Generic Power Actual state.
+         */
+        if (srv->state->power_actual) {
+            srv->state->power_last = srv->state->power_actual;
+        }
+    }
+
+    change.gen_power_level_set.power = srv->state->power_actual;
+    bt_mesh_generic_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_GENERIC_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    gen_power_level_publish(srv->model, BLE_MESH_MODEL_OP_GEN_POWER_LEVEL_STATUS);
+
+    bt_mesh_generic_server_unlock();
+    return;
+}
+
+void light_lightness_actual_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_lightness_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_lightness_srv, actual_transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->actual_transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->actual_transition.timer.work._reserved;
+
+    if (srv->actual_transition.just_started) {
+        srv->actual_transition.just_started = false;
+        if (srv->actual_transition.counter == 0U) {
+            change.lightness_set.lightness = srv->state->lightness_actual;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->actual_transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->actual_transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->actual_transition.counter != 0U) {
+        srv->actual_transition.counter--;
+        srv->state->lightness_actual -= srv->tt_delta_lightness_actual;
+    }
+
+    if (srv->actual_transition.counter == 0U) {
+        transition_timer_stop(&srv->actual_transition);
+
+        srv->state->lightness_actual = srv->state->target_lightness_actual;
+        /**
+         * Whenever the Light Lightness Actual state is changed with a non-
+         * transactional message or a completed sequence of transactional
+         * messages to a non-zero value, the value of the Light Lightness
+         * Last shall be set to the value of the Light Lightness Actual.
+         */
+        if (srv->state->lightness_actual) {
+            srv->state->lightness_last = srv->state->lightness_actual;
+        }
+    }
+
+    change.lightness_set.lightness = srv->state->lightness_actual;
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    light_lightness_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void light_lightness_linear_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_lightness_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_lightness_srv, linear_transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->linear_transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->linear_transition.timer.work._reserved;
+
+    if (srv->linear_transition.just_started) {
+        srv->linear_transition.just_started = false;
+        if (srv->linear_transition.counter == 0U) {
+            change.lightness_linear_set.lightness = srv->state->lightness_linear;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->linear_transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->linear_transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->linear_transition.counter != 0U) {
+        srv->linear_transition.counter--;
+        srv->state->lightness_linear -= srv->tt_delta_lightness_linear;
+    }
+
+    if (srv->linear_transition.counter == 0U) {
+        transition_timer_stop(&srv->linear_transition);
+        srv->state->lightness_linear = srv->state->target_lightness_linear;
+    }
+
+    change.lightness_linear_set.lightness = srv->state->lightness_linear;
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    light_lightness_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_LINEAR_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void light_ctl_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_ctl_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_ctl_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.ctl_set.lightness = srv->state->lightness;
+            change.ctl_set.temperature = srv->state->temperature;
+            change.ctl_set.delta_uv = srv->state->delta_uv;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+        srv->state->lightness -= srv->tt_delta_lightness;
+        srv->state->temperature -= srv->tt_delta_temperature;
+        srv->state->delta_uv -= srv->tt_delta_delta_uv;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state->lightness = srv->state->target_lightness;
+        srv->state->temperature = srv->state->target_temperature;
+        srv->state->delta_uv = srv->state->target_delta_uv;
+    }
+
+    change.ctl_set.lightness = srv->state->lightness;
+    change.ctl_set.temperature = srv->state->temperature;
+    change.ctl_set.delta_uv = srv->state->delta_uv;
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    light_ctl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_CTL_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void light_ctl_temp_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_ctl_temp_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_ctl_temp_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.ctl_temp_set.temperature = srv->state->temperature;
+            change.ctl_temp_set.delta_uv = srv->state->delta_uv;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+        srv->state->temperature -= srv->tt_delta_temperature;
+        srv->state->delta_uv -= srv->tt_delta_delta_uv;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state->temperature = srv->state->target_temperature;
+        srv->state->delta_uv = srv->state->target_delta_uv;
+    }
+
+    change.ctl_temp_set.temperature = srv->state->temperature;
+    change.ctl_temp_set.delta_uv = srv->state->delta_uv;
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    light_ctl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_CTL_TEMPERATURE_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void light_hsl_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_hsl_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_hsl_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.hsl_set.lightness = srv->state->lightness;
+            change.hsl_set.hue = srv->state->hue;
+            change.hsl_set.saturation = srv->state->saturation;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+        srv->state->lightness -= srv->tt_delta_lightness;
+        srv->state->hue -= srv->tt_delta_hue;
+        srv->state->saturation -= srv->tt_delta_saturation;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state->lightness = srv->state->target_lightness;
+        srv->state->hue = srv->state->target_hue;
+        srv->state->saturation = srv->state->target_saturation;
+    }
+
+    change.hsl_set.lightness = srv->state->lightness;
+    change.hsl_set.hue = srv->state->hue;
+    change.hsl_set.saturation = srv->state->saturation;
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void light_hsl_hue_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_hsl_hue_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_hsl_hue_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.hsl_hue_set.hue = srv->state->hue;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+        srv->state->hue -= srv->tt_delta_hue;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state->hue = srv->state->target_hue;
+    }
+
+    change.hsl_hue_set.hue = srv->state->hue;
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_HUE_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void light_hsl_sat_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_hsl_sat_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_hsl_sat_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.hsl_saturation_set.saturation = srv->state->saturation;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+        srv->state->saturation -= srv->tt_delta_saturation;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state->saturation = srv->state->target_saturation;
+    }
+
+    change.hsl_saturation_set.saturation = srv->state->saturation;
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    light_hsl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_HSL_SATURATION_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void light_xyl_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_xyl_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_xyl_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.xyl_set.lightness = srv->state->lightness;
+            change.xyl_set.x = srv->state->x;
+            change.xyl_set.y = srv->state->y;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+        srv->state->lightness -= srv->tt_delta_lightness;
+        srv->state->x -= srv->tt_delta_x;
+        srv->state->y -= srv->tt_delta_y;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state->lightness = srv->state->target_lightness;
+        srv->state->x = srv->state->target_x;
+        srv->state->y = srv->state->target_y;
+    }
+
+    change.xyl_set.lightness = srv->state->lightness;
+    change.xyl_set.x = srv->state->x;
+    change.xyl_set.y = srv->state->y;
+    bt_mesh_lighting_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    light_xyl_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_XYL_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void light_lc_work_handler(struct k_work *work)
+{
+    struct bt_mesh_light_lc_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_light_lc_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_light_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_light_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.lc_light_onoff_set.onoff = srv->lc->state.light_onoff;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            /**
+             * Because binary states cannot support transitions, when changing to
+             * 0x01 (On), the Generic OnOff state shall change immediately when
+             * the transition starts, and when changing to 0x00, the state shall
+             * change when the transition finishes.
+             */
+            if (srv->lc->state.target_light_onoff == BLE_MESH_STATE_ON) {
+                srv->lc->state.light_onoff = BLE_MESH_STATE_ON;
+                bt_mesh_light_server_state_change_t change = {
+                    .lc_light_onoff_set.onoff = srv->lc->state.light_onoff,
+                };
+                bt_mesh_lighting_server_cb_evt_to_btc(
+                    BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            }
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_light_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->lc->state.light_onoff = srv->lc->state.target_light_onoff;
+        if (srv->lc->state.light_onoff != BLE_MESH_STATE_ON) {
+            change.lc_light_onoff_set.onoff = srv->lc->state.light_onoff;
+            bt_mesh_lighting_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_LIGHTING_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+        }
+    }
+
+    light_lc_publish(srv->model, BLE_MESH_MODEL_OP_LIGHT_LC_LIGHT_ONOFF_STATUS);
+
+    bt_mesh_light_server_unlock();
+    return;
+}
+
+void scene_recall_work_handler(struct k_work *work)
+{
+    struct bt_mesh_scene_srv *srv =
+        CONTAINER_OF(work, struct bt_mesh_scene_srv, transition.timer.work);
+    struct bt_mesh_msg_ctx *ctx = NULL;
+    bt_mesh_time_scene_server_state_change_t change = {0};
+
+    if (srv == NULL || srv->state == NULL ||
+        srv->transition.timer.work._reserved == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    bt_mesh_time_scene_server_lock();
+
+    ctx = (struct bt_mesh_msg_ctx *)srv->transition.timer.work._reserved;
+
+    if (srv->transition.just_started) {
+        srv->transition.just_started = false;
+        if (srv->transition.counter == 0U) {
+            change.scene_recall.scene_number = srv->state->current_scene;
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+            bt_mesh_atomic_clear_bit(srv->transition.flag, BLE_MESH_TRANS_TIMER_START);
+        } else {
+            transition_timer_start(&srv->transition);
+        }
+
+        bt_mesh_time_scene_server_unlock();
+        return;
+    }
+
+    if (srv->transition.counter != 0U) {
+        srv->transition.counter--;
+    }
+
+    if (srv->transition.counter == 0U) {
+        transition_timer_stop(&srv->transition);
+        srv->state->current_scene = srv->state->target_scene;
+        srv->state->in_progress = false;
+        srv->state->target_scene = INVALID_SCENE_NUMBER;
+    }
+
+    change.scene_recall.scene_number = srv->state->current_scene;
+    bt_mesh_time_scene_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, srv->model, ctx, (const u8_t *)&change, sizeof(change));
+
+    scene_publish(srv->model, ctx, BLE_MESH_MODEL_OP_SCENE_STATUS);
+
+    bt_mesh_time_scene_server_unlock();
+    return;
+}
+
+/* Timers related handlers & threads (End) */
+
+void bt_mesh_server_stop_transition(struct bt_mesh_state_transition *transition)
+{
+    memset(transition, 0x0, offsetof(struct bt_mesh_state_transition, flag));
+    if (bt_mesh_atomic_test_and_clear_bit(transition->flag, BLE_MESH_TRANS_TIMER_START)) {
+        k_delayed_work_cancel(&transition->timer);
+    }
+}
+
+void bt_mesh_server_start_transition(struct bt_mesh_state_transition *transition)
+{
+    if (transition->delay) {
+        k_delayed_work_submit(&transition->timer, K_MSEC(5 * transition->delay));
+        bt_mesh_atomic_set_bit(transition->flag, BLE_MESH_TRANS_TIMER_START);
+    } else {
+        k_work_submit(&transition->timer.work);
+    }
+}
+
+/* Messages handlers (End) */

+ 1424 - 0
components/bt/esp_ble_mesh/mesh_models/server/time_scene_server.c

@@ -0,0 +1,1424 @@
+// Copyright 2017-2019 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.
+
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "osi/mutex.h"
+
+#include "mesh_types.h"
+#include "mesh_kernel.h"
+#include "mesh_trace.h"
+#include "mesh.h"
+#include "access.h"
+#include "model_opcode.h"
+#include "transport.h"
+
+#include "server_common.h"
+#include "state_binding.h"
+#include "state_transition.h"
+#include "time_scene_server.h"
+
+#include "btc_ble_mesh_time_scene_model.h"
+
+static osi_mutex_t time_scene_server_mutex;
+
+static void bt_mesh_time_scene_server_mutex_new(void)
+{
+    if (!time_scene_server_mutex) {
+        osi_mutex_new(&time_scene_server_mutex);
+        __ASSERT(time_scene_server_mutex, "%s, fail", __func__);
+    }
+}
+
+void bt_mesh_time_scene_server_lock(void)
+{
+    osi_mutex_lock(&time_scene_server_mutex, OSI_MUTEX_MAX_TIMEOUT);
+}
+
+void bt_mesh_time_scene_server_unlock(void)
+{
+    osi_mutex_unlock(&time_scene_server_mutex);
+}
+
+/* message handlers (Start) */
+
+/* Time Server & Time Setup Server message handlers */
+static void send_time_status(struct bt_mesh_model *model,
+                             struct bt_mesh_msg_ctx *ctx,
+                             bool publish, u16_t opcode)
+{
+    struct net_buf_simple *msg = NULL;
+    u8_t zero[5] = {0};
+    u8_t length = 1 + 10;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, opcode);
+    switch (opcode) {
+    case BLE_MESH_MODEL_OP_TIME_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_TIME_SRV) {
+            struct bt_mesh_time_srv *srv = model->user_data;
+            net_buf_simple_add_mem(msg, srv->state->time.tai_seconds, TAI_SECONDS_LEN);
+            if (memcmp(srv->state->time.tai_seconds, zero, TAI_SECONDS_LEN)) {
+                net_buf_simple_add_u8(msg, srv->state->time.subsecond);
+                /**
+                 * Set the Uncertainty field to a value that is a sum of the value of
+                 * the Uncertainty state and an estimated time it will take the message
+                 * to be processed before being sent on the radio interface.
+                 *
+                 * TODO: how to estimate the processing time?
+                 */
+                net_buf_simple_add_u8(msg, srv->state->time.uncertainty);
+                net_buf_simple_add_le16(msg,
+                    (srv->state->time.tai_utc_delta_curr << 1) | srv->state->time.time_authority);
+                net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_curr);
+            }
+        } else if (model->id == BLE_MESH_MODEL_ID_TIME_SETUP_SRV) {
+            struct bt_mesh_time_setup_srv *srv = model->user_data;
+            net_buf_simple_add_mem(msg, srv->state->time.tai_seconds, TAI_SECONDS_LEN);
+            if (memcmp(srv->state->time.tai_seconds, zero, TAI_SECONDS_LEN)) {
+                net_buf_simple_add_u8(msg, srv->state->time.subsecond);
+                net_buf_simple_add_u8(msg, srv->state->time.uncertainty);
+                net_buf_simple_add_le16(msg,
+                    (srv->state->time.tai_utc_delta_curr << 1) | srv->state->time.time_authority);
+                net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_curr);
+            }
+        }
+        break;
+    case BLE_MESH_MODEL_OP_TIME_ZONE_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_TIME_SRV) {
+            struct bt_mesh_time_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_curr);
+            net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_new);
+            net_buf_simple_add_mem(msg, srv->state->time.tai_zone_change, TAI_OF_ZONE_CHANGE_LEN);
+        } else if (model->id == BLE_MESH_MODEL_ID_TIME_SETUP_SRV) {
+            struct bt_mesh_time_setup_srv *srv = model->user_data;
+            net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_curr);
+            net_buf_simple_add_u8(msg, srv->state->time.time_zone_offset_new);
+            net_buf_simple_add_mem(msg, srv->state->time.tai_zone_change, TAI_OF_ZONE_CHANGE_LEN);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS:
+        if (model->id == BLE_MESH_MODEL_ID_TIME_SRV) {
+            struct bt_mesh_time_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->time.tai_utc_delta_curr);
+            net_buf_simple_add_le16(msg, srv->state->time.tai_utc_delta_new);
+            net_buf_simple_add_mem(msg, srv->state->time.tai_delta_change, TAI_OF_DELTA_CHANGE_LEN);
+        } else if (model->id == BLE_MESH_MODEL_ID_TIME_SETUP_SRV) {
+            struct bt_mesh_time_setup_srv *srv = model->user_data;
+            net_buf_simple_add_le16(msg, srv->state->time.tai_utc_delta_curr);
+            net_buf_simple_add_le16(msg, srv->state->time.tai_utc_delta_new);
+            net_buf_simple_add_mem(msg, srv->state->time.tai_delta_change, TAI_OF_DELTA_CHANGE_LEN);
+        }
+        break;
+    case BLE_MESH_MODEL_OP_TIME_ROLE_STATUS: {
+        struct bt_mesh_time_setup_srv *srv = model->user_data;
+        net_buf_simple_add_u8(msg, srv->state->time_role);
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown Time status opcode 0x%04x", __func__, opcode);
+        if (publish == false) {
+            bt_mesh_free_buf(msg);
+        }
+        return;
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void time_get(struct bt_mesh_model *model,
+                     struct bt_mesh_msg_ctx *ctx,
+                     struct net_buf_simple *buf)
+{
+    struct bt_mesh_server_rsp_ctrl *rsp_ctrl = NULL;
+    u8_t zero[5] = {0};
+    u16_t opcode, val;
+    u8_t prev_ttl;
+
+    if (model->user_data == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_TIME_SRV: {
+        struct bt_mesh_time_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Time Server state", __func__);
+            return;
+        }
+        rsp_ctrl = &srv->rsp_ctrl;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_TIME_SETUP_SRV: {
+        struct bt_mesh_time_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Time Setup Server state", __func__);
+            return;
+        }
+        rsp_ctrl = &srv->rsp_ctrl;
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Time Server 0x%04x", __func__, model->id);
+        return;
+    }
+
+    if (rsp_ctrl->get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        if (ctx->recv_op != BLE_MESH_MODEL_OP_TIME_STATUS) {
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+            return;
+        }
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_TIME_GET:
+        opcode = BLE_MESH_MODEL_OP_TIME_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_TIME_STATUS: {
+        struct bt_mesh_time_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, Invalid Time Server state", __func__);
+            return;
+        }
+        if (srv->state->time_role != TIME_RELAY &&
+            srv->state->time_role != TIME_CLINET) {
+            /**
+             * If the value of the Time Role state of the element is 0x00 (None) or
+             * 0x01 (Time Authority), the message shall be ignored.
+             */
+            return;
+        }
+        if (rsp_ctrl->status_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_recv_status_msg_t status = {0};
+            memcpy(status.time_status.tai_seconds, buf->data, TAI_SECONDS_LEN);
+            net_buf_simple_pull(buf, TAI_SECONDS_LEN);
+            if (memcmp(status.time_status.tai_seconds, zero, TAI_SECONDS_LEN)) {
+                if (buf->len != TAI_SECONDS_LEN) {
+                    BT_ERR("%s, Invalid Time Status length %d", __func__, buf->len + TAI_SECONDS_LEN);
+                    return;
+                }
+                status.time_status.subsecond = net_buf_simple_pull_u8(buf);
+                status.time_status.uncertainty = net_buf_simple_pull_u8(buf);
+                val = net_buf_simple_pull_le16(buf);
+                status.time_status.time_authority = val & BIT(0);
+                status.time_status.tai_utc_delta = (val >> 1) & BIT_MASK(15);
+                status.time_status.time_zone_offset = net_buf_simple_pull_u8(buf);
+            }
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_STATUS_MSG, model, ctx, (const u8_t *)&status, sizeof(status));
+            return;
+        }
+        memcpy(srv->state->time.tai_seconds, buf->data, TAI_SECONDS_LEN);
+        net_buf_simple_pull(buf, TAI_SECONDS_LEN);
+        /**
+         * If the TAI Seconds field is 0x0000000000 the Subsecond, Uncertainty,
+         * Time Authority, TAI-UTC Delta and Time Zone Offset fields shall be
+         * omitted; otherwise these fields shall be present.
+         */
+        if (memcmp(srv->state->time.tai_seconds, zero, TAI_SECONDS_LEN)) {
+            if (buf->len != TAI_SECONDS_LEN) {
+                BT_ERR("%s, Invalid Time Status length %d", __func__, buf->len + TAI_SECONDS_LEN);
+                return;
+            }
+            srv->state->time.subsecond = net_buf_simple_pull_u8(buf);
+            srv->state->time.uncertainty = net_buf_simple_pull_u8(buf);
+            val = net_buf_simple_pull_le16(buf);
+            srv->state->time.tai_utc_delta_curr = (val >> 1) & BIT_MASK(15);
+            srv->state->time.time_zone_offset_curr = net_buf_simple_pull_u8(buf);
+        }
+
+        bt_mesh_time_scene_server_state_change_t change = {0};
+        memcpy(change.time_status.tai_seconds, srv->state->time.tai_seconds, TAI_SECONDS_LEN);
+        change.time_status.subsecond = srv->state->time.subsecond;
+        change.time_status.uncertainty = srv->state->time.uncertainty;
+        change.time_status.time_authority = srv->state->time.time_authority;
+        change.time_status.tai_utc_delta_curr = srv->state->time.subsecond;
+        bt_mesh_time_scene_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        if (model->pub == NULL || model->pub->msg == NULL ||
+            model->pub->addr == BLE_MESH_ADDR_UNASSIGNED) {
+            return;
+        }
+        prev_ttl = model->pub->ttl;
+        if (srv->state->time_role == TIME_RELAY) {
+            /**
+             * Shall publish a Time Status message using TTL = 0 if the value of the
+             * Time Role state is 0x02 (Time Relay) and the Publish Address for the
+             * Time Server model is not set to unassigned address.
+             */
+            model->pub->ttl = 0U;
+        }
+        send_time_status(model, NULL, true, BLE_MESH_MODEL_OP_TIME_STATUS);
+        /* Restore model publication ttl value */
+        model->pub->ttl = prev_ttl;
+        return;
+    }
+    case BLE_MESH_MODEL_OP_TIME_ZONE_GET:
+        opcode = BLE_MESH_MODEL_OP_TIME_ZONE_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET:
+        opcode = BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_TIME_ROLE_GET:
+        opcode = BLE_MESH_MODEL_OP_TIME_ROLE_STATUS;
+        break;
+    default:
+        BT_WARN("%s, Unknown Time Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    send_time_status(model, ctx, false, opcode);
+    return;
+}
+
+static void time_set(struct bt_mesh_model *model,
+                     struct bt_mesh_msg_ctx *ctx,
+                     struct net_buf_simple *buf)
+{
+    struct bt_mesh_time_setup_srv *srv = model->user_data;
+    bt_mesh_time_scene_server_state_change_t change = {0};
+    u16_t opcode, val;
+    u8_t role;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_TIME_SET:
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_recv_set_msg_t set = {0};
+            memcpy(set.time_set.tai_seconds, buf->data, TAI_SECONDS_LEN);
+            net_buf_simple_pull(buf, TAI_SECONDS_LEN);
+            set.time_set.subsecond = net_buf_simple_pull_u8(buf);
+            set.time_set.uncertainty = net_buf_simple_pull_u8(buf);
+            val = net_buf_simple_pull_le16(buf);
+            set.time_set.time_authority = val & BIT(0);
+            set.time_set.tai_utc_delta = (val >> 1) & BIT_MASK(15);
+            set.time_set.time_zone_offset = net_buf_simple_pull_u8(buf);
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+            return;
+        }
+        memcpy(srv->state->time.tai_seconds, buf->data, TAI_SECONDS_LEN);
+        net_buf_simple_pull(buf, TAI_SECONDS_LEN);
+        srv->state->time.subsecond = net_buf_simple_pull_u8(buf);
+        srv->state->time.uncertainty = net_buf_simple_pull_u8(buf);
+        val = net_buf_simple_pull_le16(buf);
+        srv->state->time.time_authority = val & BIT(0);
+        srv->state->time.tai_utc_delta_curr = (val >> 1) & BIT_MASK(15);
+        srv->state->time.time_zone_offset_curr = net_buf_simple_pull_u8(buf);
+        opcode = BLE_MESH_MODEL_OP_TIME_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_TIME_ZONE_SET:
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_recv_set_msg_t set = {0};
+            set.time_zone_set.time_zone_offset_new = net_buf_simple_pull_u8(buf);
+            memcpy(set.time_zone_set.tai_zone_change, buf->data, TAI_OF_ZONE_CHANGE_LEN);
+            net_buf_simple_pull(buf, TAI_OF_ZONE_CHANGE_LEN);
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+            return;
+        }
+        srv->state->time.time_zone_offset_new = net_buf_simple_pull_u8(buf);
+        memcpy(srv->state->time.tai_zone_change, buf->data, TAI_OF_ZONE_CHANGE_LEN);
+        net_buf_simple_pull(buf, TAI_OF_ZONE_CHANGE_LEN);
+        opcode = BLE_MESH_MODEL_OP_TIME_ZONE_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET:
+        val = net_buf_simple_pull_le16(buf);
+        if ((val >> 15) & BIT(0)) {
+            BT_ERR("%s, Invalid Padding value 1", __func__);
+            return;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_recv_set_msg_t set = {0};
+            set.tai_utc_delta_set.tai_utc_delta_new = val & BIT_MASK(15);
+            memcpy(set.tai_utc_delta_set.tai_delta_change, buf->data, TAI_OF_DELTA_CHANGE_LEN);
+            net_buf_simple_pull(buf, TAI_OF_DELTA_CHANGE_LEN);
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+            return;
+        }
+        srv->state->time.tai_utc_delta_new = val & BIT_MASK(15);
+        memcpy(srv->state->time.tai_delta_change, buf->data, TAI_OF_DELTA_CHANGE_LEN);
+        net_buf_simple_pull(buf, TAI_OF_DELTA_CHANGE_LEN);
+        opcode = BLE_MESH_MODEL_OP_TAI_UTC_DELTA_STATUS;
+        break;
+    case BLE_MESH_MODEL_OP_TIME_ROLE_SET:
+        role = net_buf_simple_pull_u8(buf);
+        if (role > TIME_CLINET) {
+            BT_ERR("%s, Invalid Time Role 0x%02x", __func__, role);
+            return;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_recv_set_msg_t set = {
+                .time_role_set.time_role = role,
+            };
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+            return;
+        }
+        srv->state->time_role = role;
+        opcode = BLE_MESH_MODEL_OP_TIME_ROLE_STATUS;
+        break;
+    default:
+        BT_ERR("%s, Unknown Time Set opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_TIME_SET:
+        memcpy(change.time_set.tai_seconds, srv->state->time.tai_seconds, TAI_SECONDS_LEN);
+        change.time_set.subsecond = srv->state->time.subsecond;
+        change.time_set.uncertainty = srv->state->time.uncertainty;
+        change.time_set.time_authority = srv->state->time.time_authority;
+        change.time_set.tai_utc_delta_curr = srv->state->time.subsecond;
+        break;
+    case BLE_MESH_MODEL_OP_TIME_ZONE_SET:
+        change.time_zone_set.time_zone_offset_new = srv->state->time.time_zone_offset_new;
+        memcpy(change.time_zone_set.tai_zone_change, srv->state->time.tai_zone_change, TAI_OF_ZONE_CHANGE_LEN);
+        break;
+    case BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET:
+        change.tai_utc_delta_set.tai_utc_delta_new = srv->state->time.tai_utc_delta_new;
+        memcpy(change.tai_utc_delta_set.tai_delta_change, srv->state->time.tai_delta_change, TAI_OF_DELTA_CHANGE_LEN);
+        break;
+    case BLE_MESH_MODEL_OP_TIME_ROLE_SET:
+        change.time_role_set.role = srv->state->time_role;
+        break;
+    default:
+        return;
+    }
+
+    bt_mesh_time_scene_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    /* Send corresponding time status message */
+    send_time_status(model, ctx, false, opcode);
+    return;
+}
+
+/* Scene Server & Scene Setup Server message handlers */
+static void send_scene_status(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              bool publish)
+{
+    struct bt_mesh_scene_srv *srv = model->user_data;
+    struct net_buf_simple *msg = NULL;
+    u8_t length = 1 + 6;
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(length + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, length);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SCENE_STATUS);
+    /**
+     * If the message is sent as a reply to the Scene Recall message, the
+     * Status Code field identifies the result of the related operation;
+     * otherwise, the Status Code field shall be set to Success.
+     */
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_GET) {
+        net_buf_simple_add_u8(msg, SCENE_SUCCESS);
+    } else {
+        net_buf_simple_add_u8(msg, srv->state->status_code);
+    }
+    net_buf_simple_add_le16(msg, srv->state->current_scene);
+    /**
+     * When an element is in the process of changing the Scene state, the
+     * Target Scene field identifies the target Scene Number of the target
+     * Scene state the element is to reach.
+     * When an element is not in the process of changing the Scene state,
+     * the Target Scene field shall be omitted.
+     */
+    if (srv->transition.counter) {
+        bt_mesh_server_calc_remain_time(&srv->transition);
+        net_buf_simple_add_le16(msg, srv->state->target_scene);
+        net_buf_simple_add_u8(msg, srv->transition.remain_time);
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void send_scene_register_status(struct bt_mesh_model *model,
+                                       struct bt_mesh_msg_ctx *ctx,
+                                       u8_t status_code, bool publish)
+{
+    struct bt_mesh_scene_setup_srv *srv = model->user_data;
+    struct scene_register *scene = NULL;
+    struct net_buf_simple *msg = NULL;
+    u16_t total_len = 9;
+    u16_t i;
+
+    if (ctx == NULL && publish == false) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return;
+    }
+
+    if (publish == false) {
+        msg = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN));
+        if (msg == NULL) {
+            BT_ERR("%s, Failed to allocate memory", __func__);
+            return;
+        }
+    } else {
+        msg = bt_mesh_server_get_pub_msg(model, 5);
+        if (msg == NULL) {
+            return;
+        }
+    }
+
+    bt_mesh_model_msg_init(msg, BLE_MESH_MODEL_OP_SCENE_REGISTER_STATUS);
+    net_buf_simple_add_u8(msg, status_code);
+    net_buf_simple_add_le16(msg, srv->state->current_scene);
+
+    for (i = 0U; i < srv->state->scene_count; i++) {
+        scene = &srv->state->scenes[i];
+        if (scene->scene_number != INVALID_SCENE_NUMBER) {
+            total_len += SCENE_NUMBER_LEN;
+            if ((publish == false && total_len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SERVER_RSP_MAX_LEN)) ||
+                (publish == true && total_len > msg->size + BLE_MESH_SERVER_TRANS_MIC_SIZE)) {
+                /* Add this in case the message is too long */
+                break;
+            }
+            net_buf_simple_add_le16(msg, scene->scene_number);
+        }
+    }
+
+    if (publish == false) {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, msg, NULL, NULL));
+        bt_mesh_free_buf(msg);
+    } else {
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_publish(model));
+    }
+    return;
+}
+
+static void scene_get(struct bt_mesh_model *model,
+                      struct bt_mesh_msg_ctx *ctx,
+                      struct net_buf_simple *buf)
+{
+    struct bt_mesh_scene_srv *srv = model->user_data;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_time_scene_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_SCENE_GET:
+        send_scene_status(model, ctx, false);
+        return;
+    case BLE_MESH_MODEL_OP_SCENE_REGISTER_GET:
+        /**
+         * When a Scene Server receives a Scene Register Get message, it shall
+         * respond with a Scene Register Status message, setting the Status
+         * Code field to Success.
+         */
+        send_scene_register_status(model, ctx, SCENE_SUCCESS, false);
+        return;
+    default:
+        BT_WARN("%s, Unknown Scene Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+}
+
+void scene_publish(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, u16_t opcode)
+{
+    struct bt_mesh_scene_srv *srv = model->user_data;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    send_scene_status(model, ctx, true);
+    return;
+}
+
+static void scene_recall(struct bt_mesh_model *model,
+                         struct bt_mesh_msg_ctx *ctx,
+                         struct net_buf_simple *buf)
+{
+    struct bt_mesh_scene_srv *srv = model->user_data;
+    struct scene_register *scene = NULL;
+    u8_t tid, trans_time, delay;
+    u16_t scene_number;
+    bool optional;
+    s64_t now;
+    u16_t i;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    scene_number = net_buf_simple_pull_le16(buf);
+    if (scene_number == INVALID_SCENE_NUMBER) {
+        BT_ERR("%s, Invalid Scene Number 0x0000", __func__);
+        return;
+    }
+    tid = net_buf_simple_pull_u8(buf);
+
+    if (bt_mesh_server_get_optional(model, buf, &trans_time, &delay, &optional)) {
+        return;
+    }
+
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_time_scene_server_recv_set_msg_t set = {
+            .scene_recall.op_en = optional,
+            .scene_recall.scene_number = scene_number,
+            .scene_recall.tid = tid,
+            .scene_recall.trans_time = trans_time,
+            .scene_recall.delay = delay,
+        };
+        bt_mesh_time_scene_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    for (i = 0U; i < srv->state->scene_count; i++) {
+        scene = &srv->state->scenes[i];
+        if (scene->scene_number == scene_number) {
+            break;
+        }
+    }
+    if (i == srv->state->scene_count) {
+        BT_WARN("%s, Scene Number 0x%04x not exist", __func__, scene_number);
+        srv->state->status_code = SCENE_NOT_FOUND;
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_RECALL) {
+            send_scene_status(model, ctx, false);
+        }
+        send_scene_status(model, ctx, true);
+        return;
+    }
+    srv->state->status_code = SCENE_SUCCESS;
+
+    /* Mesh Model Spec doesn't mention about this operation. */
+    if (bt_mesh_is_server_recv_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now)) {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_RECALL) {
+            send_scene_status(model, ctx, false);
+        }
+        send_scene_status(model, ctx, true);
+        /* In this condition, no event will be callback to application layer */
+        return;
+    }
+
+    bt_mesh_time_scene_server_lock();
+
+    bt_mesh_server_stop_transition(&srv->transition);
+    bt_mesh_server_update_last_msg(&srv->last, tid, ctx->addr, ctx->recv_dst, &now);
+
+    srv->state->in_progress = false;
+    /**
+     * When the scene transition is not in progress, the value of the Target
+     * Scene state shall be set to 0x0000.
+     */
+    srv->state->target_scene = INVALID_SCENE_NUMBER;
+
+    /**
+     * If the target state is equal to the current state, the transition
+     * shall not be started and is considered complete.
+     */
+    if (srv->state->current_scene != scene_number) {
+        scene_tt_values(srv, trans_time, delay);
+    } else {
+        if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_RECALL) {
+            send_scene_status(model, ctx, false);
+        }
+        send_scene_status(model, ctx, true);
+
+        bt_mesh_time_scene_server_state_change_t change = {
+            .scene_recall.scene_number = scene_number,
+        };
+        bt_mesh_time_scene_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+        bt_mesh_time_scene_server_unlock();
+        return;
+    }
+
+    /* Copy the ctx of the received message */
+    if (srv->transition.timer.work._reserved) {
+        memcpy(srv->transition.timer.work._reserved, ctx, sizeof(struct bt_mesh_msg_ctx));
+    }
+
+    /* For Instantaneous Transition */
+    if (srv->transition.counter == 0U) {
+        srv->state->current_scene = scene_number;
+    } else {
+        /**
+         * When a scene transition is in progress, the value of the Current
+         * Scene state shall be set to 0x0000.
+         */
+        srv->state->in_progress = true;
+        srv->state->current_scene = INVALID_SCENE_NUMBER;
+        srv->state->target_scene = scene_number;
+    }
+
+    srv->transition.just_started = true;
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_RECALL) {
+        send_scene_status(model, ctx, false);
+    }
+    send_scene_status(model, ctx, true);
+
+    bt_mesh_time_scene_server_unlock();
+
+    bt_mesh_server_start_transition(&srv->transition);
+    return;
+}
+
+static void scene_action(struct bt_mesh_model *model,
+                         struct bt_mesh_msg_ctx *ctx,
+                         struct net_buf_simple *buf)
+{
+    struct bt_mesh_scene_setup_srv *srv = model->user_data;
+    struct scene_register *scene = NULL;
+    u16_t scene_number;
+    u16_t i;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    scene_number = net_buf_simple_pull_le16(buf);
+    if (scene_number == INVALID_SCENE_NUMBER) {
+        BT_ERR("%s, Invalid Scene number 0x0000", __func__);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_SCENE_STORE:
+    case BLE_MESH_MODEL_OP_SCENE_STORE_UNACK: {
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_recv_set_msg_t set = {
+                .scene_store.scene_number = scene_number,
+            };
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+            return;
+        }
+        /* Try to find a matching Scene Number */
+        for (i = 0U; i < srv->state->scene_count; i++) {
+            scene = &srv->state->scenes[i];
+            if (scene->scene_number == scene_number) {
+                srv->state->status_code = SCENE_SUCCESS;
+                srv->state->current_scene = scene_number;
+                break;
+            }
+        }
+        /* Try to find a unset entry if no matching Scene Number is found */
+        if (i == srv->state->scene_count) {
+            BT_DBG("%s, No matching Scene Number 0x%04x found", __func__, scene_number);
+            for (i = 0U; i < srv->state->scene_count; i++) {
+                scene = &srv->state->scenes[i];
+                if (scene->scene_number == INVALID_SCENE_NUMBER) {
+                    scene->scene_number = scene_number;
+                    srv->state->status_code = SCENE_SUCCESS;
+                    srv->state->current_scene = scene_number;
+                    break;
+                }
+            }
+            if (i == srv->state->scene_count) {
+                BT_WARN("%s, Scene Register full", __func__);
+                srv->state->status_code = SCENE_REG_FULL;
+                /* Get the Scene Number of the currently active scene */
+                for (i = 0; i < srv->state->scene_count; i++) {
+                    scene = &srv->state->scenes[i];
+                    if (scene->scene_number != INVALID_SCENE_NUMBER) {
+                        srv->state->current_scene = scene->scene_number;
+                        break;
+                    }
+                }
+                if (i == srv->state->scene_count) {
+                    /* A value of 0x0000 when no scene is active */
+                    srv->state->current_scene = INVALID_SCENE_NUMBER;
+                }
+            }
+        }
+
+        if (srv->state->in_progress == true) {
+            /**
+             * When the scene transition is in progress and a new Scene Number is
+             * stored in the Scene Register as a result of Scene Store operation,
+             * the Target Scene state shall be set to the new Scene Number.
+             */
+            srv->state->target_scene = scene_number;
+        }
+        if (srv->state->status_code == SCENE_SUCCESS) {
+            bt_mesh_time_scene_server_state_change_t change = {
+                .scene_store.scene_number = scene_number,
+            };
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        }
+        break;
+    }
+    case BLE_MESH_MODEL_OP_SCENE_DELETE:
+    case BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK: {
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_recv_set_msg_t set = {
+                .scene_delete.scene_number = scene_number,
+            };
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+            return;
+        }
+        for (i = 0U; i < srv->state->scene_count; i++) {
+            scene = &srv->state->scenes[i];
+            if (scene->scene_number == scene_number) {
+                scene->scene_number = INVALID_SCENE_NUMBER;
+                break;
+            }
+        }
+        if (i == srv->state->scene_count) {
+            BT_WARN("%s, Scene Number 0x%04x not exist", __func__, scene_number);
+            /**
+             * When a Scene Server receives a Scene Delete message with the Scene
+             * Number value that does not match a Scene Number stored within the
+             * Scene Register state, it shall respond with the Scene Register
+             * Status message, setting the Status Code field to Success.
+             */
+        }
+        srv->state->status_code = SCENE_SUCCESS;
+        if (srv->state->current_scene == scene_number) {
+            /**
+             * When the Current Scene Number is deleted from a Scene Register state
+             * as a result of Scene Delete operation, the Current Scene state shall
+             * be set to 0x0000.
+             */
+            srv->state->current_scene = INVALID_SCENE_NUMBER;
+        } else {
+            /**
+             * MMDL/SR/SCES/BV-02-C requires response with Current Scene set to the
+             * latest Scene Number, but this is not mentioned in the spec.
+             *
+             * TODO: Do we need a timestamp for each newly added scene?
+             */
+            for (i = srv->state->scene_count; i > 0; i--) {
+                scene = &srv->state->scenes[i - 1];
+                if (scene->scene_number != INVALID_SCENE_NUMBER) {
+                    srv->state->current_scene = scene->scene_number;
+                    break;
+                }
+            }
+            if (i == 0U) {
+                /* A value of 0x0000 when no scene is active */
+                srv->state->current_scene = INVALID_SCENE_NUMBER;
+            }
+        }
+
+        if (srv->state->target_scene == scene_number &&
+            srv->state->in_progress == true) {
+            /**
+             * When the scene transition is in progress and the target Scene Number
+             * is deleted from a Scene Register state as a result of Scene Delete
+             * operation, the Target Scene state shall be set to 0x0000.
+             */
+            srv->state->target_scene = INVALID_SCENE_NUMBER;
+
+            /**
+             * When a scene is deleted when a scene transition to the deleted Scene
+             * Number is in progress, the scene transition shall be terminated, but
+             * individual model transitions shall not be terminated.
+             */
+            struct bt_mesh_scene_srv *scene_srv = NULL;
+            struct bt_mesh_model *scene_model = NULL;
+
+            scene_model = bt_mesh_model_find(bt_mesh_model_elem(model), BLE_MESH_MODEL_ID_SCENE_SRV);
+            if (scene_model == NULL) {
+                BT_ERR("%s, Scene Server is not present in the element", __func__);
+                break;
+            }
+
+            scene_srv = scene_model->user_data;
+            if (scene_srv == NULL || scene_srv->state == NULL) {
+                BT_ERR("%s, Invalid Scene Server parameter", __func__);
+                break;
+            }
+
+            if (srv->state != scene_srv->state) {
+                /**
+                 * Add this in case the Scene Setup Server is extending the Scene
+                 * Server in another element.
+                 */
+                BT_WARN("%s, Different Scene state in Scene Server & Scene Setup Server", __func__);
+                break;
+            }
+
+            scene_srv->state->in_progress = false;
+            bt_mesh_server_stop_transition(&scene_srv->transition);
+        }
+
+        bt_mesh_time_scene_server_state_change_t change = {
+            .scene_delete.scene_number = scene_number,
+        };
+        bt_mesh_time_scene_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+        break;
+    }
+    default:
+        BT_ERR("%s, Unknown Scene setup action opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_STORE ||
+        ctx->recv_op == BLE_MESH_MODEL_OP_SCENE_DELETE) {
+        send_scene_register_status(model, ctx, srv->state->status_code, false);
+    }
+    send_scene_register_status(model, NULL, srv->state->status_code, true);
+
+    return;
+}
+
+static u16_t get_schedule_reg_bit(struct bt_mesh_scheduler_state *state)
+{
+    u16_t val = 0;
+    u8_t i;
+
+    for (i = 0U; i < state->schedule_count; i++) {
+        if (state->schedules[i].in_use) {
+            val |= (1 << i);
+        }
+    }
+
+    return val;
+}
+
+static u64_t get_schedule_reg_state(struct bt_mesh_scheduler_state *state, u8_t index)
+{
+    struct schedule_register *reg = &state->schedules[index];
+    u64_t val;
+
+    val  = ((u64_t)(reg->year) << 4) | index;
+    val |= ((u64_t)(reg->day) << 23) | ((u64_t)(reg->month) << 11);
+    val |= ((u64_t)(reg->minute) << 33) | ((u64_t)(reg->hour) << 28);
+    val |= ((u64_t)(reg->day_of_week) << 45) | ((u64_t)(reg->second) << 39);
+    val |= ((u64_t)(reg->trans_time) << 56) | ((u64_t)(reg->action) << 52);
+
+    return val;
+}
+
+static void send_scheduler_act_status(struct bt_mesh_model *model,
+                                      struct bt_mesh_msg_ctx *ctx,
+                                      u8_t index)
+{
+    NET_BUF_SIMPLE_DEFINE(msg, 1 + 10 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+    u64_t value;
+
+    bt_mesh_model_msg_init(&msg, BLE_MESH_MODEL_OP_SCHEDULER_ACT_STATUS);
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_SCHEDULER_SRV: {
+        struct bt_mesh_scheduler_srv *srv = model->user_data;
+        value = get_schedule_reg_state(srv->state, index);
+        net_buf_simple_add_le32(&msg, (u32_t)value);
+        net_buf_simple_add_le32(&msg, (u32_t)(value >> 32));
+        net_buf_simple_add_le16(&msg, srv->state->schedules[index].scene_number);
+        break;
+    }
+    case BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV: {
+        struct bt_mesh_scheduler_setup_srv *srv = model->user_data;
+        value = get_schedule_reg_state(srv->state, index);
+        net_buf_simple_add_le32(&msg, (u32_t)value);
+        net_buf_simple_add_le32(&msg, (u32_t)(value >> 32));
+        net_buf_simple_add_le16(&msg, srv->state->schedules[index].scene_number);
+        break;
+    }
+    default:
+        BT_ERR("%s, Invalid Scheduler Server 0x%04x", __func__, model->id);
+        return;
+    }
+
+    BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL));
+    return;
+}
+
+static void scheduler_get(struct bt_mesh_model *model,
+                          struct bt_mesh_msg_ctx *ctx,
+                          struct net_buf_simple *buf)
+{
+    struct bt_mesh_scheduler_srv *srv = model->user_data;
+    NET_BUF_SIMPLE_DEFINE(msg, 2 + 2 + BLE_MESH_SERVER_TRANS_MIC_SIZE);
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    switch (ctx->recv_op) {
+    case BLE_MESH_MODEL_OP_SCHEDULER_GET: {
+        if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, NULL, 0);
+            return;
+        }
+
+        bt_mesh_model_msg_init(&msg, BLE_MESH_MODEL_OP_SCHEDULER_STATUS);
+        net_buf_simple_add_le16(&msg, get_schedule_reg_bit(srv->state));
+        BLE_MESH_CHECK_SEND_STATUS(bt_mesh_model_send(model, ctx, &msg, NULL, NULL));
+        return;
+    }
+    case BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET: {
+        u8_t index = net_buf_simple_pull_u8(buf);
+        if (index > SCHEDULE_ENTRY_MAX_INDEX) {
+            BT_ERR("%s, Invalid Scheduler Register Entry index 0x%02x", __func__, index);
+            return;
+        }
+
+        if (srv->rsp_ctrl.get_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+            bt_mesh_time_scene_server_recv_get_msg_t get = {
+                .scheduler_act_get.index = index,
+            };
+            bt_mesh_time_scene_server_cb_evt_to_btc(
+                BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_GET_MSG, model, ctx, (const u8_t *)&get, sizeof(get));
+            return;
+        }
+
+        send_scheduler_act_status(model, ctx, index);
+        return;
+    }
+    default:
+        BT_WARN("%s, Unknown Scheduler Get opcode 0x%04x", __func__, ctx->recv_op);
+        return;
+    }
+}
+
+static void scheduler_act_set(struct bt_mesh_model *model,
+                              struct bt_mesh_msg_ctx *ctx,
+                              struct net_buf_simple *buf)
+{
+    /**
+     * A recommended implementation of the Scheduler should calculate the value
+     * of the TAI Seconds of the next scheduled event and put it in a queue of
+     * scheduled events sorted by time. Every second, the first event in the
+     * queue is compared with the value of the Time state. The first event is
+     * executed if it is less than or equal to the Time state and then removed
+     * from the queue. After execution, the Repeat Flag shall be checked, and
+     * the next occurrence of the scheduled event is calculated and put in the
+     * queue.
+     */
+    struct bt_mesh_scheduler_setup_srv *srv = model->user_data;
+    u8_t index, year, day, hour, minute, second, day_of_week, action, trans_time;
+    u16_t month, scene_number;
+    u64_t value;
+
+    if (srv == NULL || srv->state == NULL) {
+        BT_ERR("%s, Invalid model user_data", __func__);
+        return;
+    }
+
+    value  = net_buf_simple_pull_le32(buf);
+    value |= ((u64_t)net_buf_simple_pull_le32(buf) << 32);
+
+    index = value & BIT_MASK(4);
+    year = (value >> 4) & BIT_MASK(7);
+    month = (value >> 11) & BIT_MASK(12);
+    day = (value >> 23) & BIT_MASK(5);
+    hour = (value >> 28) & BIT_MASK(5);
+    minute = (value >> 33) & BIT_MASK(6);
+    second = (value >> 39) & BIT_MASK(6);
+    day_of_week = (value >> 45) & BIT_MASK(7);
+    action = (value >> 52) & BIT_MASK(4);
+    trans_time = (value >> 56) & BIT_MASK(8);
+
+    if (index > SCHEDULE_ENTRY_MAX_INDEX) {
+        BT_ERR("%s, Invalid Scheduler Register Entry index 0x%02x", __func__, index);
+        return;
+    }
+
+    if (year > SCHEDULE_YEAR_ANY_YEAR) {
+        BT_ERR("%s, Invalid Scheduler Register year 0x%02x", __func__, year);
+        return;
+    }
+
+    if (hour > SCHEDULE_HOUR_ONCE_A_DAY) {
+        BT_ERR("%s, Invalid Scheduler Register hour 0x%02x", __func__, hour);
+        return;
+    }
+
+    if (action > SCHEDULE_ACT_SCENE_RECALL && action != SCHEDULE_ACT_NO_ACTION) {
+        BT_ERR("%s, Invalid Scheduler Register action 0x%02x", __func__, action);
+        return;
+    }
+
+    scene_number = net_buf_simple_pull_le16(buf);
+
+    if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_RSP_BY_APP) {
+        bt_mesh_time_scene_server_recv_set_msg_t set = {
+            .scheduler_act_set.index = index,
+            .scheduler_act_set.year = year,
+            .scheduler_act_set.month = month,
+            .scheduler_act_set.day = day,
+            .scheduler_act_set.hour = hour,
+            .scheduler_act_set.minute = minute,
+            .scheduler_act_set.second = second,
+            .scheduler_act_set.day_of_week = day_of_week,
+            .scheduler_act_set.action = action,
+            .scheduler_act_set.trans_time = trans_time,
+            .scheduler_act_set.scene_number = scene_number,
+        };
+        bt_mesh_time_scene_server_cb_evt_to_btc(
+            BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_RECV_SET_MSG, model, ctx, (const u8_t *)&set, sizeof(set));
+        return;
+    }
+
+    srv->state->schedules[index].in_use = true;
+    srv->state->schedules[index].year = year;
+    srv->state->schedules[index].month = month;
+    srv->state->schedules[index].day = day;
+    srv->state->schedules[index].hour = hour;
+    srv->state->schedules[index].minute = minute;
+    srv->state->schedules[index].second = second;
+    srv->state->schedules[index].day_of_week = day_of_week;
+    srv->state->schedules[index].action = action;
+    srv->state->schedules[index].trans_time = trans_time;
+    srv->state->schedules[index].scene_number = scene_number;
+
+    bt_mesh_time_scene_server_state_change_t change = {
+        .scheduler_act_set.index = index,
+        .scheduler_act_set.year = year,
+        .scheduler_act_set.month = month,
+        .scheduler_act_set.day = day,
+        .scheduler_act_set.hour = hour,
+        .scheduler_act_set.minute = minute,
+        .scheduler_act_set.second = second,
+        .scheduler_act_set.day_of_week = day_of_week,
+        .scheduler_act_set.action = action,
+        .scheduler_act_set.trans_time = trans_time,
+        .scheduler_act_set.scene_number = scene_number,
+    };
+    bt_mesh_time_scene_server_cb_evt_to_btc(
+        BTC_BLE_MESH_EVT_TIME_SCENE_SERVER_STATE_CHANGE, model, ctx, (const u8_t *)&change, sizeof(change));
+
+    if (ctx->recv_op == BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET) {
+        send_scheduler_act_status(model, ctx, index);
+    }
+
+    return;
+}
+
+/* message handlers (End) */
+
+/* Mapping of message handlers for Time Server (0x1200) */
+const struct bt_mesh_model_op time_srv_op[] = {
+    { BLE_MESH_MODEL_OP_TIME_GET,          0, time_get },
+    { BLE_MESH_MODEL_OP_TIME_STATUS,       5, time_get },
+    { BLE_MESH_MODEL_OP_TIME_ZONE_GET,     0, time_get },
+    { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_GET, 0, time_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Time Setup Server (0x1201) */
+const struct bt_mesh_model_op time_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_TIME_SET,          10, time_set },
+    { BLE_MESH_MODEL_OP_TIME_ZONE_SET,      6, time_set },
+    { BLE_MESH_MODEL_OP_TAI_UTC_DELTA_SET,  7, time_set },
+    { BLE_MESH_MODEL_OP_TIME_ROLE_GET,      0, time_get },
+    { BLE_MESH_MODEL_OP_TIME_ROLE_SET,      1, time_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Scene Server (0x1203) */
+const struct bt_mesh_model_op scene_srv_op[] = {
+    { BLE_MESH_MODEL_OP_SCENE_GET,          0, scene_get    },
+    { BLE_MESH_MODEL_OP_SCENE_RECALL,       3, scene_recall },
+    { BLE_MESH_MODEL_OP_SCENE_RECALL_UNACK, 3, scene_recall },
+    { BLE_MESH_MODEL_OP_SCENE_REGISTER_GET, 0, scene_get    },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Scene Setup Server (0x1204) */
+const struct bt_mesh_model_op scene_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_SCENE_STORE,        2, scene_action },
+    { BLE_MESH_MODEL_OP_SCENE_STORE_UNACK,  2, scene_action },
+    { BLE_MESH_MODEL_OP_SCENE_DELETE,       2, scene_action },
+    { BLE_MESH_MODEL_OP_SCENE_DELETE_UNACK, 2, scene_action },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Scheduler Server (0x1206) */
+const struct bt_mesh_model_op scheduler_srv_op[] = {
+    { BLE_MESH_MODEL_OP_SCHEDULER_GET,     0, scheduler_get },
+    { BLE_MESH_MODEL_OP_SCHEDULER_ACT_GET, 1, scheduler_get },
+    BLE_MESH_MODEL_OP_END,
+};
+
+/* Mapping of message handlers for Scheduler Setup Server (0x1207) */
+const struct bt_mesh_model_op scheduler_setup_srv_op[] = {
+    { BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET,       10, scheduler_act_set },
+    { BLE_MESH_MODEL_OP_SCHEDULER_ACT_SET_UNACK, 10, scheduler_act_set },
+    BLE_MESH_MODEL_OP_END,
+};
+
+static int check_scene_server_init(struct bt_mesh_scenes_state *state)
+{
+    u16_t i;
+
+    if (state->scene_count == 0U || state->scenes == NULL) {
+        BT_ERR("%s, Invalid Scene state", __func__);
+        return -EINVAL;
+    }
+
+    for (i = 0U; i < state->scene_count; i++) {
+        if (state->scenes[i].scene_value == NULL) {
+            BT_ERR("%s, Invalid Scene value, index %d", __func__, i);
+            return -EINVAL;
+        }
+    }
+
+    return 0;
+}
+
+static int time_scene_server_init(struct bt_mesh_model *model)
+{
+    if (model->user_data == NULL) {
+        BT_ERR("%s, No Time Scene Server context provided, model_id 0x%04x", __func__, model->id);
+        return -EINVAL;
+    }
+
+    switch (model->id) {
+    case BLE_MESH_MODEL_ID_TIME_SRV: {
+        struct bt_mesh_time_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Time State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_TIME_SETUP_SRV: {
+        struct bt_mesh_time_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Time State", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_SCENE_SRV: {
+        struct bt_mesh_scene_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Scene State", __func__);
+            return -EINVAL;
+        }
+        if (check_scene_server_init(srv->state)) {
+            return -EINVAL;
+        }
+        if (srv->rsp_ctrl.set_auto_rsp == BLE_MESH_SERVER_AUTO_RSP) {
+            bt_mesh_server_alloc_ctx(&srv->transition.timer.work);
+            k_delayed_work_init(&srv->transition.timer, scene_recall_work_handler);
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_SCENE_SETUP_SRV: {
+        struct bt_mesh_scene_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Scene State", __func__);
+            return -EINVAL;
+        }
+        if (check_scene_server_init(srv->state)) {
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_SCHEDULER_SRV: {
+        struct bt_mesh_scheduler_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Scheduler State", __func__);
+            return -EINVAL;
+        }
+        if (srv->state->schedule_count == 0U || srv->state->schedules == NULL) {
+            BT_ERR("%s, NULL Register Schedule", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    case BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV: {
+        struct bt_mesh_scheduler_setup_srv *srv = model->user_data;
+        if (srv->state == NULL) {
+            BT_ERR("%s, NULL Scheduler State", __func__);
+            return -EINVAL;
+        }
+        if (srv->state->schedule_count == 0U || srv->state->schedules == NULL) {
+            BT_ERR("%s, NULL Register Schedule", __func__);
+            return -EINVAL;
+        }
+        srv->model = model;
+        break;
+    }
+    default:
+        BT_WARN("%s, Unknown Time Scene Server Model, model_id 0x%04x", __func__, model->id);
+        return -EINVAL;
+    }
+
+    bt_mesh_time_scene_server_mutex_new();
+
+    return 0;
+}
+
+int bt_mesh_time_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Time Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /**
+     * When this model is present on an Element, the corresponding Time Setup
+     * Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_TIME_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Time Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return time_scene_server_init(model);
+}
+
+int bt_mesh_time_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    /* This model does not support subscribing nor publishing */
+    if (model->pub) {
+        BT_ERR("%s, Time Setup Server shall not support publication", __func__);
+        return -EINVAL;
+    }
+
+    return time_scene_server_init(model);
+}
+
+int bt_mesh_scene_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Scene Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /* The model may be present only on the Primary element of a node. */
+    if (primary == false) {
+        BT_WARN("%s, Scene Server is not on the Primary element", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    /**
+     * When this model is present on an Element, the corresponding Scene Setup
+     * Server model shall also be present.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_SCENE_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Scene Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return time_scene_server_init(model);
+}
+
+int bt_mesh_scene_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    /* The model may be present only on the Primary element of a node. */
+    if (primary == false) {
+        BT_WARN("%s, Scene Setup Server is not on the Primary element", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return time_scene_server_init(model);
+}
+
+int bt_mesh_scheduler_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    if (model->pub == NULL) {
+        BT_ERR("%s, Scheduler Server has no publication support", __func__);
+        return -EINVAL;
+    }
+
+    /* The model may be present only on the Primary element of a node. */
+    if (primary == false) {
+        BT_WARN("%s, Scheduler Server is not on the Primary element", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    /**
+     * When this model is present on an Element, the corresponding Scheduler
+     * Setup Server model shall also be present. The model requires the Time
+     * Server model shall be present on the element.
+     */
+    struct bt_mesh_elem *element = bt_mesh_model_elem(model);
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_SCHEDULER_SETUP_SRV) == NULL) {
+        BT_WARN("%s, Scheduler Setup Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    if (bt_mesh_model_find(element, BLE_MESH_MODEL_ID_TIME_SRV) == NULL) {
+        BT_WARN("%s, Time Server is not present", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return time_scene_server_init(model);
+}
+
+int bt_mesh_scheduler_setup_srv_init(struct bt_mesh_model *model, bool primary)
+{
+    /* The model may be present only on the Primary element of a node. */
+    if (primary == false) {
+        BT_WARN("%s, Scheduler Setup Server is not on the Primary element", __func__);
+        /* Just give a warning here, continue with the initialization */
+    }
+    return time_scene_server_init(model);
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов