@@ -6,6 +6,24 @@ const noRoom = {
66 selector : 'no-room' ,
77} ;
88
9+ const ONE_HOUR_IN_MINUTES = 60 ;
10+ const TWELVE_HOURS_IN_MINUTES = 12 * 60 ;
11+ const ONE_DAY_IN_MINUTES = 24 * 60 ;
12+ const SEVEN_DAYS_IN_MINUTES = 7 * 24 * 60 ;
13+ const THIRTY_DAYS_IN_MINUTES = 30 * 24 * 60 ;
14+ const THREE_MONTHS_IN_MINUTES = 3 * 30 * 24 * 60 ;
15+ const ONE_YEAR_IN_MINUTES = 365 * 24 * 60 ;
16+
17+ const intervalByName = {
18+ 'last-hour' : ONE_HOUR_IN_MINUTES ,
19+ 'last-twelve-hours' : TWELVE_HOURS_IN_MINUTES ,
20+ 'last-day' : ONE_DAY_IN_MINUTES ,
21+ 'last-week' : SEVEN_DAYS_IN_MINUTES ,
22+ 'last-month' : THIRTY_DAYS_IN_MINUTES ,
23+ 'last-three-months' : THREE_MONTHS_IN_MINUTES ,
24+ 'last-year' : ONE_YEAR_IN_MINUTES ,
25+ } ;
26+
927/**
1028 * @description Get all resources (room and devices) available for the MCP service.
1129 * @returns {Promise<Array> } Array of resources with home schema configuration.
@@ -148,6 +166,25 @@ async function getAllTools() {
148166 ) ,
149167 ] ;
150168
169+ const historyDevices = ( await this . gladys . device . get ( ) )
170+ . filter ( ( device ) => {
171+ return device . features . some ( ( feature ) => this . isHistoryFeature ( feature ) ) ;
172+ } )
173+ . map ( ( device ) => ( {
174+ ...device ,
175+ name : device . name ,
176+ features : device . features . filter ( ( feature ) => this . isHistoryFeature ( feature ) ) ,
177+ } ) ) ;
178+ const availableHistoryFeature = [
179+ ...new Set (
180+ historyDevices
181+ . map ( ( device ) => {
182+ return device . features . map ( ( feature ) => `${ feature . category } :${ feature . type } ` ) ;
183+ } )
184+ . flat ( ) ,
185+ ) ,
186+ ] ;
187+
151188 return [
152189 {
153190 intent : 'camera.get-image' ,
@@ -254,10 +291,12 @@ async function getAllTools() {
254291 ) ;
255292
256293 return {
257- content : states . map ( ( state ) => ( {
258- type : 'text' ,
259- text : JSON . stringify ( state ) ,
260- } ) ) ,
294+ content : [
295+ {
296+ type : 'text' ,
297+ text : this . toon ( states ) ,
298+ } ,
299+ ] ,
261300 } ;
262301 } ,
263302 } ,
@@ -341,6 +380,95 @@ async function getAllTools() {
341380 } ;
342381 } ,
343382 } ,
383+ {
384+ intent : 'device.get-history' ,
385+ config : {
386+ title : 'Get device history' ,
387+ description : 'Get history states of specific device.' ,
388+ inputSchema : {
389+ room : z
390+ . enum ( rooms . map ( ( { name } ) => name ) )
391+ . describe ( 'Room to get information from.' )
392+ . optional ( ) ,
393+ device : z
394+ . enum ( [ ...new Set ( historyDevices . map ( ( { name } ) => name ) ) ] )
395+ . describe ( 'Device name to get history.' )
396+ . optional ( ) ,
397+ feature : z
398+ . enum ( availableHistoryFeature )
399+ . describe ( 'Type of device to query.' )
400+ . optional ( ) ,
401+ interval : z
402+ . enum ( Object . keys ( intervalByName ) )
403+ . describe ( 'Time interval to get history from.' )
404+ . optional ( ) ,
405+ } ,
406+ } ,
407+ cb : async ( { room, device, feature, interval } ) => {
408+ let selectedDevices = historyDevices ;
409+
410+ if ( room && room !== '' ) {
411+ const { selector } = this . findBySimilarity ( rooms , room ) ;
412+ selectedDevices = selectedDevices . filter ( ( d ) => ( d . room ?. selector || noRoom . selector ) === selector ) ;
413+ }
414+
415+ if ( feature && feature !== '' ) {
416+ const [ featureCategory , featureType ] = feature . split ( ':' ) ;
417+ selectedDevices = selectedDevices . filter ( ( d ) => {
418+ return d . features . some (
419+ ( f ) => f . category === featureCategory && ( featureType ? f . type === featureType : true ) ,
420+ ) ;
421+ } ) ;
422+ }
423+
424+ if ( device && device !== '' ) {
425+ const deviceFound = this . findBySimilarity ( selectedDevices , device ) ;
426+ if ( deviceFound ?. name ) {
427+ selectedDevices = [ deviceFound ] ;
428+ }
429+ }
430+
431+ if ( selectedDevices . length > 0 ) {
432+ const selectedFeature =
433+ selectedDevices [ 0 ] . features . find ( ( f ) => {
434+ if ( feature && feature !== '' ) {
435+ const [ featureCategory , featureType ] = feature . split ( ':' ) ;
436+
437+ return f . category === featureCategory && ( featureType ? f . type === featureType : true ) ;
438+ }
439+
440+ return false ;
441+ } ) || selectedDevices [ 0 ] . features [ 0 ] ;
442+
443+ const aggStates = await this . gladys . device . getDeviceFeaturesAggregates (
444+ selectedFeature . selector ,
445+ interval ? intervalByName [ interval ] : THIRTY_DAYS_IN_MINUTES ,
446+ 500 ,
447+ ) ;
448+
449+ return {
450+ content : [
451+ {
452+ type : 'text' ,
453+ text : this . toon ( {
454+ room : selectedDevices [ 0 ] . room ?. name || noRoom . name ,
455+ device : selectedDevices [ 0 ] . name ,
456+ feature : selectedFeature . name ,
457+ category : selectedFeature . category ,
458+ type : selectedFeature . type ,
459+ unit : this . formatValue ( selectedFeature ) . unit ,
460+ values : aggStates . values ,
461+ } ) ,
462+ } ,
463+ ] ,
464+ } ;
465+ }
466+
467+ return {
468+ content : [ { type : 'text' , text : `device.get-history, no device or feature found` } ] ,
469+ } ;
470+ } ,
471+ } ,
344472 ] ;
345473}
346474
0 commit comments