Change settings inside the plugin

Answered

Comments

18 comments

  • Avatar
    Andrey Terentyev

    Hello Hendrick,

    > Is there a way to set a different value to some parameter in settings in the plugin code?

    Since your plugin has got settings values from the GUI client it can do what ever is necessary: save to an internal data structure, save to a file, send to an external system over the network etc. I don't really understand what do you mean by that?
    Could you please elaborate a bit your scenario?

    Here is a thread might be worth reading.
    https://support.networkoptix.com/hc/en-us/community/posts/360039368793-I-have-a-question-about-ROI-metadataSDK-

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    Hello Andrey,
    My scenario is following: I want to keep settings in the plugin and in the cloud simultaneously, and be able to modify settings automatically in the plugin when they are modified in the cloud. I.e. not just only modify variables in code but modify actual settings so user will see in GUI that some setting was changed.

    Thanks for the link, I will examine it.

    0
    Comment actions Permalink
  • Avatar
    Andrey Terentyev

     Hello,

    Thank you for explaination.

    What you need is to implement getPluginSideSettings.

    In current v4.1 release there is a bug, because of which the getPluginSideSettings is not called when plugin settings dialog is being opened. Although it's fixed, the fix will be available with the upcoming hotfix only.

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    Hello Andrey,
    Do I understand correctly that getPluginSideSettings method will be called every time I open settings? (after the bugfix)
    If so I see it in a such way:
    1. I  receive settings in the plugin from the cloud
    2. I store them in a plugin (or in a sqlite db) until the user opens settings or Nx server or plugin is restarted
    3. if the user opens settings getPluginSideSettings is called and I return changed Result<const ISettingsResponse*>* , so settings are applied to the networkoptix plugin and are visible in GUI
    4. if plugin or server is restarted then settingsReceived is called and I return changed Result<const ISettingsResponse*> so settings are applied to the networkoptix plugin and are visible in GUI


    Do I get it right or I'm missing something?

    0
    Comment actions Permalink
  • Avatar
    Andrey Terentyev

    Hello,

    There are three classes Plugin, Engine, DeviceAgent comprising an analytics plugin.

    1. I receive settings in the plugin from the cloud
    Decide which part of the code are you going to go this: Engine, DeviceAgent?

    2. I store them in a plugin (or in a sqlite db) until the user opens settings or Nx server or plugin is restarted
    "plugin is restarted" should be precised.
    When plugin is being enabled on a device, an Engine class instance already exists and a DeviceAgent class instance only is created.
    When server is being restarted the instances of all classes (Plugin, Engine, DevieAgent) are recreated.

    Both Engine and DeviceAgent classes have the getPluginSideSettings method.
    You should decide when and where you want to perform step 1 operation.

    You don't need additional sqlite db, because you have your cloud for long time storing.

    3.
    settings are applied to the networkoptix plugin and are visible in GUI.
    I don't really get it. What is "networkoptix plugin" ?
    getPluginSideSettings IS a part of a plugin code. It is invoked for getting settings values from the plugin. Those can be read either from internal structure updated at "step 1" or read right away from the cloud.
    Server merges updated values with the values from its DB and sends to the GUI.

    4. When server is being restarted the instances of all classes (Plugin, Engine, DevieAgent) are recreated.
    When Engine class instance is being created the setSettings method is called which invokes doSetSettings (i_engine.h).

    public: Result<const ISettingsResponse*> setSettings(const IStringMap* settings)
    {
    Result<const ISettingsResponse*> result;
    doSetSettings(&result, settings);
    return result;
    }

    The doSetSettings is the place where you should place your code for processing the settings.
    the settingReceived is supposed to be called AFTER the settings are saved in the internal structure in your code.

    void Engine::doSetSettings(
    Result<const ISettingsResponse*>* outResult, const IStringMap* settings)
    {
    if (!logUtils.convertAndOutputStringMap(&m_settings, settings, "Received settings"))
    *outResult = error(ErrorCode::invalidParams, "Unable to convert the input string map");
    else
    *outResult = settingsReceived();
    }

    When plugin is being enabled on a device DeviceAgent class instance in created.
    The DeviceAgent class has the setSettings, doSetSettings and settingReceived, as well, called in the same manner as in Engine class.
    All of them are for supplying a plugin with the settings values not for getting settings values from the plugin.

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    >Decide which part of the code are you going to go this: Engine, DeviceAgent?
    I need to store settings per camera, so I need to do it in the DeviceAgent

    >getPluginSideSettings IS a part of a plugin code. It is invoked for getting settings values from the plugin. Those can be read either from internal structure updated at "step 1" or read right away from the cloud.

    I understand that it's a part of a plugin code. I assumed that I can't call this function manually and I need to wait for a moment when user opens settings or when server is restarted.  That's why I was thinking about db for permanent storage. If I can call this function manually at any moment (i.e. when settings are changed in the cloud) then all this is unnecessary. Can I call this function at any moment?

    >The doSetSettings is the place where you should place your code for processing the settings.
    Can I call this function manually?

    0
    Comment actions Permalink
  • Avatar
    Andrey Terentyev

    Hi,

    > Can I call this function at any moment?

    getPluginSideSettings is declared as protected.

    protected: virtual void getPluginSideSettings(
    Result<const ISettingsResponse*>* outResult) const = 0;

    That means you it can be called from inside any descendant. You can call it from any place inside the DevieAgent class.
    If you want it be called outside the class, you could create a public method, which would invoke getPluginSideSettings.

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    Hello Andrey,
    Thank you for your answers, I appreciate it.

    Now I understand that if I want to receive settings from the cloud I need to receive settings somewhere (not in every DeviceAgent but in a single listener) and then apply settings to DeviceAgents.


    I would like to summarize it all and be sure that I get it right.

    getPluginSideSettings is called when user opens Plugin Settings. I can call it manually. 
    There is also doSetSettings in src/nx/sdk/analytics/i_device_agent.h and in src/nx/sdk/analytics/i_engine.hYou recommended to apply settings inside of doSetSettings.
    Is there any difference between calling manually getPluginSideSettings and calling manually doSetSettings?

    I'm thinking about keep a map of DeviceAgents and listener inside of the Engine. When listener get new settings I need to select a needed DeviceAgent, get it's settings via DeviceAgent::getPluginSideSettings, change settings and then apply settings by calling DeviceAgent::doSetSettings with changed settings. Is it a good idea?

    0
    Comment actions Permalink
  • Avatar
    Andrey Terentyev

    Hi,

    doSetSettings and getPluginSideSettings are called under different conditions, on different events.

    doSetSettings  is for passing settings FROM the Server TO a plugin.

    getPluginSideSettings is for getting settings FROM the plugin (possibly from an external application) TO the Server.

    > When listener get new settings
    From where? What is the source?

    > I need to select a needed DeviceAgent, get it's settings via DeviceAgent::getPluginSideSettings
    If settings are the same for all DeviceAgents, you don't. Your listener just saves the settings in the internal structure. DeviceAgent::getPluginSideSettings is called by the Server and reads the settings from internal structure. Passes to the Server. The Server merges with values read from DB and passes to the GUI.

    In GUI user clicks "Apply" or "OK" button, settings values are passed to the server. Server saves to DB and calls doSetSettings.

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    >From where? What is the source?
    Our cloud is the source (not a networkoptix cloud). Now I don't know exactly which method I will use. Probably I will constantly pull some URL or connect to a websocket. The user should be able to turn on and off types of analytics for a specific camera in our web app (i.e. cloud) and in the Nx plugin. So, when user turn on or turn off something for a specific camera in the cloud I need to update it's settings in the networkoptix plugin.

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    >In GUI user clicks "Apply" or "OK" button, settings values are passed to the server. Server saves to DB and calls doSetSettings.

    Ok, I need to do the same process but from the code, when I receive settings from listener.

    0
    Comment actions Permalink
  • Avatar
    Maxim Podstrechny

    Hi Hendrik,

    My name is Maxim, Andrey is on a vacation now and for some time I will be answering questions on the forum instead of him.

    Just wanted to ask if you still have any questions or difficulties considering the subject of this thread.

    Thank you.

     

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    Hello Maxim,

    I still have a question

    I want to share analytics settings between our web app and the networkoptix plugin. For example I have a setting 'detect people' for a specific camera and I want to be able to change it in the plugin and in the web app. If user changed settings in the web app and then opened the settings window in the networkoptix server, user must see already changed settings.

    Is it possible?
    If so, how can I do it? I need to change settings for a particular camera, so I want to change a DeviceAgent settings.

    0
    Comment actions Permalink
  • Avatar
    Maxim Podstrechny

    Hello Hendrik,

    There was a lot of discussion about getPluginSideSettings in this thread. Why not using it?

    So, you can keep your settings somewhere in your Cloud and pull it when you need it (e.g., when the user opens the plugin settings window).

     

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    Hello Maxim,

    I'm sorry for such long delay.

    The problem with getPluginSideSettings is don't understand how to use it. 

    I need to pass Result<const ISettingsResponse*>* outResult to it and I don't know where to get it.

    I tried following code

     

    void DeviceAgent::applySettings(int test) {
    m_testSetting = test;
    Result<const ISettingsResponse*>* result;

    getPluginSideSettings(result);
    }

    void DeviceAgent::getPluginSideSettings(
    Result<const ISettingsResponse*>* outResult) const
    {
    const auto response = new SettingsResponse();
    response->setValue("pluginSideTestSpinBox", std::to_string(m_testSetting));

    *outResult = response;

    }


    But it doesn't work. I call applySettings function, then go to the plugin settings window and see that pluginSideTestSpinBox setting has not changed.

    How can I fix it?

    Thanks for answer. 

    0
    Comment actions Permalink
  • Avatar
    Hendrik Baekeland

    Sorry, actually now I'm  surprised that I didn't receive segfault.

    I changed code to the following:

    void DeviceAgent::applySettings(int test) {
    m_testSetting = test;
    Result<const ISettingsResponse*>* result = new Result<const ISettingsResponse*>();

    getPluginSideSettings(result);
    }

    void DeviceAgent::getPluginSideSettings(
    Result<const ISettingsResponse*>* outResult) const
    {
    const auto response = new SettingsResponse();
    response->setValue("pluginSideTestSpinBox", std::to_string(m_testSetting));

    *outResult = response;

    }

    And now it works.

    I'm afraid of memory leaking because of constant creation of Result<const ISettingsResponse*>* with new but I think I can somehow avoid it.

    0
    Comment actions Permalink
  • Avatar
    Maxim Podstrechny

    Hi Hendrik,

    Instead of creating a new structure on the heap every time you're using operator new, why don't you just use a variable for storing the result? You can do something like this:

    Result<const ISettingsResponse*> result;
    getPluginSideSettings(&result);

    And here's the code of the getPluginSideSettings function from Stub Analytics Plugin: that's a sample plugin and its source code is provided inside our Metadata SDK package. You can find it in the following file: samples/stub_analytics_plugin/src/nx/vms_server_plugins/analytics/stub/engine.cpp. I think, you might find it useful.


    void Engine::getPluginSideSettings(Result<const ISettingsResponse*>* outResult) const
    {
        auto settingsResponse = new SettingsResponse();
        settingsResponse->setValue(kEnginePluginSideSetting, kEnginePluginSideSettingValue);

        *outResult = settingsResponse;
    }
    0
    Comment actions Permalink
  • Avatar
    Linh Nguyen

    Hi Hendrick,

    Did you solve your problem? I have the same task. I want to send the setting from outside (Video Analytics Server).

    If you solved it. Could you help me how to do that? Thank you.

    0
    Comment actions Permalink

Please sign in to leave a comment.