Combine sensor example with light_lightness example

Hi, I am using nrf52840 and Mesh V4.2.0 sensor and light_lightness examples.

I have been able to successfully combine the server side, but I have no idea how to start combining the client part. Is there anyone who has an idea?

Thank you.

  • Hi.

    Could you maybe add some more informationa about what you want to do?

    no idea how to start combining the client part.

    What is it that you want to combine here?

    ______________

    The sensor example is composed of the following minor examples:

    • Sensor server: A minimalistic server that implements a Sensor server model, with the sensor value emulated and controllable by buttons on the board.
    • Sensor client: A minimalistic client that implements two instances of a Sensor client model. Buttons on the board can be used to send messages to the Sensor servers in order to control their cadence and request status messages.

    So there should already both a client and a server example available for you.

    Br,
    Joakim

  • Hi, sorry for the late reply. Yes, I have seen the sensor example so now I'm trying to add the example into the light lightness example.

    Could you maybe add some more informationa about what you want to do?

    So on the server side, when I press button 2, the motion and brightness increase. Similarly, when I press button 1, the motion and brightness decrease. Also whenever I press button 1 or 2, the server will publish the motion and brightness changes to the client, hence I want to combine both the examples together.

    At the client side, whenever I want to set the lightness of the server, it will also send the motion status back to the client along with the lightness.

    So how do I go about doing this? Thank you for your help.

  • Hi again.

    Sorry about the delay. Due to Christmas holiday, there has been low staffing.

    We do have two examples showing the functionality you are after. Have you tried combining the examples? Are you stuck on something specific.

    I might not have the time to merge the examples and upload for you but I can help you if there are some specific part that you are stuck on?

    Br,
    Joakim

  • Hi,

    So I am stuck on trying to publish motion status from my server to client. Please let me know if any of my steps are wrong, thank you. 

    For my server side:

    In main.c, I added:

    /* Application variable for holding instantaneous lightness value */
    static uint16_t m_pwm0_present_actual_lightness;
    static uint8_t present_motion;
    .
    .
    /* Callback for reading the hardware state */
    static void get_lightness_cb(const app_light_lightness_setup_server_t * p_app, uint16_t * p_lightness, uint8_t * p_present_motion)
    {
        *p_lightness = (m_pwm0_present_actual_lightness);
        *p_present_motion = (present_motion);
    }
    .
    .
    static void button_event_handler(uint32_t button_number)
    {
        /* Increase button number because the buttons on the board is marked with 1 to 4 */
        button_number++;
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
        switch (button_number)
        {
            /* Sending value `1` or `2` via RTT will result in LED state to change and trigger
            the STATUS message to inform client about the state change. This is a demonstration of
            state change publication due to local event. */
            case 1:
            {
                m_pwm0_present_actual_lightness = MAX(0, (int32_t)m_pwm0_present_actual_lightness - APP_LIGHTNESS_STEP_SIZE);
                present_motion = (present_motion > 10)
                                      ? present_motion - 10
                                      : 0;
                break;
            }
    
            case 2:
            {
                m_pwm0_present_actual_lightness = MIN(UINT16_MAX,
                                                      (int32_t)m_pwm0_present_actual_lightness + APP_LIGHTNESS_STEP_SIZE);
                present_motion = (present_motion < 90)
                                      ? present_motion + 10
                                      : 100;
                break;
            }
    
            /* Initiate node reset */
            case 4:
            {
                /* Clear all the states to reset the node. */
                if (mesh_stack_is_device_provisioned())
                {
    #if MESH_FEATURE_GATT_PROXY_ENABLED
                    (void) proxy_stop();
    #endif
                    mesh_stack_config_clear();
                    node_reset();
                }
                else
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "The device is unprovisioned. Resetting has no effect.\n");
                }
                break;
            }
    
            default:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);
                break;
        }
    
        if (button_number == 1 || button_number == 2)
        {
            pwm_utils_level_set(&m_pwm, light_lightness_utils_actual_to_generic_level(m_pwm0_present_actual_lightness));
            uint32_t status = app_light_lightness_current_value_publish(&m_light_lightness_server_0);
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "lightness: %d, motion: %d\n", m_pwm0_present_actual_lightness, present_motion);
            if ( status != NRF_SUCCESS)
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Unable to publish status message, status: %d\n", status);
            }
        }
    }
    

    In app_light_lightness.c, my app_light_lightness_current_value_publish:

    uint32_t app_light_lightness_current_value_publish(app_light_lightness_setup_server_t * p_app)
    {
        if (p_app == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        app_transition_abort(&p_app->state.transition);
        p_app->app_light_lightness_get_cb(p_app, &p_app->state.present_lightness, &p_app->state.present_motion);
    
        if (p_app->state.present_lightness >= LIGHT_LIGHTNESS_LAST_MIN)
        {
            ERROR_CHECK(light_lightness_mc_last_state_set(p_app->light_lightness_setup_server.state.handle,
                                                          p_app->state.present_lightness,
                                                          LIGHT_LIGHTNESS_MC_WRITE_DESTINATION_ALL));
        }
        ERROR_CHECK(light_lightness_mc_actual_state_set(p_app->light_lightness_setup_server.state.handle,
                                                        p_app->state.present_lightness));
    
        /* Notify anyone interested that we just got a command to set the lightness */
        if (p_app->app_add_notify.app_notify_set_cb != NULL)
        {
            p_app->app_add_notify.app_notify_set_cb(p_app->app_add_notify.p_app_notify_v, p_app->state.present_lightness);
        }
    
        return publish_lightness(p_app, 0);
    }

    In app_light_lightness.c, my publish_lightness:

    static uint32_t publish_lightness(app_light_lightness_setup_server_t * p_app, uint32_t remaining_time_ms)
    {
        light_lightness_status_params_t publication_data;
        light_lightness_server_t * p_light_lightness_srv;
    
        publication_data.present_lightness = p_app->state.present_lightness;
        publication_data.target_lightness  = p_app->state.target_lightness;
        publication_data.remaining_time_ms = remaining_time_ms;
        publication_data.present_motion = p_app->state.present_motion;
    
        /* Notify anyone interested that we are publishing lightness */
        if (p_app->app_add_notify.app_add_publish_cb != NULL)
        {
            p_app->app_add_notify.app_add_publish_cb(p_app->app_add_notify.p_app_publish_v, &publication_data);
        }
    
        p_light_lightness_srv = &p_app->light_lightness_setup_server.light_lightness_srv;
        return light_lightness_server_status_publish((const light_lightness_server_t * )p_light_lightness_srv,
                                                     (const light_lightness_status_params_t *)&publication_data);
    }

    In light_lightness_setup_server.c, my light_lightness_server_status_publish:

    uint32_t light_lightness_server_status_publish(const light_lightness_server_t * p_server,
                                                   const light_lightness_status_params_t * p_params)
    {
        if (p_server == NULL ||
            p_params == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        publish_bound_actual_states(p_server, p_params);
    
        return status_actual_send(p_server, NULL, p_params);
        return status_ll_send(p_server, NULL, p_params);
    }

    In light_lightness_setup_server.c, my status_ll_send:

    static uint32_t status_ll_send(const light_lightness_server_t * p_server,
                                       const access_message_rx_t * p_message,
                                       const light_lightness_status_params_t * p_params)
    {
        light_lightness_status_msg_pkt_t msg_pkt;
        msg_pkt.present_motion = p_params->present_motion;
        
        if (p_params->present_motion > LL_ONOFF_MAX)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    
        access_message_tx_t reply =
        {
            .opcode = ACCESS_OPCODE_SIG(LL_OPCODE_STATUS),
            .p_buffer = (const uint8_t *) &msg_pkt,
            .length = p_params->remaining_time_ms > 0 ? LIGHT_LIGHTNESS_STATUS_MAXLEN : LIGHT_LIGHTNESS_STATUS_MINLEN,
            .force_segmented = p_server->settings.force_segmented,
            .transmic_size = p_server->settings.transmic_size
        };
    
        if (p_message == NULL)
        {
            return access_model_publish(p_server->model_handle, &reply);
        }
        else
        {
            return access_model_reply(p_server->model_handle, p_message, &reply);
        }
    }

    To handle the opcode, I've also added handle_ll_get:

    static void handle_ll_get(access_model_handle_t model_handle,
                           const access_message_rx_t * p_rx_msg,
                           void * p_args)
    {
        light_lightness_server_t * p_server = (light_lightness_server_t *) p_args;
        light_lightness_setup_server_t * p_s_server = PARENT_BY_FIELD_GET(light_lightness_setup_server_t, light_lightness_srv, p_args);
        light_lightness_status_params_t out_data = {0};
    
        if (p_rx_msg->length == 0)
        {
            p_s_server->settings.p_callbacks->light_lightness_cbs.get_cb(p_s_server, &p_rx_msg->meta_data, &out_data);
            (void) status_ll_send(p_server, p_rx_msg, &out_data);
        }
    }

    Under the m_opcode_handlers:

    static const access_opcode_handler_t m_opcode_handlers[] =
    {
        {ACCESS_OPCODE_SIG(LIGHT_LIGHTNESS_OPCODE_GET), handle_get},
        {ACCESS_OPCODE_SIG(LL_OPCODE_GET), handle_ll_get},
    }

    For my client side, my main.c I've added:

    /* Light lightness client model interface: Process the received status message in this callback */
    static void app_light_lightness_client_status_cb(const light_lightness_client_t *p_self,
                                                     const access_message_rx_meta_t *p_meta,
                                                     const light_lightness_status_params_t *p_in)
    {
        if (p_in->remaining_time_ms > 0)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Lightness client: 0x%04x, Present Lightness: %d, Target Lightness: %d, Remaining Time: %d ms\n",
                  p_meta->src.value, p_in->present_lightness, p_in->target_lightness, p_in->remaining_time_ms);
        }
        else
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Lightness client: 0x%04x, Present lightness: %d, Present motion: %d\n",
                  p_meta->src.value, p_in->present_lightness, p_in->present_motion);
        }
    }

    In light_lightness_client.c, to handle the opcode:

    static void status_ll_handle(access_model_handle_t handle, const access_message_rx_t * p_rx_msg, void * p_args)
    {
        light_lightness_client_t * p_client = (light_lightness_client_t *) p_args;
        light_lightness_status_params_t in_data = {0};
    
        if (p_rx_msg->length == LL_STATUS_MINLEN || p_rx_msg->length == LL_STATUS_MAXLEN)
        {
            light_lightness_status_msg_pkt_t * p_msg_params_packed = (light_lightness_status_msg_pkt_t *) p_rx_msg->p_data;
    
            if (p_rx_msg->length == LL_STATUS_MINLEN)
            {
                in_data.present_motion = p_msg_params_packed->present_motion;
            }
            else
            {
                in_data.present_motion = p_msg_params_packed->present_motion;
            }
    
            p_client->settings.p_callbacks->lightness_status_cb(p_client, &p_rx_msg->meta_data, &in_data);
        }
    }
    .
    .
    static const access_opcode_handler_t m_opcode_handlers[] =
    {
        {ACCESS_OPCODE_SIG(LIGHT_LIGHTNESS_OPCODE_STATUS), status_handle},
        {ACCESS_OPCODE_SIG(LL_OPCODE_STATUS), status_ll_handle},
    }
    .
    .
    uint32_t ll_client_get(light_lightness_client_t * p_client)
    {
        if (p_client == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        if (access_reliable_model_is_free(p_client->model_handle))
        {
            message_create(p_client, LL_OPCODE_GET, NULL, 0, &p_client->access_message.message);
            reliable_context_create(p_client, LL_OPCODE_STATUS, &p_client->access_message);
    
            return access_model_reliable_publish(&p_client->access_message);
        }
        else
        {
            return NRF_ERROR_BUSY;
        }
    }

    Sorry if this is a lot of codes, but I hope you are able to study what I'm trying to do and help me with them. Thank you in advance.

Related