Joni Turunen
Joni Turunen

Reputation: 137

Creating a Custom Data Adapter: Importing data adapter

Following the tutorial for creating a custom data adapter: https://forge.autodesk.com/en/docs/dataviz/v1/developers_guide/advanced_topics/custom_data_adapter/

Getting error in chrome console: enter image description here

Created file Hyperion.Data.BimapiDataAdapter in the folder forge-dataviz-iot-reference-app-main\node_modules\forge-dataviz-iot-data-modules\client\data based on the Hyperion.Data.Adapter file in the same folder. Then edited on line 371 and changed RestApiDataAdapter to BimapiDataAdapter.

enter image description here

Then trying to import this in BaseApp.jsx on line 34 in the folder forge-dataviz-iot-reference-app-main\node_modules\forge-dataviz-iot-react-components\client\components.

enter image description here

Upvotes: 0

Views: 194

Answers (1)

Eason Kang
Eason Kang

Reputation: 7070

Your Hyperion.Data.BimapiDataAdapter.js is not placed aside forge-dataviz-iot-react-components/BaseApp.jsx, so the package-tool Webpack cannot it by ./Hyperion.Data.BimapiDataAdapter in BaseApp.jsx.

Here is my approach to exposing Hyperion.Data.BimapiDataAdapter.js.

  1. Create Hyperion.Data.BimapiDataAdapter.js under forge-dataviz-iot-reference-app-main\node_modules\forge-dataviz-iot-data-modules\client\data. Here is how it looks like (just copied and pasted the contents of RestApiDataAdapter for the quick demo)
import { DataAdapter } from './Hyperion.Data';

/**
 * Data adapter class dealing with sample data.
 * @memberof Autodesk.DataVisualization.Data
 * @alias Autodesk.DataVisualization.Data.BimapiDataAdapter
 * @augments DataAdapter
 */
 export class BimapiDataAdapter extends DataAdapter {
    /**
     * Constructs an instance of BimapiDataAdapter.
     */
    constructor(provider = "synthetic", baseName = "") {
        super("BimapiDataAdapter", baseName);
        /* eslint-disable no-undef */
        this._provider = provider;
    }

    /**
     * Loads all DeviceModel objects from the sample REST API.
     *
     * @returns {Promise<DeviceModel[]>} A promise that resolves to a single
     * &nbsp;dimensional array containing a list of loaded DeviceModel objects. If no
     * &nbsp;DeviceModel is available, the promise resolves to an empty array.
     * @memberof Autodesk.DataVisualization.Data
     * @alias Autodesk.DataVisualization.Data.BimapiDataAdapter#loadDeviceModels
     */
    async loadDeviceModels() {
        const adapterId = this.id;
        return fetch(this._getResourceUrl("api/device-models"))
            .then((response) => response.json())
            .then((rawDeviceModels) => {
                /** @type {DeviceModel[]} */
                const normalizedDeviceModels = [];

                rawDeviceModels.forEach((rdm) => {
                    // Create a normalized device model representation.
                    const ndm = new DeviceModel(rdm.deviceModelId, adapterId);
                    ndm.name = rdm.deviceModelName;
                    ndm.description = rdm.deviceModelDesc;

                    // Generate device property representation.
                    rdm.deviceProperties.forEach((rdp) => {
                        const propId = rdp.propertyId;
                        const propName = rdp.propertyName;

                        const ndp = ndm.addProperty(propId, propName);
                        ndp.description = rdp.propertyDesc;
                        ndp.dataType = rdp.propertyType;
                        ndp.dataUnit = rdp.propertyUnit;
                        ndp.rangeMin = rdp.rangeMin ? rdp.rangeMin : undefined;
                        ndp.rangeMax = rdp.rangeMax ? rdp.rangeMax : undefined;
                    });

                    normalizedDeviceModels.push(ndm);
                });

                // Fetch actual devices for each of the device models.
                return this.fetchDevicesForModels(normalizedDeviceModels);
            });
    }

    /**
     * Fetches actual device IDs and populate DeviceModel objects with them.
     *
     * @param {DeviceModel[]} deviceModels The DeviceModel objects for which
     * &nbsp;actual device IDs are to be populated.
     *
     * @returns {Promise<DeviceModel[]>} A promise that resolves to the
     * &nbsp;DeviceModel objects populated with actual device IDs.
     * @memberof Autodesk.DataVisualization.Data
     * @alias Autodesk.DataVisualization.Data.BimapiDataAdapter#fetchDevicesForModels
     */
    async fetchDevicesForModels(deviceModels) {
        const promises = deviceModels.map((deviceModel) => {
            const model = deviceModel.id;
            return fetch(this._getResourceUrl("api/devices", { model: model }))
                .then((response) => response.json())
                .then((jsonData) => jsonData.deviceInfo);
        });

        return Promise.all(promises).then((deviceInfosList) => {
            // Assign devices to each device model.
            deviceModels.forEach((deviceModel, index) => {
                // Turn data provider specific device data format into
                // the unified data format stored in Device object.
                //
                const deviceInfos = deviceInfosList[index];
                deviceInfos.forEach((deviceInfo) => {
                    const device = deviceModel.addDevice(deviceInfo.id);
                    device.name = deviceInfo.name;

                    const p = deviceInfo.position;
                    device.position = new THREE.Vector3(
                        parseFloat(p.x),
                        parseFloat(p.y),
                        parseFloat(p.z)
                    );

                    device.lastActivityTime = deviceInfo.lastActivityTime;
                    device.deviceModel = deviceModel;
                    device.sensorTypes = deviceModel.propertyIds;
                });
            });

            return deviceModels;
        });
    }

    /**
     * Fetches the property data based on the given device ID.
     *
     * @param {QueryParam} query Parameters of this query.
     *
     * @returns {Promise<DeviceData>} A promise that resolves to an aggregated
     * &nbsp;property data for the queried device.
     * @memberof Autodesk.DataVisualization.Data
     * @alias Autodesk.DataVisualization.Data.BimapiDataAdapter#fetchDeviceData
     */
    async fetchDeviceData(query) {
        const pids = query.propertyIds;
        const promises = pids.map((pid) => this._fetchPropertyData(query, pid));

        return Promise.all(promises).then((deviceDataList) => {
            const deviceData = new DeviceData(query.deviceId);
            deviceDataList.forEach((devData) => deviceData.mergeFrom(devData));
            return deviceData;
        });
    }

    /**
     * Fetches data for a single property based on the given device ID.
     *
     * @param {QueryParam} query Parameters of this query.
     * @param {string} propertyId The ID of the property.
     *
     * @returns {Promise<DeviceData>} A promise that resolves to an aggregated
     * &nbsp;property data for the queried device.
     */
    async _fetchPropertyData(query, propertyId) {
        const url = this._getResourceUrl("api/aggregates", {
            device: query.deviceId,
            property: propertyId,
            startTime: query.dateTimeSpan.startSecond,
            endTime: query.dateTimeSpan.endSecond,
            resolution: query.dateTimeSpan.resolution,
        });

        return fetch(url)
            .then((response) => response.json())
            .then((rawAggregates) => {
                // Convert 'rawAggregates' which is in the following format, into 'AggregatedValues'
                //
                // rawAggregates = {
                //     timestamps: number[],
                //     count: number[],
                //     min: number[],
                //     max: number[],
                //     avg: number[],
                //     sum: number[],
                //     stdDev: number[]
                // }
                //
                const aggrValues = new AggregatedValues(query.dateTimeSpan);
                aggrValues.tsValues = rawAggregates.timestamps;
                aggrValues.countValues = rawAggregates.count;
                aggrValues.maxValues = rawAggregates.max;
                aggrValues.minValues = rawAggregates.min;
                aggrValues.avgValues = rawAggregates.avg;
                aggrValues.sumValues = rawAggregates.sum;
                aggrValues.stdDevValues = rawAggregates.stdDev;
                aggrValues.setDataRange("avgValues", getPaddedRange(aggrValues.avgValues));

                const deviceData = new DeviceData(query.deviceId);
                const propertyData = deviceData.getPropertyData(propertyId);
                propertyData.setAggregatedValues(aggrValues);

                return deviceData;
            })
            .catch((err) => {
                console.error(err);
            });
    }

    /**
     * Gets the resource URL for a given endpoint with query parameters
     *
     * @param {string} endpoint The endpoint for the URL to generate
     * @param {Object.<string, string>} parameters Key-value pairs of query parameters
     *
     * @returns {string} The string that represents the complete resource URL
     * @private
     */
    _getResourceUrl(endpoint, parameters) {
        parameters = parameters || {};

        parameters["provider"] = this._provider;
        parameters["project"] = "unused";
        const ps = Object.entries(parameters).map(([k, v]) => `${k}=${v}`);
        return `${this._baseName}/${endpoint}?${ps.join("&")}`;
    }
}
  1. Expose the class BimapiDataAdapter from ``forge-dataviz-iot-reference-app-main\node_modules\forge-dataviz-iot-data-modules\client.js`
export * from "./client/data/Hyperion.Data";
export * from "./client/data/Hyperion.Data.BimapiDataAdapter"; //!<<< add this line
  1. Import BimapiDataAdapter in forge-dataviz-iot-reference-app-main\node_modules\forge-dataviz-iot-react-components\client\components\BaseApp.jsx from where import { ... } from "forge-dataviz-iot-data-modules/client" is
import {
    Session,
    AzureDataAdapter,
    RestApiDataAdapter,
    DataView,
    DateTimeSpan,
    EventType,
    DeviceProperty,
    DeviceModel,
    BimapiDataAdapter //!<<< here it is
} from "forge-dataviz-iot-data-modules/client";

Afterward, re-execute ENV=local npm run dev in your terminal console.

If you have further questions on how Webpack resolves packages, I would advise you to check these out:

Upvotes: 1

Related Questions