bacnet-device
Version:
A TypeScript library for implementing BACnet IP devices in Node.js.
141 lines • 4.92 kB
JavaScript
/**
* BACnet singlet property implementation module
*
* This module provides the implementation for BACnet properties
* that contain a single value (as opposed to array properties).
*
* @module
*/
import fastq from 'fastq';
import {} from '../value.js';
import { BDEvented } from '../evented.js';
import { BDError } from '../errors.js';
import { PropertyIdentifier, ErrorCode, ErrorClass, ApplicationTag } from '@innovation-system/node-bacnet';
/**
* Implementation of a BACnet property with a single value
*
* This class represents a BACnet property that contains a single value (not an array).
* It manages the property's value and handles read/write operations and change notifications.
*
* @typeParam Tag - The BACnet application tag for the property value
* @typeParam Type - The JavaScript type corresponding to the application tag
* @extends BDEvented<BDSingletPropertyEvents<Tag, Type>>
*/
export class BDSingletProperty extends BDEvented {
/** Indicates this is not a list/array property */
list;
/** The BACnet application tag for this property's value */
type;
/** Whether this property can be written to */
writable;
settable;
/** The BACnet property identifier */
identifier;
/**
* The current value of this property
* @private
*/
#value;
/**
* Queue for serializing value changes
* @private
*/
#queue;
/**
* Creates a new BACnet singlet property
*
* @param identifier - The BACnet property identifier
* @param type - The BACnet application tag for this property's value
* @param writable - Whether this property can be written to
* @param value - The initial value for this property
*/
constructor(identifier, type, writable, value) {
super();
this.list = false;
this.type = type;
this.writable = typeof value !== 'function' && writable;
this.settable = typeof value !== 'function';
this.identifier = identifier;
this.#value = typeof value === 'function' ? value : { type, value };
this.#queue = fastq.promise(this.#worker, 1);
}
/**
* Gets the current value of this property
*
* @returns The current property value
*/
getValue() {
return typeof this.#value === 'function' ? this.#value().value : this.#value.value;
}
/**
* Sets a new value for this property
*
* This method queues the value change to ensure proper event
* notification and serialization of changes.
*
* @param value - The new value to set
* @returns A promise that resolves when the value has been set
*/
async setValue(value) {
if (this.settable) {
await this.#queue.push({ type: this.type, value });
}
else {
throw new Error(`Property ${this.identifier} is not settable`);
}
}
/**
* Reads the current value of this property for BACnet operations
*
* This internal method is used by BACnet objects to read the property value
* when handling BACnet protocol operations.
*
* @returns The current property value in BACnet format
* @internal
*/
___readValue() {
return typeof this.#value === 'function' ? this.#value() : this.#value;
}
/**
* Writes a new value to this property for BACnet operations
*
* This internal method is used by BACnet objects to write the property value
* when handling BACnet protocol operations.
*
* @param value - The new value to write in BACnet format
* @returns A promise that resolves when the value has been set
* @throws BACnetError if the property is not writable or the value type is invalid
* @internal
*/
async ___writeValue(value) {
if (!this.writable || !this.settable) {
throw new BDError('not writable', ErrorCode.WRITE_ACCESS_DENIED, ErrorClass.PROPERTY);
}
if (Array.isArray(value)) {
if (value.length !== 1) {
throw new BDError('not a list', ErrorCode.REJECT_INVALID_PARAMETER_DATA_TYPE, ErrorClass.PROPERTY);
}
else {
value = value[0];
}
}
if (value.type !== this.type) {
throw new BDError('not a list', ErrorCode.REJECT_INVALID_PARAMETER_DATA_TYPE, ErrorClass.PROPERTY);
}
await this.#queue.push(value);
}
/**
* Worker function for processing the value change queue
*
* This method processes each value change and triggers the appropriate events.
*
* @param value - The new value to set
* @private
*/
#worker = async (value) => {
await this.trigger('beforecov', this, value);
this.#value = value;
await this.trigger('aftercov', this, value);
};
}
//# sourceMappingURL=singlet.js.map