@@ -10,7 +10,7 @@ import { JobControl } from './api/controls/JobControl';
1010import { TempControl } from './api/controls/TempControl' ;
1111import { NetworkUtils } from './api/network/NetworkUtils' ;
1212import { Endpoints } from './api/server/Endpoints' ;
13- import type { FFMachineInfo } from './models/ff-models' ;
13+ import type { FFMachineInfo , Temperature } from './models/ff-models' ;
1414import { MachineInfo } from './models/MachineInfo' ;
1515import { FlashForgeClient } from './tcpapi/FlashForgeClient' ;
1616
@@ -58,10 +58,23 @@ export class FiveMClient {
5858 public isPro : boolean = false ;
5959 public isAD5X : boolean = false ;
6060 public isCreator5 : boolean = false ;
61+ public isCreator5Pro : boolean = false ;
62+ /** Immutable factory model name (e.g. "Creator 5 Pro"); not user-editable. */
63+ public model : string = '' ;
6164 public firmwareVersion : string = '' ;
6265 public firmVer : string = '' ;
6366 public cameraStreamUrl : string = '' ;
6467
68+ // Hardware capability flags (presence-derived, see MachineInfo.fromDetail).
69+ /** Whether the printer has a built-in camera. */
70+ public hasCamera : boolean = false ;
71+ /** Whether the printer has a lidar/first-layer scanner. */
72+ public hasLidar : boolean = false ;
73+ /** Whether the printer has a real door sensor (only then is door status meaningful). */
74+ public hasDoorSensor : boolean = false ;
75+ /** Current/target temperatures for every tool/nozzle (1 entry for single-nozzle models). */
76+ public toolTemps : Temperature [ ] = [ ] ;
77+
6578 public ipAddress : string ;
6679 public macAddress : string = '' ;
6780
@@ -78,6 +91,14 @@ export class FiveMClient {
7891 public filtrationControl : boolean = false ;
7992 /** Raw product info containing all control states */
8093 public productInfo : Product | null = null ;
94+ /** Capabilities derived from the /product control states (1 = available). */
95+ public capabilities : ProductCapabilities = {
96+ hasLed : false ,
97+ hasFiltration : false ,
98+ hasChamberControl : false ,
99+ hasNozzleControl : false ,
100+ hasPlatformControl : false ,
101+ } ;
81102
82103 /**
83104 * Creates an instance of FiveMClient.
@@ -201,6 +222,12 @@ export class FiveMClient {
201222 this . isPro = info . IsPro ; // Use the value from MachineInfo
202223 this . isAD5X = info . IsAD5X ; // Cache the AD5X status
203224 this . isCreator5 = info . IsCreator5 ; // Cache the Creator 5 status
225+ this . isCreator5Pro = info . IsCreator5Pro ; // Cache the Creator 5 Pro status
226+ this . model = info . Model || '' ;
227+ this . hasCamera = info . HasCamera ;
228+ this . hasLidar = info . HasLidar ;
229+ this . hasDoorSensor = info . HasDoorSensor ;
230+ this . toolTemps = info . ToolTemps || [ ] ;
204231 this . firmwareVersion = info . FirmwareVersion || '' ;
205232 this . firmVer = info . FirmwareVersion ? info . FirmwareVersion . split ( '-' ) [ 0 ] : '' ;
206233 this . cameraStreamUrl = info . CameraStreamUrl || '' ;
@@ -318,6 +345,31 @@ export class FiveMClient {
318345 }
319346 }
320347
348+ /**
349+ * Derives capability flags from a /product response. Polarity is
350+ * `1 = available, 0 = not available`; any missing field is treated as 0.
351+ *
352+ * NOTE: `hasFiltration` requires BOTH internal and external fan controls to be
353+ * available, matching the 5M Pro charcoal-filtration behavior. This is a pure
354+ * read of what /product advertises. The Creator 5 Pro under-reports it (both
355+ * fans 0 despite having the hardware), so its filtration is force-enabled by
356+ * model in `sendProductCommand` rather than here.
357+ *
358+ * @param product Raw (possibly sparse) product control-state object.
359+ * @returns Derived {@link ProductCapabilities}.
360+ */
361+ public static deriveCapabilities ( product : Partial < Product > ) : ProductCapabilities {
362+ const avail = ( v : number | undefined ) : boolean => v === 1 ;
363+ return {
364+ hasLed : avail ( product . lightCtrlState ) ,
365+ hasFiltration :
366+ avail ( product . internalFanCtrlState ) && avail ( product . externalFanCtrlState ) ,
367+ hasChamberControl : avail ( product . chamberTempCtrlState ) ,
368+ hasNozzleControl : avail ( product . nozzleTempCtrlState ) ,
369+ hasPlatformControl : avail ( product . platformTempCtrlState ) ,
370+ } ;
371+ }
372+
321373 /**
322374 * Sends a product command to the printer to retrieve control states.
323375 * This method sets the `httpClientBusy` flag while the request is in progress.
@@ -341,13 +393,20 @@ export class FiveMClient {
341393 try {
342394 const productResponse = response . data as ProductResponse ;
343395 if ( productResponse && NetworkUtils . isOk ( productResponse ) ) {
344- // Parse & set control states
345- const product = productResponse . product ;
396+ // Parse & set control states. /product polarity is 1 = available,
397+ // 0 = not available. Fields may be absent on some models, so default
398+ // missing values to 0 (treat as not-available) rather than assume.
399+ const product = productResponse . product ?? { } ;
346400 this . productInfo = product ; // Store raw product data
347- this . ledControl = product . lightCtrlState !== 0 ;
348- this . filtrationControl = ! (
349- product . internalFanCtrlState === 0 || product . externalFanCtrlState === 0
350- ) ;
401+ this . capabilities = FiveMClient . deriveCapabilities ( product ) ;
402+ // Creator 5 Pro has 5M-Pro-style filtration/aux fan per FlashForge
403+ // specs, but its /product under-reports it (both fan states 0), so
404+ // enable by model. The 5M Pro advertises it correctly and needs no
405+ // override. isCreator5Pro is already set here (verifyConnection ->
406+ // cacheDetails runs before initControl -> sendProductCommand).
407+ if ( this . isCreator5Pro ) this . capabilities . hasFiltration = true ;
408+ this . ledControl = this . capabilities . hasLed ;
409+ this . filtrationControl = this . capabilities . hasFiltration ;
351410 //console.log("LedControl: " + this.ledControl);
352411 //console.log("FiltrationControl: " + this.filtrationControl);
353412 return true ;
@@ -388,16 +447,33 @@ interface ProductResponse extends GenericResponse {
388447 * while other numbers (typically 1) mean on/available or a specific mode.
389448 */
390449export interface Product {
391- /** State of the chamber temperature control. */
392- chamberTempCtrlState : number ;
393- /** State of the external fan control. */
394- externalFanCtrlState : number ;
395- /** State of the internal fan control. */
396- internalFanCtrlState : number ;
397- /** State of the light control. */
398- lightCtrlState : number ;
399- /** State of the nozzle temperature control. */
400- nozzleTempCtrlState : number ;
401- /** State of the platform (bed) temperature control. */
402- platformTempCtrlState : number ;
450+ /** State of the chamber temperature control (1 = available). */
451+ chamberTempCtrlState ?: number ;
452+ /** State of the external fan control (1 = available). */
453+ externalFanCtrlState ?: number ;
454+ /** State of the internal fan control (1 = available). */
455+ internalFanCtrlState ?: number ;
456+ /** State of the light control (1 = available). */
457+ lightCtrlState ?: number ;
458+ /** State of the nozzle temperature control (1 = available). */
459+ nozzleTempCtrlState ?: number ;
460+ /** State of the platform (bed) temperature control (1 = available). */
461+ platformTempCtrlState ?: number ;
462+ }
463+
464+ /**
465+ * Capability flags derived from a printer's /product control states.
466+ * Each is true only when the corresponding control is reported as available.
467+ */
468+ export interface ProductCapabilities {
469+ /** LED light control is available. */
470+ hasLed : boolean ;
471+ /** Air-filtration control (both internal and external fans) is available. */
472+ hasFiltration : boolean ;
473+ /** Chamber temperature control is available. */
474+ hasChamberControl : boolean ;
475+ /** Nozzle temperature control is available. */
476+ hasNozzleControl : boolean ;
477+ /** Platform (bed) temperature control is available. */
478+ hasPlatformControl : boolean ;
403479}
0 commit comments