@duet3d/objectmodel 3.7.0-beta.1 → 3.7.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,13 +4,7 @@ TypeScript implementation of the Duet3D Object Model.
4
4
 
5
5
  ## Installation
6
6
 
7
- Install via `npm install @duet3d/objectmodel`. Users of Vue 2 must also run this command after the first import:
8
-
9
- ```
10
- globalThis._duetModelSetArray = (array, index, value) => Vue.set(array, index, value);
11
- ```
12
-
13
- This is required to make sure that change events for arrays are correctly fired.
7
+ Install via `npm install @duet3d/objectmodel`.
14
8
 
15
9
  ## Bug reports
16
10
 
@@ -18,9 +18,10 @@ export declare class ModelCollection<T extends IModelObject | null> extends Arra
18
18
  /**
19
19
  * Update this instance from the given data
20
20
  * @param jsonElement JSON data to upgrade this instance from
21
+ * @param authoritative Whether the given data is a complete snapshot of the items and everything below them
21
22
  * @returns Updated instance
22
23
  */
23
- update(jsonElement: any): IModelObject | null;
24
+ update(jsonElement: any, authoritative?: boolean): IModelObject | null;
24
25
  }
25
26
  export default ModelCollection;
26
27
  /**
@@ -1,5 +1,4 @@
1
1
  import { isModelObject } from "./ModelObject";
2
- import { setArrayItem } from "./index";
3
2
  /**
4
3
  * Class for storing model object items in an array
5
4
  */
@@ -34,9 +33,10 @@ export class ModelCollection extends Array {
34
33
  /**
35
34
  * Update this instance from the given data
36
35
  * @param jsonElement JSON data to upgrade this instance from
36
+ * @param authoritative Whether the given data is a complete snapshot of the items and everything below them
37
37
  * @returns Updated instance
38
38
  */
39
- update(jsonElement) {
39
+ update(jsonElement, authoritative = false) {
40
40
  if (jsonElement === null) {
41
41
  return null;
42
42
  }
@@ -52,23 +52,23 @@ export class ModelCollection extends Array {
52
52
  if (currentItem === null) {
53
53
  const newItem = jsonElement[i];
54
54
  if (newItem instanceof that.$itemConstructor) {
55
- setArrayItem(this, i, jsonElement[i]);
55
+ this[i] = jsonElement[i];
56
56
  }
57
57
  else {
58
58
  const refItem = new that.$itemConstructor();
59
- setArrayItem(this, i, refItem.update(newItem));
59
+ this[i] = refItem.update(newItem, authoritative);
60
60
  }
61
61
  }
62
62
  else if (isModelObject(currentItem)) {
63
- const newItem = currentItem.update(jsonElement[i]);
63
+ const newItem = currentItem.update(jsonElement[i], authoritative);
64
64
  if (currentItem !== newItem) {
65
- setArrayItem(this, i, newItem);
65
+ this[i] = newItem;
66
66
  }
67
67
  }
68
68
  else {
69
69
  const newItem = jsonElement[i];
70
70
  if (currentItem !== newItem) {
71
- setArrayItem(this, i, newItem);
71
+ this[i] = newItem;
72
72
  }
73
73
  }
74
74
  }
@@ -80,7 +80,7 @@ export class ModelCollection extends Array {
80
80
  }
81
81
  else {
82
82
  const newItem = new that.$itemConstructor();
83
- super.push(newItem.update(itemToAdd));
83
+ super.push(newItem.update(itemToAdd, authoritative));
84
84
  }
85
85
  }
86
86
  return this;
@@ -15,14 +15,16 @@ export declare class ModelDictionary<T> extends Map<string, T | null> implements
15
15
  * Overridden set method to perform type-checks and update
16
16
  * @param key Key to set
17
17
  * @param value Value to set
18
+ * @param authoritative Whether the given value is a complete snapshot of the item and everything below it
18
19
  */
19
- set(key: string, value: T | null): this;
20
+ set(key: string, value: T | null, authoritative?: boolean): this;
20
21
  /**
21
22
  * Update this instance from the given data
22
23
  * @param jsonElement JSON data to upgrade this instance from
24
+ * @param authoritative Whether the given data is a complete snapshot of the items and everything below them
23
25
  * @returns Updated instance
24
26
  */
25
- update(jsonElement: any): IModelObject | null;
27
+ update(jsonElement: any, authoritative?: boolean): IModelObject | null;
26
28
  /**
27
29
  * Convert this object to JSON
28
30
  * @returns JSON object
@@ -18,8 +18,9 @@ export class ModelDictionary extends Map {
18
18
  * Overridden set method to perform type-checks and update
19
19
  * @param key Key to set
20
20
  * @param value Value to set
21
+ * @param authoritative Whether the given value is a complete snapshot of the item and everything below it
21
22
  */
22
- set(key, value) {
23
+ set(key, value, authoritative = false) {
23
24
  const that = this;
24
25
  if (value === null) {
25
26
  if (that.$nullDeletesKeys) {
@@ -33,13 +34,13 @@ export class ModelDictionary extends Map {
33
34
  if (that.$itemConstructor !== null && !(value instanceof that.$itemConstructor)) {
34
35
  const newItem = new that.$itemConstructor();
35
36
  if (isModelObject(newItem)) {
36
- const updatedItem = newItem.update(value);
37
+ const updatedItem = newItem.update(value, authoritative);
37
38
  return super.set(key, updatedItem);
38
39
  }
39
40
  }
40
41
  }
41
42
  else if (isModelObject(currentItem)) {
42
- const newItem = currentItem.update(value);
43
+ const newItem = currentItem.update(value, authoritative);
43
44
  if (currentItem !== newItem) {
44
45
  return super.set(key, value);
45
46
  }
@@ -50,20 +51,21 @@ export class ModelDictionary extends Map {
50
51
  /**
51
52
  * Update this instance from the given data
52
53
  * @param jsonElement JSON data to upgrade this instance from
54
+ * @param authoritative Whether the given data is a complete snapshot of the items and everything below them
53
55
  * @returns Updated instance
54
56
  */
55
- update(jsonElement) {
57
+ update(jsonElement, authoritative = false) {
56
58
  if (jsonElement === null) {
57
59
  this.clear();
58
60
  }
59
61
  else if (jsonElement instanceof Map) {
60
62
  for (const [key, value] of jsonElement.entries()) {
61
- this.set(key, value);
63
+ this.set(key, value, authoritative);
62
64
  }
63
65
  }
64
66
  else {
65
67
  for (const [key, value] of Object.entries(jsonElement)) {
66
- this.set(key, value);
68
+ this.set(key, value, authoritative);
67
69
  }
68
70
  }
69
71
  return this;
@@ -5,9 +5,12 @@ export interface IModelObject {
5
5
  /**
6
6
  * Update this instance from the given data
7
7
  * @param jsonElement JSON data to upgrade this instance from
8
+ * @param authoritative Whether the given data is a complete snapshot of this instance and everything below it,
9
+ * so that properties missing from it are known to be null. Set this only for responses that were not filtered
10
+ * by the sender, i.e. full object model key queries but never live/patch updates
8
11
  * @returns Updated instance (may not equal the original instance)
9
12
  */
10
- update(jsonElement: any): IModelObject | null;
13
+ update(jsonElement: any, authoritative?: boolean): IModelObject | null;
11
14
  }
12
15
  /**
13
16
  * Check whether a given value provides model update functionality
@@ -18,12 +21,20 @@ export declare function isModelObject(value: any): value is IModelObject;
18
21
  * Base class for object model classes
19
22
  */
20
23
  export declare abstract class ModelObject implements IModelObject {
24
+ /**
25
+ * Whether an authoritative update may reset the properties of this class that are missing from it.
26
+ * Set to false where an instance never receives a complete snapshot of itself. Deliberately static
27
+ * because an instance member would become part of the structural type and break consumers that hold
28
+ * a mapped version of the model, such as a Pinia store
29
+ */
30
+ static readonly resetsMissingProperties: boolean;
21
31
  /**
22
32
  * Update this instance from the given data
23
33
  * @param jsonElement JSON data to upgrade this instance from
34
+ * @param authoritative Whether the given data is a complete snapshot of this instance and everything below it
24
35
  * @returns Updated instance (may not equal the original instance)
25
36
  */
26
- update(jsonElement: any): IModelObject | null;
37
+ update(jsonElement: any, authoritative?: boolean): IModelObject | null;
27
38
  /**
28
39
  * Wrap a nullable model object property so that type checks can be performed
29
40
  * @param key Property key of the derived class
@@ -1,4 +1,34 @@
1
- import { ModelCollection, setArrayItem } from "./index";
1
+ import { ModelCollection } from "./index";
2
+ /**
3
+ * Names of the properties that default to null, per model object class. Queried from a pristine instance because
4
+ * TS types are gone at runtime, so a null default is the only remaining evidence that a property may hold null
5
+ */
6
+ const nullableProperties = new WeakMap();
7
+ /**
8
+ * Get the names of the properties of the given instance's class that may hold null
9
+ * @param instance Instance to inspect the class of
10
+ */
11
+ function getNullableProperties(instance) {
12
+ let result = nullableProperties.get(instance.constructor);
13
+ if (result === undefined) {
14
+ result = new Set();
15
+ try {
16
+ for (const [key, value] of Object.entries(new instance.constructor())) {
17
+ if (value === null) {
18
+ result.add(key);
19
+ }
20
+ }
21
+ }
22
+ catch (e) {
23
+ // A class that cannot be constructed without arguments simply opts out of null reconstruction
24
+ if (process.env.NODE_ENV !== "production") {
25
+ console.warn(`Failed to determine nullable properties of ${instance.constructor.name}`, e);
26
+ }
27
+ }
28
+ nullableProperties.set(instance.constructor, result);
29
+ }
30
+ return result;
31
+ }
2
32
  /**
3
33
  * Check whether a given value provides model update functionality
4
34
  * @param value Value to check
@@ -13,19 +43,27 @@ export class ModelObject {
13
43
  /**
14
44
  * Update this instance from the given data
15
45
  * @param jsonElement JSON data to upgrade this instance from
46
+ * @param authoritative Whether the given data is a complete snapshot of this instance and everything below it
16
47
  * @returns Updated instance (may not equal the original instance)
17
48
  */
18
- update(jsonElement) {
49
+ update(jsonElement, authoritative = false) {
19
50
  if (jsonElement === null) {
20
51
  return null;
21
52
  }
53
+ if (authoritative && this.constructor.resetsMissingProperties) {
54
+ for (const key of getNullableProperties(this)) {
55
+ if (!(key in jsonElement)) {
56
+ this[key] = null;
57
+ }
58
+ }
59
+ }
22
60
  for (const [key, value] of Object.entries(jsonElement)) {
23
61
  if (key in this) {
24
62
  const ownKey = key;
25
63
  const prop = this[ownKey];
26
64
  if (isModelObject(prop)) {
27
65
  // Update model objects
28
- const updatedObject = prop.update(value);
66
+ const updatedObject = prop.update(value, authoritative);
29
67
  if (prop !== updatedObject) {
30
68
  const propDescriptor = Object.getOwnPropertyDescriptor(this, key);
31
69
  if (propDescriptor !== undefined) {
@@ -49,12 +87,12 @@ export class ModelObject {
49
87
  for (let i = 0; i < Math.min(prop.length, value.length); i++) {
50
88
  const propItem = prop[i];
51
89
  if (propItem === null) {
52
- setArrayItem(prop, i, value[i]);
90
+ prop[i] = value[i];
53
91
  }
54
92
  else {
55
93
  const newItem = value[i];
56
94
  if (propItem !== newItem) {
57
- setArrayItem(prop, i, newItem);
95
+ prop[i] = newItem;
58
96
  }
59
97
  }
60
98
  }
@@ -219,6 +257,13 @@ export class ModelObject {
219
257
  });
220
258
  }
221
259
  }
260
+ /**
261
+ * Whether an authoritative update may reset the properties of this class that are missing from it.
262
+ * Set to false where an instance never receives a complete snapshot of itself. Deliberately static
263
+ * because an instance member would become part of the structural type and break consumers that hold
264
+ * a mapped version of the model, such as a Pinia store
265
+ */
266
+ ModelObject.resetsMissingProperties = true;
222
267
  export default ModelObject;
223
268
  /**
224
269
  * Initialize a model object from the given data
@@ -24,6 +24,11 @@ import LedStrip from "./ledStrips";
24
24
  */
25
25
  export declare class ObjectModel extends ModelObject {
26
26
  constructor();
27
+ /**
28
+ * A payload handed to the root always covers a subset of the top-level keys rather than the whole model,
29
+ * so authoritative reconstruction has to start one level below it
30
+ */
31
+ static readonly resetsMissingProperties: boolean;
27
32
  readonly boards: ModelCollection<Board>;
28
33
  readonly directories: Directories;
29
34
  readonly fans: ModelCollection<Fan | null>;
@@ -47,4 +47,9 @@ export class ObjectModel extends ModelObject {
47
47
  ModelObject.wrapModelProperty(this, "sbc", SBC);
48
48
  }
49
49
  }
50
+ /**
51
+ * A payload handed to the root always covers a subset of the top-level keys rather than the whole model,
52
+ * so authoritative reconstruction has to start one level below it
53
+ */
54
+ ObjectModel.resetsMissingProperties = false;
50
55
  export default ObjectModel;
@@ -48,6 +48,7 @@ export declare class Board extends ModelObject {
48
48
  shortName: string;
49
49
  state: BoardState;
50
50
  supportsDirectDisplay: boolean;
51
+ timeout: number;
51
52
  uniqueId: string | null;
52
53
  v12: MinMaxCurrent | null;
53
54
  vIn: MinMaxCurrent | null;
@@ -59,6 +59,7 @@ export class Board extends ModelObject {
59
59
  this.shortName = "";
60
60
  this.state = BoardState.unknown;
61
61
  this.supportsDirectDisplay = false;
62
+ this.timeout = 10;
62
63
  this.uniqueId = null;
63
64
  this.v12 = null;
64
65
  this.vIn = null;
@@ -18,6 +18,7 @@
18
18
  "boards[].directDisplay.encoder": "Encoder of this screen or null if none",
19
19
  "boards[].directDisplay.encoder.pulsesPerClick": "Number of pulses per click of the rotary encoder",
20
20
  "boards[].directDisplay.screen": "Screen information",
21
+ "boards[].directDisplay.screen.contrast": "Configured contrast",
21
22
  "boards[].directDisplay.screen.controller": {
22
23
  "values": {
23
24
  "ST7920": "ST7920 controller",
@@ -25,6 +26,7 @@
25
26
  "ILI9488": "ILI9488 controller"
26
27
  }
27
28
  },
29
+ "boards[].directDisplay.screen.resistorRatio": "Configured resistor ratio",
28
30
  "boards[].drivers": "Drivers of this board",
29
31
  "boards[].drivers[].closedLoop.currentFraction": "Current fraction of the configured motor current used",
30
32
  "boards[].drivers[].closedLoop.positionError": "Position error in full steps of the motor",
@@ -74,6 +76,7 @@
74
76
  }
75
77
  },
76
78
  "boards[].supportsDirectDisplay": "Indicates if this board supports external displays",
79
+ "boards[].timeout": "Connection timeout of this board (in s)",
77
80
  "boards[].uniqueId": "Unique identifier of the board or null if unknown",
78
81
  "boards[].v12": "Minimum, maximum, and current voltages on the 12V rail or null if unknown",
79
82
  "boards[].v12.current": "Current value",
@@ -498,6 +501,7 @@
498
501
  "move.currentMove.distance": "Total distance of the current move (in mm)",
499
502
  "move.currentMove.duration": "Duration of the current move (in s)",
500
503
  "move.currentMove.extrusionRate": "Current extrusion rate (in mm/s)",
504
+ "move.currentMove.filePosition": "Position in the job file of the move being executed (in bytes or null)",
501
505
  "move.currentMove.laserPwm": "Laser PWM of the current move (0..1) or null if not applicable",
502
506
  "move.currentMove.requestedSpeed": "Requested speed of the current move (in mm/s)",
503
507
  "move.currentMove.topSpeed": "Top speed of the current move (in mm/s)",
@@ -536,6 +540,14 @@
536
540
  "move.keepout[].coords[].max": "Maximum axis coordinate",
537
541
  "move.keepout[].coords[].min": "Minimum axis coordinate",
538
542
  "move.kinematics": "Configured kinematics options",
543
+ "move.kinematics.anchors": "Anchor configurations for A, B, C, Dz",
544
+ "move.kinematics.crosstalk": "Proximal to distal, proximal to Z and distal to Z crosstalk",
545
+ "move.kinematics.deltaRadius": "Delta radius (in mm)",
546
+ "move.kinematics.distalLength": "Distal arm length (in mm)",
547
+ "move.kinematics.forwardMatrix": "Forward matrix",
548
+ "move.kinematics.homedHeight": "Homed height of a delta printer in mm",
549
+ "move.kinematics.inverseMatrix": "Inverse matrix",
550
+ "move.kinematics.minRadius": "Requested minimum radius (in mm)",
539
551
  "move.kinematics.name": {
540
552
  "summary": "Name of the configured kinematics",
541
553
  "values": {
@@ -554,9 +566,35 @@
554
566
  "unknown": "Unknown"
555
567
  }
556
568
  },
569
+ "move.kinematics.printRadius": "Print radius for Hangprinter and Delta geometries (in mm)",
570
+ "move.kinematics.proximalLength": "Proximal arm length (in mm)",
571
+ "move.kinematics.psiLimits": "Psi limits (in degrees)",
572
+ "move.kinematics.radiusHomed": "Homed radius (in mm)",
573
+ "move.kinematics.radiusMax": "Maximum radius (in mm)",
574
+ "move.kinematics.radiusMin": "Minimum radius (in mm)",
557
575
  "move.kinematics.segmentation": "Segmentation parameters or null if not configured",
558
576
  "move.kinematics.segmentation.minSegLength": "Minimum length of a segment (in mm)",
559
577
  "move.kinematics.segmentation.segmentsPerSec": "Number of segments per second",
578
+ "move.kinematics.thetaLimits": "Theta limits (in degrees)",
579
+ "move.kinematics.tiltCorrection": "Parameters describing the tilt correction",
580
+ "move.kinematics.tiltCorrection.correctionFactor": "Correction factor",
581
+ "move.kinematics.tiltCorrection.lastCorrections": "Last corrections (in mm)",
582
+ "move.kinematics.tiltCorrection.maxCorrection": "Maximum Z correction (in mm)",
583
+ "move.kinematics.tiltCorrection.screwPitch": "Pitch of the Z leadscrews (in mm)",
584
+ "move.kinematics.tiltCorrection.screwX": "X positions of the leadscrews (in mm)",
585
+ "move.kinematics.tiltCorrection.screwY": "Y positions of the leadscrews (in mm)",
586
+ "move.kinematics.towers": "Delta tower properties",
587
+ "move.kinematics.towers[].angleCorrection": "Tower position corrections (in degrees)",
588
+ "move.kinematics.towers[].diagonal": "Diagonal rod length (in mm)",
589
+ "move.kinematics.towers[].endstopAdjustment": "Deviation of the ideal endstop position (in mm)",
590
+ "move.kinematics.towers[].xPos": "X coordinate of this tower (in mm)",
591
+ "move.kinematics.towers[].yPos": "Y coordinate of this tower (in mm)",
592
+ "move.kinematics.ttAccMax": "Maximum turntable acceleration (in mm/s^2)",
593
+ "move.kinematics.ttSpeedMax": "Maximum turntable speed (in mm/s)",
594
+ "move.kinematics.xOffset": "X offset (in mm)",
595
+ "move.kinematics.xTilt": "How much Z needs to be raised for each unit of movement in the +X direction",
596
+ "move.kinematics.yOffset": "Y offset (in mm)",
597
+ "move.kinematics.yTilt": "How much Z needs to be raised for each unit of movement in the +Y direction",
560
598
  "move.limitAxes": "Limit axis positions by their minima and maxima",
561
599
  "move.motionSystems": "List of configured motion systems",
562
600
  "move.motionSystems[].currentMove": "Information about the current move",
@@ -565,6 +603,7 @@
565
603
  "move.motionSystems[].currentMove.distance": "Total distance of the current move (in mm)",
566
604
  "move.motionSystems[].currentMove.duration": "Duration of the current move (in s)",
567
605
  "move.motionSystems[].currentMove.extrusionRate": "Current extrusion rate (in mm/s)",
606
+ "move.motionSystems[].currentMove.filePosition": "Position in the job file of the move being executed (in bytes or null)",
568
607
  "move.motionSystems[].currentMove.laserPwm": "Laser PWM of the current move (0..1) or null if not applicable",
569
608
  "move.motionSystems[].currentMove.requestedSpeed": "Requested speed of the current move (in mm/s)",
570
609
  "move.motionSystems[].currentMove.topSpeed": "Top speed of the current move (in mm/s)",
@@ -578,7 +617,7 @@
578
617
  "move.motionSystems[].restorePoints[].extruderPos": "The virtual extruder position at the start of this move",
579
618
  "move.motionSystems[].restorePoints[].fanPwm": "PWM value of the tool fan (0..1)",
580
619
  "move.motionSystems[].restorePoints[].feedRate": "Requested feedrate (in mm/s)",
581
- "move.motionSystems[].restorePoints[].gCommandNumber": "Which of G0/G1/G2/G3 generated the move at this restore point",
620
+ "move.motionSystems[].restorePoints[].gCommandNumber": "Which of G0/G1/G2/G3 generated the move at this restore point, or -1 if unknown",
582
621
  "move.motionSystems[].restorePoints[].ioBits": "The output port bits setting for this move or null if not applicable",
583
622
  "move.motionSystems[].restorePoints[].laserPwm": "Laser PWM value (0..1) or null if not applicable",
584
623
  "move.motionSystems[].restorePoints[].toolNumber": "The tool number that was active",
@@ -782,6 +821,9 @@
782
821
  "sbc.memory.total": "Total memory (in bytes)",
783
822
  "sbc.model": "SBC model or null if unknown",
784
823
  "sbc.serial": "Serial of the SBC or null if unknown",
824
+ "sbc.upgrade": "Details about a software upgrade in progress or null if no upgrade is running",
825
+ "sbc.upgrade.message": "Description of the current upgrade step",
826
+ "sbc.upgrade.progress": "Progress of the current upgrade step (0..1) or null if indeterminate",
785
827
  "sbc.uptime": "Uptime of the running system (in s)",
786
828
  "sensors": "Information about connected sensors including Z-probes and endstops",
787
829
  "sensors.analog": "List of analog sensors",
@@ -874,6 +916,23 @@
874
916
  }
875
917
  },
876
918
  "sensors.filamentMonitors": "List of configured filament monitors",
919
+ "sensors.filamentMonitors[].agc": "AGC reading of this filament monitor (null if unknown)",
920
+ "sensors.filamentMonitors[].avgPercentage": "Average ratio of measured vs. commanded movement",
921
+ "sensors.filamentMonitors[].calibrated": "Calibrated properties of this filament monitor",
922
+ "sensors.filamentMonitors[].calibrated.mmPerPulse": "Extruded distance per pulse (in mm)",
923
+ "sensors.filamentMonitors[].calibrated.mmPerRev": "Extruded distance per revolution (in mm)",
924
+ "sensors.filamentMonitors[].calibrated.percentMax": "Maximum percentage (0..1 or greater)",
925
+ "sensors.filamentMonitors[].calibrated.percentMin": "Minimum percentage (0..1)",
926
+ "sensors.filamentMonitors[].calibrated.sensitivity": "Calibrated sensitivity",
927
+ "sensors.filamentMonitors[].calibrated.totalDistance": "Total extruded distance (in mm)",
928
+ "sensors.filamentMonitors[].configured": "Configured properties of this filament monitor",
929
+ "sensors.filamentMonitors[].configured.allMoves": "Whether all moves and not only printing moves are supposed to be checked",
930
+ "sensors.filamentMonitors[].configured.calibrationFactor": "Calibration factor of this sensor",
931
+ "sensors.filamentMonitors[].configured.mmPerPulse": "Extruded distance per pulse (in mm)",
932
+ "sensors.filamentMonitors[].configured.mmPerRev": "Extruded distance per revolution (in mm)",
933
+ "sensors.filamentMonitors[].configured.percentMax": "Maximum percentage (0..1 or greater)",
934
+ "sensors.filamentMonitors[].configured.percentMin": "Minimum percentage (0..1)",
935
+ "sensors.filamentMonitors[].configured.sampleDistance": "Sample distance (in mm)",
877
936
  "sensors.filamentMonitors[].enableMode": {
878
937
  "summary": "Enable mode of this filament monitor",
879
938
  "values": {
@@ -883,6 +942,11 @@
883
942
  }
884
943
  },
885
944
  "sensors.filamentMonitors[].enabled": "Whether this filament monitor is enabled",
945
+ "sensors.filamentMonitors[].filamentPresent": "Indicates if filament is present in this filament monitor (null if unknown)",
946
+ "sensors.filamentMonitors[].lastPercentage": "Last ratio of measured vs. commanded movement",
947
+ "sensors.filamentMonitors[].maxPercentage": "Maximum ratio of measured vs. commanded movement",
948
+ "sensors.filamentMonitors[].minPercentage": "Minimum ratio of measured vs. commanded movement",
949
+ "sensors.filamentMonitors[].position": "Reported sensor position of this filament monitor. The maximum value depends on the type of the sensor, e.g. 0..1023 for a Duet3D MFM.",
886
950
  "sensors.filamentMonitors[].status": {
887
951
  "summary": "Last reported status of this filament monitor",
888
952
  "values": {
@@ -895,6 +959,7 @@
895
959
  "sensorError": "Sensor encountered an error"
896
960
  }
897
961
  },
962
+ "sensors.filamentMonitors[].totalExtrusion": "Total extrusion commanded (in mm)",
898
963
  "sensors.filamentMonitors[].type": {
899
964
  "summary": "Type of this filament monitor",
900
965
  "values": {
@@ -1047,7 +1112,7 @@
1047
1112
  "state.restorePoints[].extruderPos": "The virtual extruder position at the start of this move",
1048
1113
  "state.restorePoints[].fanPwm": "PWM value of the tool fan (0..1)",
1049
1114
  "state.restorePoints[].feedRate": "Requested feedrate (in mm/s)",
1050
- "state.restorePoints[].gCommandNumber": "Which of G0/G1/G2/G3 generated the move at this restore point",
1115
+ "state.restorePoints[].gCommandNumber": "Which of G0/G1/G2/G3 generated the move at this restore point, or -1 if unknown",
1051
1116
  "state.restorePoints[].ioBits": "The output port bits setting for this move or null if not applicable",
1052
1117
  "state.restorePoints[].laserPwm": "Laser PWM value (0..1) or null if not applicable",
1053
1118
  "state.restorePoints[].toolNumber": "The tool number that was active",
package/dist/index.d.ts CHANGED
@@ -23,4 +23,3 @@ export * from "./volumes";
23
23
  export * from "./ObjectModel";
24
24
  import ObjectModel from "./ObjectModel";
25
25
  export default ObjectModel;
26
- export declare function setArrayItem(array: Array<any>, index: number, value: any): void;
package/dist/index.js CHANGED
@@ -25,13 +25,3 @@ export * from "./ObjectModel";
25
25
  // Expose ObjectModel as default export
26
26
  import ObjectModel from "./ObjectModel";
27
27
  export default ObjectModel;
28
- // Unfortunately we need to define a way to update arrays to remain compatible with Vue 2 (due to IE11).
29
- // This will become obsolete as soon as DWC is upgraded to Vue 3, but that isn't going to happen anytime soon.
30
- // Until then a Vue 2 user would have to call something like this on initialization to work around this limitation:
31
- // globalThis._duetModelSetArray = (array, index, value) => Vue.set(array, index, value);
32
- // or in TypeScript
33
- // (globalThis as any)._duetModelSetArray = (array: object, index: string | number, value: any) => Vue.set(array, index, value);
34
- globalThis._duetModelSetArray = (array, index, value) => array[index] = value;
35
- export function setArrayItem(array, index, value) {
36
- globalThis._duetModelSetArray(array, index, value);
37
- }
@@ -14,6 +14,7 @@ export declare class CurrentMove extends ModelObject {
14
14
  distance: number;
15
15
  duration: number;
16
16
  extrusionRate: number;
17
+ filePosition: number | null;
17
18
  laserPwm: number | null;
18
19
  requestedSpeed: number;
19
20
  topSpeed: number;
@@ -16,6 +16,7 @@ export class CurrentMove extends ModelObject {
16
16
  this.distance = 0;
17
17
  this.duration = 0;
18
18
  this.extrusionRate = 0;
19
+ this.filePosition = null;
19
20
  this.laserPwm = null;
20
21
  this.requestedSpeed = 0;
21
22
  this.topSpeed = 0;
@@ -0,0 +1,6 @@
1
+ import ModelObject from "../ModelObject";
2
+ export declare class Upgrade extends ModelObject {
3
+ message: string;
4
+ progress: number | null;
5
+ }
6
+ export default Upgrade;
@@ -0,0 +1,9 @@
1
+ import ModelObject from "../ModelObject";
2
+ export class Upgrade extends ModelObject {
3
+ constructor() {
4
+ super(...arguments);
5
+ this.message = "";
6
+ this.progress = null;
7
+ }
8
+ }
9
+ export default Upgrade;
@@ -2,7 +2,9 @@ import ModelObject from "../ModelObject";
2
2
  import DSF from "./dsf";
3
3
  import CPU from "./CPU";
4
4
  import Memory from "./Memory";
5
+ import Upgrade from "./Upgrade";
5
6
  export declare class SBC extends ModelObject {
7
+ constructor();
6
8
  appArmor: boolean;
7
9
  readonly cpu: CPU;
8
10
  readonly dsf: DSF;
@@ -11,9 +13,11 @@ export declare class SBC extends ModelObject {
11
13
  readonly memory: Memory;
12
14
  model: string | null;
13
15
  serial: string | null;
16
+ upgrade: Upgrade | null;
14
17
  uptime: number | null;
15
18
  }
16
19
  export default SBC;
17
20
  export * from "./dsf";
18
21
  export * from "./CPU";
19
22
  export * from "./Memory";
23
+ export * from "./Upgrade";
package/dist/sbc/index.js CHANGED
@@ -2,9 +2,10 @@ import ModelObject from "../ModelObject";
2
2
  import DSF from "./dsf";
3
3
  import CPU from "./CPU";
4
4
  import Memory from "./Memory";
5
+ import Upgrade from "./Upgrade";
5
6
  export class SBC extends ModelObject {
6
7
  constructor() {
7
- super(...arguments);
8
+ super();
8
9
  this.appArmor = false;
9
10
  this.cpu = new CPU();
10
11
  this.dsf = new DSF();
@@ -13,10 +14,13 @@ export class SBC extends ModelObject {
13
14
  this.memory = new Memory();
14
15
  this.model = null;
15
16
  this.serial = null;
17
+ this.upgrade = null;
16
18
  this.uptime = null;
19
+ ModelObject.wrapModelProperty(this, "upgrade", Upgrade);
17
20
  }
18
21
  }
19
22
  export default SBC;
20
23
  export * from "./dsf";
21
24
  export * from "./CPU";
22
25
  export * from "./Memory";
26
+ export * from "./Upgrade";
@@ -26,6 +26,7 @@ export declare class FilamentMonitorBase extends ModelObject {
26
26
  */
27
27
  enabled: boolean;
28
28
  enableMode: FilamentMonitorEnableMode;
29
+ filamentPresent: boolean | null;
29
30
  status: FilamentMonitorStatus;
30
31
  type: FilamentMonitorType;
31
32
  constructor(type?: FilamentMonitorType);
@@ -31,6 +31,7 @@ export class FilamentMonitorBase extends ModelObject {
31
31
  */
32
32
  this.enabled = false;
33
33
  this.enableMode = FilamentMonitorEnableMode.disabled;
34
+ this.filamentPresent = null;
34
35
  this.status = FilamentMonitorStatus.noDataReceived;
35
36
  this.type = type;
36
37
  }
@@ -16,6 +16,7 @@ export declare class RotatingMagnetFilamentMonitorConfigured extends ModelObject
16
16
  }
17
17
  export declare class RotatingMagnetFilamentMonitor extends Duet3DFilamentMonitor {
18
18
  constructor();
19
+ agc: number | null;
19
20
  calibrated: RotatingMagnetFilamentMonitorCalibrated | null;
20
21
  readonly configured: RotatingMagnetFilamentMonitorConfigured;
21
22
  update(jsonElement: any): IModelObject | null;
@@ -24,6 +24,7 @@ export class RotatingMagnetFilamentMonitorConfigured extends ModelObject {
24
24
  export class RotatingMagnetFilamentMonitor extends Duet3DFilamentMonitor {
25
25
  constructor() {
26
26
  super(FilamentMonitorType.rotatingMagnet);
27
+ this.agc = null;
27
28
  this.calibrated = new RotatingMagnetFilamentMonitorCalibrated();
28
29
  this.configured = new RotatingMagnetFilamentMonitorConfigured();
29
30
  ModelObject.wrapModelProperty(this, "calibrated", RotatingMagnetFilamentMonitorCalibrated);
@@ -6,7 +6,7 @@ export class RestorePoint extends ModelObject {
6
6
  this.extruderPos = 0;
7
7
  this.fanPwm = 0;
8
8
  this.feedRate = 0;
9
- this.gCommandNumber = 0;
9
+ this.gCommandNumber = -1;
10
10
  this.ioBits = null;
11
11
  this.laserPwm = null;
12
12
  this.toolNumber = -1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duet3d/objectmodel",
3
- "version": "3.7.0-beta.1",
3
+ "version": "3.7.0-beta.10",
4
4
  "description": "TypeScript implementation of the Duet3D Object Model",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,10 +15,10 @@
15
15
  "./documentation.json": "./dist/documentation.json"
16
16
  },
17
17
  "scripts": {
18
- "test": "jest --config jestconfig.json",
19
- "build": "tsc && tsx scripts/extract-metadata.ts",
18
+ "test": "tsc -p tsconfig.test.json --noEmit && jest --config jestconfig.json",
19
+ "build": "tsc && node scripts/extract-metadata.ts",
20
20
  "prepare": "npm run build",
21
- "prepublishOnly": "npm test"
21
+ "prepublishOnly": "npm test && node scripts/check-metadata.ts"
22
22
  },
23
23
  "repository": {
24
24
  "type": "git",
@@ -31,12 +31,12 @@
31
31
  },
32
32
  "homepage": "https://github.com/Duet3D/ObjectModel#readme",
33
33
  "devDependencies": {
34
+ "@swc/core": "^1.15.43",
35
+ "@swc/jest": "^0.2.39",
34
36
  "@types/jest": "^30.0.0",
35
- "@types/node": "^25.0.0",
36
- "jest": "^30.2.0",
37
- "ts-jest": "^29.1.2",
38
- "tsx": "^4.20.0",
39
- "typescript": "^6.0.3"
37
+ "@types/node": "^26.1.1",
38
+ "jest": "^30.4.2",
39
+ "typescript": "^7.0.2"
40
40
  },
41
41
  "files": [
42
42
  "/dist"