cancel
Showing results for 
Search instead for 
Did you mean: 
SOLVED

Read and Write attributes of item

Read and Write attributes of item

HmiGuide
Community Moderator
Community Moderator

@webiq-eg Can you please provide an JS example how to read and the attributes (digits, min, max, label,...) of an existing item. I tried to do it, with the help of the documentation (shmi.core.Item & shmi.core.ItemManager), but I failed.

6 REPLIES 6

webiq-eg
Long-established Member

Hello HmiGuide,
the attributes are obtained via the callback function when I subscribe to an item:

(function() {
    var actions = shmi.pkg("visuals.session.userActions"); //get reference to userActions object

    /**
     * UI-Action 'get-item-attributes' implementation
     *
     * @params {any[]} parameters  configured ui-action parameters
     * 
     */
    actions["get-item-attributes"] = function(parameters) {
        //Place your code here
        const item = parameters[0];
        if (item) {

            const im = shmi.visuals.session.ItemManager,
                tok = im.subscribe([item], (name, value, type) => {
                    console.log(`New value for item '${name}': ${value}`);
                }, (name, properties) => {
                    if (properties.initialized) {
                        shmi.notify(JSON.stringify(properties, null, 4));
                        tok.unlisten();         //... when subsription is no longer needed, unsubscribe:
                        clearTimeout(timeout);
                    }
                    console.log(`Properties changed for item '${name}': ${JSON.stringify(properties, null, 4)}`);
                }),
                timeout = setTimeout(() => {
                    
                    tok.unlisten();
                    shmi.notify(`TIMEOUT ERROR: Item ${item} does not respond!`)
                }, 1000);
        }
    
    };
}());

I have attached a small WebIQ HMI project to try out.
Hope that helps?
Many greetings
webiq eg

HmiGuide
Community Moderator
Community Moderator

Thanks for the example. It's working, but only when the item is NOT subscribed (=used on the screen). 
I checked to documenation again, and implemented the solution below.

// get properties of item
const im = shmi.visuals.session.ItemManager
let item = im.getItem("SInt")
if (item) {
    let prop = item.getProperties()
    console.log(JSON.stringify(prop, null, 2))
} else {
    console.log("getProperties failed")
}

One question is not answered: Is it possible to write/change the attributes at runtime (with shmi functions, not via API functions).

webiq-sk
Frequent Contributor

@HmiGuide WebIQ has a subscription-based model, so your implementation will not work every time.

Here is a working version:

/**
 * Custom UI-Action 'readItemProps'.
 *
 * Description:
 * [Add description here]
 */
(function() {
    const actions = shmi.pkg("visuals.session.userActions"); //get reference to userActions object

    /**
     * Reads properties of an item.
     *
     * @param {string} itemAlias Alias of the item to read the properties of.
     * @param {?AbortSignal} signal Abort signal to cancel the operation.
     * @returns {Promise<object>}
     */
    function readItemProperties(itemAlias, signal = null) {
        return new Promise((resolve, reject) => {
            const { ItemManager } = shmi.visuals.session,
                itemAlreadyExists = (ItemManager.getItem(itemAlias)?.type ?? null) !== null;
            let token = null,
                done = false,
                callbackReady = itemAlreadyExists,
                /** @type {() => void} */
                onAbort;

            /**
             * @param {string} text
             */
            function onError(text) {
                if (done) {
                    // We are already done.
                    return;
                }

                token?.unlisten();
                token = null;
                done = true;
                signal?.removeEventListener("abort", onAbort);

                reject(new Error(text));
            }

            /**
             * @param {object} result 
             */
            function onDone(result) {
                if (done) {
                    // We are already done.
                    return;
                }

                token?.unlisten();
                token = null;
                done = true;
                signal?.removeEventListener("abort", onAbort);

                resolve(result);
            }

            onAbort = onError.bind(null, "aborted");
            signal?.addEventListener("abort", onAbort);

            token = ItemManager.subscribe([itemAlias], null, (name, properties) => {
                if (done) {
                    // We are already done.
                    return;
                }

                if (properties.type === null && callbackReady) {
                    // Subscription has been terminated by WebIQ Server and we
                    // haven't gotten our properties yet. Assume the item has
                    // failed.
                    onError(`Item ${itemAlias} not found.`);
                    return;
                } else if (!properties.initialized) {
                    // Properties are not initialized yet.
                    return;
                } else if (properties.type === -1) {
                    onError(`Unable to read properties of item ${itemAlias}.`);
                    return;
                }

                onDone(properties);
            });

            // Allow properties callback to fail when type is null.
            callbackReady = true;

            // Check if the properties callback has already been called. This
            // can happen if the item was already subscribed before. We now
            // need to cleanup the token because it wasn't available to the
            // callback.
            if (done) {
                token?.unlisten();
                token = null;
            }
        });
    }

    /**
     * UI-Action 'readItemProps' implementation
     *
     * @params {any[]} parameters  configured ui-action parameters
     * ---- Initial parameters, needs to be updated manually when changed ----
     * @param {string} parameters[0]  Item
     *
     */
    actions["readItemProps"] = async function(parameters) {
        //Place your code here
        const itemName = parameters[0];
        const props = await readItemProperties(itemName);
        console.log(props);

    };
}());

HmiGuide
Community Moderator
Community Moderator

Thanks for your adapted script. I do prefere the solution without subscription. It's much easier than with subscription.
I'm still wait for the statement (and example) if it is possible to adapt the attributes. (See message above)

webiq-sk
Frequent Contributor

Actually your solution only works when the item is currently subscribed or has already been subscribed before. If you're getting data with the item not being subscribed anymore the data returned will be outdated.

There is no other way than using the asynchronous method simply because the underlying call has to be asynchronous because the data will be retrieved asynchronously from the server via the WebSocket connection.

There simply is no synchronous way of getting the current data of any item.

webiq-sk
Frequent Contributor

Modification of attributes from the HMI is not possible at runtime.

Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist