1010from homeassistant .core import SupportsResponse
1111from homeassistant .exceptions import ServiceValidationError
1212import homeassistant .helpers .config_validation as cv
13+ from homeassistant .helpers .dispatcher import async_dispatcher_send
1314from .api import TimelineEventView , TimelineEventsView , TimelineEventCreateView
1415
1516import logging
7475 STRUCTURE ,
7576 TITLE_FIELD ,
7677 DESCRIPTION_FIELD ,
78+ SIGNAL_TIMELINE_UPDATED ,
79+ CONF_THINKING_BUDGET ,
80+ CONF_THINK ,
81+ CONF_REASONING_EFFORT ,
7782)
7883
7984CONFIG_SCHEMA = cv .config_entry_only_config_schema (DOMAIN )
@@ -116,6 +121,10 @@ async def async_setup_entry(hass, entry):
116121 CONF_MEMORY_STRINGS : entry .data .get (CONF_MEMORY_STRINGS ),
117122 CONF_SYSTEM_PROMPT : entry .data .get (CONF_SYSTEM_PROMPT ),
118123 CONF_TITLE_PROMPT : entry .data .get (CONF_TITLE_PROMPT ),
124+ # Thinking/reasoning parameters
125+ CONF_THINKING_BUDGET : entry .data .get (CONF_THINKING_BUDGET ),
126+ CONF_THINK : entry .data .get (CONF_THINK ),
127+ CONF_REASONING_EFFORT : entry .data .get (CONF_REASONING_EFFORT ),
119128 }
120129
121130 # Filter out None values
@@ -460,34 +469,47 @@ def __init__(self, data_call):
460469 if data_call .data .get (EVENT_ID )
461470 else None
462471 )
463- self .interval = int (data_call .data .get (INTERVAL , 2 ))
464- self .duration = int (data_call .data .get (DURATION , 10 ))
465- self .max_frames = int (data_call .data .get (MAX_FRAMES , 3 ))
466- self .target_width = data_call .data .get (TARGET_WIDTH , 3840 )
467- self .temperature = float ()
468- self .max_tokens = int (data_call .data .get (MAXTOKENS , 3000 ))
469- self .include_filename = data_call .data .get (INCLUDE_FILENAME , False )
470- self .expose_images = data_call .data .get (EXPOSE_IMAGES , False )
471- self .generate_title = data_call .data .get (GENERATE_TITLE , False )
472- self .sensor_entity = data_call .data .get (SENSOR_ENTITY , "" )
473- self .response_format = data_call .data .get (RESPONSE_FORMAT , "text" )
474- self .structure = data_call .data .get (STRUCTURE , None )
475- self .title_field = data_call .data .get (TITLE_FIELD , "" )
476- self .description_field = data_call .data .get (DESCRIPTION_FIELD , "" )
472+ self .interval : int = int (data_call .data .get (INTERVAL , 2 ))
473+ self .duration : int = int (data_call .data .get (DURATION , 10 ))
474+ self .max_frames : int = int (data_call .data .get (MAX_FRAMES , 3 ))
475+ self .target_width : int = data_call .data .get (TARGET_WIDTH , 3840 )
476+ self .temperature : float = float ()
477+ self .max_tokens : int = int (data_call .data .get (MAXTOKENS , 3000 ))
478+ self .include_filename : bool = data_call .data .get (INCLUDE_FILENAME , False )
479+ self .expose_images : bool = data_call .data .get (EXPOSE_IMAGES , False )
480+ self .generate_title : bool = data_call .data .get (GENERATE_TITLE , False )
481+ self .sensor_entity : str = data_call .data .get (SENSOR_ENTITY , "" )
482+ self .response_format : str = data_call .data .get (RESPONSE_FORMAT , "text" )
483+ self .structure : dict | None = data_call .data .get (STRUCTURE , None )
484+ self .title_field : str = data_call .data .get (TITLE_FIELD , "" )
485+ self .description_field : str = data_call .data .get (DESCRIPTION_FIELD , "" )
477486 self .memory : Memory | None = None
478487
479488 # ------------ Create Event ------------
480- self .title = data_call .data .get ("title" )
481- self .description = data_call .data .get ("description" )
482- self .start_time = data_call .data .get ("start_time" , dt_util .now ())
489+ self .title : str = data_call .data .get ("title" )
490+ self .description : str = data_call .data .get ("description" )
491+ self .start_time : datetime = data_call .data .get ("start_time" , dt_util .now ())
483492 self .start_time = self ._convert_time_input_to_datetime (self .start_time )
484- self .end_time = data_call .data .get (
493+ self .end_time : datetime = data_call .data .get (
485494 "end_time" , self .start_time + timedelta (minutes = 1 )
486495 )
487496 self .end_time = self ._convert_time_input_to_datetime (self .end_time )
488- self .image_path = data_call .data .get ("image_path" , "" )
489- self .camera_entity = data_call .data .get ("camera_entity" , "" )
490- self .label = data_call .data .get ("label" , "" )
497+ self .image_path : str = data_call .data .get ("image_path" , "" )
498+ self .camera_entity : str = data_call .data .get ("camera_entity" , "" )
499+ self .label : str = data_call .data .get ("label" , "" )
500+
501+ # ------------- Get Events --------------
502+ self .start : datetime = data_call .data .get (
503+ "start" , dt_util .now () - timedelta (days = 7 )
504+ )
505+ self .start = self ._convert_time_input_to_datetime (self .start )
506+ self .end : datetime = data_call .data .get ("end" , dt_util .now ())
507+ self .end = self ._convert_time_input_to_datetime (self .end )
508+ self .cameras : list = data_call .data .get ("cameras" , "" )
509+ self .categories : list = data_call .data .get ("categories" , "" )
510+ self .labels : list = data_call .data .get ("labels" , "" )
511+ self .limit : int = int (data_call .data .get ("limit" , 100 ))
512+ self .include_no_activity : bool = data_call .data .get ("include_no_activity" , True )
491513
492514 # ------------ Added during call ------------
493515 # self.base64_images : List[str] = []
@@ -521,6 +543,10 @@ def get(self, key, default=None):
521543 def get_service_call_data (self ):
522544 return self
523545
546+ def model_is_glimpse (self ) -> bool :
547+ """Check if model is Glimpse-v1 like based on model name"""
548+ return bool (self .model and "glimpse-v1" in self .model .lower ())
549+
524550
525551async def _create_event (
526552 hass ,
@@ -579,6 +605,7 @@ async def _create_event(
579605 camera_name = camera_name ,
580606 label = "" ,
581607 )
608+ async_dispatcher_send (hass , SIGNAL_TIMELINE_UPDATED )
582609
583610
584611async def _update_sensor (hass , sensor_entity : str , value : str | int , type : str ) -> None :
@@ -850,7 +877,7 @@ async def data_analyzer(data_call):
850877 await _update_sensor (hass , sensor_entity , response ["response_text" ], type )
851878 return response
852879
853- async def create_event (data_call ):
880+ async def create_event (data_call ) -> None :
854881 """Handle the service call to create an event"""
855882 start = dt_util .now ()
856883 call = ServiceCallData (data_call ).get_service_call_data ()
@@ -868,7 +895,7 @@ async def create_event(data_call):
868895 f"Config entry not found. Please create the 'Settings' config entry first."
869896 )
870897
871- timeline = Timeline (hass , config_entry )
898+ timeline : Timeline = Timeline (hass , config_entry )
872899
873900 await timeline .create_event (
874901 start = call .start_time ,
@@ -879,6 +906,34 @@ async def create_event(data_call):
879906 camera_name = call .camera_entity ,
880907 label = call .label .lower (),
881908 )
909+ async_dispatcher_send (hass , SIGNAL_TIMELINE_UPDATED )
910+
911+ async def get_events (data_call ) -> dict | None :
912+ """Handle the service call to get events"""
913+ # Find timeline config
914+ config_entry = None
915+ for entry in hass .config_entries .async_entries (DOMAIN ):
916+ # Check if the config entry is empty
917+ if entry .data [CONF_PROVIDER ] == "Settings" :
918+ config_entry = entry
919+ break
920+
921+ if config_entry is None :
922+ raise ServiceValidationError (
923+ f"Config entry not found. Please create the 'Settings' config entry first."
924+ )
925+
926+ timeline : Timeline = Timeline (hass , config_entry )
927+ events : list [dict ] | None = await timeline .get_events_json (
928+ start = data_call .data .get ("start" ),
929+ end = data_call .data .get ("end" ),
930+ cameras = [camera .lower () for camera in data_call .data .get ("cameras" , [])],
931+ categories = [category .lower () for category in data_call .data .get ("categories" , [])],
932+ labels = [label .lower () for label in data_call .data .get ("labels" , [])],
933+ limit = data_call .data .get ("limit" ),
934+ include_no_activity = data_call .data .get ("include_no_activity" , True ),
935+ )
936+ return {"events" : events or []}
882937
883938 # Register actions
884939 hass .services .register (
@@ -907,6 +962,12 @@ async def create_event(data_call):
907962 "create_event" ,
908963 create_event ,
909964 )
965+ hass .services .register (
966+ DOMAIN ,
967+ "get_events" ,
968+ get_events ,
969+ supports_response = SupportsResponse .ONLY ,
970+ )
910971 hass .http .register_view (TimelineEventsView )
911972 hass .http .register_view (TimelineEventView )
912973 hass .http .register_view (TimelineEventCreateView )
0 commit comments