@iotize/tap
Version:
IoTize Device client for Javascript
297 lines • 20.6 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { combineLatest, Observable, Subject } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { createMonitoringTicker, MonitoringController, } from '../monitor/monitor-engine';
import { TapDataError } from '../tap-data-error';
import { ModbusAccessVariable } from '../target-variable/modbus/modbus-access-variable';
import { createTapBundleFromConfig, } from '../target-variable/tap-bundle/tap-bundle';
import { createTapVariableFromConfig, } from '../target-variable/tap-variable/tap-variable';
import { TargetMemoryVariable } from '../target-variable/target-memory/target-memory-variable';
import { createDataManagerConfigFromTapDataConfig } from './create-data-manager-config-from-tap-data-config';
import { createTapBundlesFromConfig, readDataManagerTapConfigFromTap, } from './create-data-manager-from-tap-config';
const TAG = 'DataManager';
/**
* Typed data manager is usually build from Tap configuration
*
* It allow you to have compile time check for bundle/variable types.
* However, you cannot add/remove/edit variables (as it would change types)
* Use `DataManager` if you want this features
*/
export class TypedDataManager {
constructor(tap, bundles,
// variables: Record<VariableKey, EditableDataStream<VariableByType[VariableKey]>>
monitoring = new MonitoringController()) {
// const variablesCache: Record<string, EditableDataStream<VariableByType[VariableKey], unknown>> = {};
// for (const bundleKey in this.bundles) {
// const bundle = this.bundles[bundleKey];
// for (const variableKey in bundle.variables) {
// const variable = bundle.variables[variableKey];
// variablesCache[variable.config.name] = variable;
// }
// }
// this.variablesCache = variablesCache as Record<VariableKey, EditableDataStream<VariableByType[VariableKey], unknown>>;
// this.setupStreams();
this.tap = tap;
this.bundles = bundles;
this.monitoring = monitoring;
// switchableStream!: SwitchableStream;
// dataStream: Observable<Record<string, any>>;
// tlvConverter: TlvBundleConverter<Record<string, Uint8Array>>;
// sourceControllers: Record<string, DataSourceController> = {};
// protected variablesCache: Record<VariableKey, EditableDataStream<VariableByType[VariableKey], unknown>>;
// private tickers: Record<string, {
// controller: MonitoringControllerSubject,
// ticker: Observable<MonitoringTickerState>
// }> = {};
// private ticker = createMonitoringTicker(this.monitoring);
this._events = new Subject();
// this.variablesCache = {} as any;
const ticker = createMonitoringTicker(this.monitoring);
ticker.subscribe((newTick) => __awaiter(this, void 0, void 0, function* () {
// console.log('New tick', newTick);
yield this.refreshValues();
}));
}
get values() {
const bundles = this.listBundles();
return combineLatest(bundles.map((v) => v.values.pipe(startWith(undefined)))).pipe(map((values) => {
return values.reduce((accumulator, v, index) => {
const bundleStreamId = bundles[index].id;
accumulator[bundleStreamId] = v;
return accumulator;
}, {});
}));
}
get events() {
return this._events.asObservable();
}
listVariables() {
return this.listBundles().reduce((acc, bundle) => {
acc.push(...bundle.variables);
return acc;
}, []);
}
bundle(key) {
if (!(key in this.bundles)) {
throw TapDataError.bundleNotFound(key);
}
return this.bundles[key];
}
// TODO fix typing
variable(key) {
const variable = this.listVariables().find((v) => v.id === key);
if (!variable) {
throw TapDataError.variableNotFound(key);
}
return variable;
}
// public addBundleFromConfig(key: BundleKey, bundleConfig: BundleConfig) {
// // const key = bundleConfig.name || bundleConfig.id.toString();
// // this.bundles[key] = createTapBundleDataFromConfig(bundleConfig);
// throw new Error(`Not implemented yet`);
// return this;
// }
destroy() {
this.monitoring.stop();
}
refreshValues() {
return __awaiter(this, void 0, void 0, function* () {
const values = {};
for (const bundle of this.listBundles()) {
values[bundle.id] = yield bundle
.read()
.catch((error) => {
this._events.next({
error,
type: DataManager.EventType.error,
});
return error;
});
}
return values;
});
}
listBundles() {
return Object.values(this.bundles);
}
// public setupStreams() {
// // this.bundle('x').monitor.start();
// // this.variable('y').monitor.
// const variableStream = this.ticker
// .pipe(
// switchMap(() => {
// return merge(
// this.listVariables().map(v => defer(() => v.read()))
// );
// })
// );
// const bundleStream = this.ticker
// .pipe(
// switchMap(() => {
// return merge(
// this.listBundles().map(v => defer(() => v.read()))
// );
// })
// );
// // const profileStream = this.ticker
// // .pipe(
// // switchMap(async () => {
// // // debug(TAG, `New call ${time} to read profile`);
// // const profileData = (await this.tap.service.variable.readProfile()).body();
// // const decoded = this.tlvConverter.decode(profileData);
// // this.rawDataStream.next(decoded);
// // })
// // );
// this.switchableStream
// .addStream(
// 'variable',
// variableStream
// )
// .addStream(
// 'bundle',
// bundleStream
// )
// // .addStream(
// // 'profile',
// // profileStream
// // );
// }
hasBundle(bundleKey) {
return bundleKey in this.bundles;
}
createConfiguredBundle(key, config) {
return createTapBundleFromConfig(this.tap, key, config);
}
createConfiguredVariable(key, config) {
return createTapVariableFromConfig(this.tap.service.variable, key, config);
}
/**
* Create a variable with direct modbus access
* May/May not be available according to the configured target protocol on your device
*
* @param id
* @param options
*/
createModbusAccessVariable(id, options) {
return new ModbusAccessVariable(id, {
config: options.config,
targetService: this.tap.service.target,
converter: options.converter,
});
}
/**
* Create direct target access to variable
* May/May not be available according to configured target protocol on your device
* @param id
* @param options
*/
createTargetMemoryVariable(id, options) {
return new TargetMemoryVariable(id, {
config: options.config,
targetService: this.tap.service.target,
converter: options.converter,
});
}
}
export class DataManager extends TypedDataManager {
constructor(tap, bundles = {},
// variables: Record<VariableKey, EditableDataStream<VariableByType[VariableKey]>>
monitoring = new MonitoringController()) {
super(tap, bundles, monitoring);
}
// registerConfiguredBundle(config: BundleConfig) {
// throw new Error('Not implemented yet');
// }
// registerConfiguredVariable(config: VariableConfig) {
// // this.variables.push();
// throw new Error('Not implemented yet');
// }
// createTapBundle<T>(name: string, bundleId: number, variables: T): BundleDataStreamInterface<T> {
// return createTapBundleFromConfig(
// this.tap,
// name,
// {
// id: bundleId,
// variables
// }
// );
// }
setBundles(bundles) {
this.bundles = bundles;
}
addBundle(bundle) {
this.bundles[bundle.id] = bundle;
}
removeBundle(bundleKey) {
delete this.bundles[bundleKey];
}
addVariable(bundleKey, variable) {
const bundle = this.bundle(bundleKey);
bundle.variables.push(variable); // TODO fix typing
}
/**
* Register bundles configured in the Tap
*/
registerBundles(bundlesConfig) {
const tapBundles = createTapBundlesFromConfig(this.tap, bundlesConfig);
this.setBundles(tapBundles);
return tapBundles;
}
registerBundle(key, config) {
const tapBundle = createTapBundleFromConfig(this.tap, key, config);
this.addBundle(tapBundle);
}
clear() {
this.bundles = {};
}
/**
* Synchronize DataManager bundles and variables with the connected Tap device
* It will the current profile accessible variables/bundles
*/
synchronizeTapConfig() {
return new Observable((observer) => {
try {
readDataManagerTapConfigFromTap(this.tap, {
observer,
})
.then((config) => {
const newBundles = this.registerBundles(config);
observer.next({
step: 'done',
bundles: newBundles,
});
observer.complete();
})
.catch((err) => {
observer.error(err);
});
}
catch (err) {
observer.error(err);
}
});
}
/**
* Configure DataManager bundles and variables from a DataConfig object (found in Tap configuration files)
* Data decoder will be dedecuced from dataType/length field.
*/
configureWithDataConfig(config) {
this.clear();
this.registerBundles(createDataManagerConfigFromTapDataConfig(config).bundles);
}
}
(function (DataManager) {
let EventType;
(function (EventType) {
EventType["error"] = "error";
})(EventType = DataManager.EventType || (DataManager.EventType = {}));
})(DataManager || (DataManager = {}));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vZGF0YS9zcmMvbGliL2RhdGEtbWFuYWdlci9kYXRhLW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBS0EsT0FBTyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzFELE9BQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFaEQsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixvQkFBb0IsR0FDckIsTUFBTSwyQkFBMkIsQ0FBQztBQUNuQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFakQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sa0RBQWtELENBQUM7QUFDeEYsT0FBTyxFQUNMLHlCQUF5QixHQUcxQixNQUFNLDBDQUEwQyxDQUFDO0FBQ2xELE9BQU8sRUFDTCwyQkFBMkIsR0FFNUIsTUFBTSw4Q0FBOEMsQ0FBQztBQUN0RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx5REFBeUQsQ0FBQztBQU0vRixPQUFPLEVBQUUsd0NBQXdDLEVBQUUsTUFBTSxtREFBbUQsQ0FBQztBQUM3RyxPQUFPLEVBRUwsMEJBQTBCLEVBRTFCLCtCQUErQixHQUNoQyxNQUFNLHVDQUF1QyxDQUFDO0FBRS9DLE1BQU0sR0FBRyxHQUFHLGFBQWEsQ0FBQztBQXlCMUI7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLGdCQUFnQjtJQWtDM0IsWUFDUyxHQUFRLEVBQ0wsT0FHVDtJQUNELGtGQUFrRjtJQUMzRSxhQUFhLElBQUksb0JBQW9CLEVBQUU7UUFFOUMsdUdBQXVHO1FBQ3ZHLDBDQUEwQztRQUMxQyw4Q0FBOEM7UUFDOUMsb0RBQW9EO1FBQ3BELDBEQUEwRDtRQUMxRCwyREFBMkQ7UUFDM0QsUUFBUTtRQUNSLElBQUk7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