Copyright © https://mongoose-os.com

Mongoose OS Forum

frame

How to know when WiFi is ready?

I tried using ffi like this:
let wifiStatus = ffi('char *mgos_wifi_get_status_str()');
But mJS give me this error:  
MJS exec error: bad ffi signature: "char *mgos_wifi_get_status_str()": dlsym('mgos_wifi_get_status_str') failed

Thanks for any advice.

Comments

  • SergeySergey Dublin, Ireland
    That API exists in C but not yet exported in JS.
    Could you elaborate on your use case please?
  • I made a temperature sampling program to send data using MQTT from a timer call back every 2 seconds but it would fail at the start because wifi was not ready.  It's a minor issue that can just be ignored but I though it can be handled if there is a way to wait until wifi is ready.  I can do this with RPC.Local call to Sys.GetInfo then use the response's wifi status data.  I saw mgos_wifi_get_status_str in the documentation so I though it would be simpler to use.
  • SergeySergey Dublin, Ireland
    MQTT connection also has "connect" event which can be used, and it is also not yet exported to JS :)
    I think it makes sense to rely on MQTT connection. cause, say, you may be successfully connected to WiFi but your MQTT connection could be dead for whatever reason.

    let me think on the API... MQTT.on() maybe?

    MQTT.on('connect', function() { ... });
    MQTT.on('disconnect', function() { ... });


  • @Sergey , I am also thinking of a centralized event emit/subscribe mechanism for mJS. 

    For example, in C, we do:
    ```
    // first, put all event data in a json string, and then:
    emit(SOME_EVENT, *event_data_json_string);
    ```

    Then in mJS, we can subscribe by:
    ```
    subscribe(SOME_EVENT, function(event_data_json_string) {
      // parse the json string into a javascript object;
      // then, do something with the object data;
    });
    ```

    This way we can avoid ffi define, and may be easier to maintain.

  • JLehmanJLehman Connecticut
    I may be in a similar state but in C.  I do a mgos_mqtt_pub and get a return status of 1 but I know the device is not connected and I do not see it connect.  How do I know the connection state and/or how do I get it to connect?  

    Is mgos_mqtt_pub supposed to make it connect?

  • SergeySergey Dublin, Ireland
    edited May 10
    @JLehman mOS maintains only one MQTT connection with a server, which is described by the "mqtt" configuration setting. If mqtt.enable=true, then mOS makes an infinite reconnection loop to the "mqtt.server". 

    In C, there is a mgos_mqtt_global_subscribe() function which allows to specify a callback function that receives necessary events for this single MQTT connection:

    https://github.com/cesanta/mongoose-os/blob/2e61b5210a18401332b7a55fe1d3cb6065c73b8c/fw/src/mgos_mqtt.h#L24-L31

    There is a simple wrapper for this function, mgos_mqtt_sub(), which actually gets ffi-ed to JS. That simple wrapper is called only on PUBLISH event:
    https://github.com/cesanta/mongoose-os/blob/2e61b5210a18401332b7a55fe1d3cb6065c73b8c/fw/src/mgos_mqtt.c#L314

    Thus if you're working in C, you're all set - just use mgos_mqtt_global_subscribe().

    For the rest of us, JS dudes, something else should be done.
    Well, one possibility is to just FFI mgos_mqtt_global_subscribe(). 
  • dirkjdirkj Germany

    The initial question was about knowing, when WiFi is ready (not mqtt).

    I tried to use the mgos_wifi_add_on_change_cb in JS using ffi, but cannot get the right signature for that. Could someone please help?
    I tried this:

    let addWiFiReadyCallback = ffi('void mgos_wifi_add_on_change_cb(void (*)(int, void *), void *)');
    

    But I get the following error message:

    MJS error: bad ffi signature: "void mgos_wifi_add_on_change_cb(void (*)(int, void *), void *)": dlsym('mgos_wifi_add_on_change_cb') failed
    

    Any help or pointer to some reference implementation is appreciated.

  • SergeySergey Dublin, Ireland
    edited May 17

    Try this one:

    let x = ffi('void mgos_wifi_add_on_change_cb(void (*)(int, userdata), userdata)');
    x(function(ev) {
      print('IN WIFI CB', ev);
    }, null);
    
  • asr0asr0 Germany
    edited May 18

    Hi, I reimplemented the wifi.ready function that was there before that here is it added to the mjs base example:

    #include <stdio.h>
    #include "common/platform.h"
    #include "common/cs_file.h"
    #include "fw/src/mgos_app.h"
    #include "fw/src/mgos_gpio.h"
    #include "fw/src/mgos_sys_config.h"
    #include "fw/src/mgos_timers.h"
    #include "fw/src/mgos_hal.h"
    #include "fw/src/mgos_dlsym.h"
    #include "fw/src/mgos_wifi.h"
    #include "mjs.h"
    
    #if CS_PLATFORM == CS_P_ESP8266
    #define LED_GPIO 2 /* On ESP-12E there is a blue LED connected to GPIO2  */
    #elif CS_PLATFORM == CS_P_ESP32
    #define LED_GPIO 21 /* No LED on DevKitC, use random GPIO close to GND pin */
    #elif CS_PLATFORM == CS_P_CC3200
    #define LED_GPIO 64 /* The red LED on LAUNCHXL */
    #elif(CS_PLATFORM == CS_P_STM32) && defined(BSP_NUCLEO_F746ZG)
    /* Nucleo-144 F746 */
    #define LED_GPIO STM32_PIN_PB7 /* Blue LED */
    #elif(CS_PLATFORM == CS_P_STM32) && defined(BSP_DISCO_F746G)
    

    /* Discovery-0 F746 /
    #define LED_GPIO STM32_PIN_PI1 /
    Green LED /
    #else
    #error Unknown platform
    #endif

    int get_led_gpio_pin(void) {
    return LED_GPIO;
    }
    //User supplied callback to be called when wifi is connected.
    typedef void (
    on_wifi_ready_t)(void param);
    on_wifi_ready_t on_wifi_ready;
    //wrapper around user provided callback; to be called in mgos_wifi_ready_cb
    void mgos_wifi_changed(enum mgos_wifi_status event, void *arg){
    if(event == MGOS_WIFI_IP_ACQUIRED){ on_wifi_ready(arg); }
    }
    //Wrapper to enable a Wifi.ready function in mjs
    void mgos_wifi_ready_cb(on_wifi_ready_t cb, void *arg){
    on_wifi_ready = cb;
    mgos_wifi_add_on_change_cb(mgos_wifi_changed, arg);
    }

    enum mgos_app_init_result mgos_app_init(void) {
    /
    Initialize JavaScript engine */
    int mem1, mem2, mem3;
    mem1 = mgos_get_free_heap_size();
    struct mjs *mjs = mjs_create();
    mem2 = mgos_get_free_heap_size();
    mjs_set_ffi_resolver(mjs, mgos_dlsym);
    mjs_err_t err = mjs_exec_file(mjs, "init.js", NULL);
    if (err != MJS_OK) {
    LOG(LL_ERROR, ("MJS exec error: %s\n", mjs_strerror(mjs, err)));
    }
    mem3 = mgos_get_free_heap_size();
    LOG(LL_INFO, ("mJS memory stat: before init: %d "
    "after init: %d after init.js: %d",
    mem1, mem2, mem3));
    return MGOS_APP_INIT_SUCCESS;
    }

    Here is how it gets used in init.js:

    Wifi.ready(function(t){
    // Call every second
    do something when wifi is ready

    }, null);

    and here is the api_wifi.js
    that you should put in the ./fs folder

    / System API. Source C API is defined at:
    // main.c main.h

    let Wifi = {
    ready: ffi('void mgos_wifi_ready_cb(void (*)(userdata),userdata)')
    };

    and then include in init.js with load('api_wifi.js');
    this needs to be done so ffi symbols can be know at compiletime. (so adding ffi calls on the fly during playing around will not work)
    I would submit a pull request for that but the function currently has the limitation that there can be only one wifi.ready, because the callback is saved in a global variable. For me this drawback is okay, but I can change that if its needed. Offtopic: it would be nice to have support for enums in mjs so the ffi could be made directly.

  • dirkjdirkj Germany

    Thanks @Sergey and @asr0 --- got it :-)

  • SergeySergey Dublin, Ireland

    Thanks!

    I don't think you need a C wrapper. Enums are ints, really, so in FFI spec you can say int, and use C API directly, just like I posted earlier.

  • asr0asr0 Germany

    If I remember correctly I tried this, but it would still say that the signature is wrong. Maybe I made some mistake. So I came up with this solution and it worked for me :smiley: probably needlessly complex. :smile:

  • @Sergey : MQTT connection also has "connect" event which can be used, and it is also not yet exported to JS :)

    Any chance you're still looking at implementing this API? My use case is similar to the aforementioned. I only want to activate init.js once the device has successfully connected to MQTT client and I'm ready to publish. Thanks!

  • SergeySergey Dublin, Ireland

    On my list :)
    Team is busy with the factoring out libraries and https://mongoose-os.com/docs - having a good docs is a must IMO.

    Might happen next week, but cannot promise 100%. @jocode could you elaborate on the project you're working on please?

  • Understood. Yes, we're truly missing the docs. Thanks for quick reply and the efforts on mos and moving things in the right direction.

    We're looking at implementing a device on ESP8266 that can be woken up when activated by a user (e.g.; a button press) and publish its status to AWS. If its status changes, it will publish again. After a short period of inactivity, the device will put itself to deep sleep. Only to be awaken with user interaction and cycle repeats. Similar to Amazon Dash button.

    Right now, we face two issues:
    1) the time it takes to boot up to successful MQTT connection - at least 10 secs or more
    You had addressed this boot up time issue in another post and suggested ESP32 could be faster. Do you know how much faster? Also, I couldn't find any documentation on deep sleep with ESP32 so that might be an issue.

    2) how to tell when MQTT connection is successful without relying on Timer.set(1000, true, function() { ... }, null) and waiting 10 secs before publishing initial status (that woke up device).

    We're working with mJS (thank you!) and not brave enough to jump into C. Any suggestions/hints are much appreciated.

Sign In or Register to comment.