[issue/1002] Fix and enhance singleton sensor tagging with cache persistence#1029
[issue/1002] Fix and enhance singleton sensor tagging with cache persistence#1029saratpoluri merged 49 commits intomainfrom
Conversation
- Environmental sensors: ambient readings with exposure tracking - Attribute sensors: persistent object-specific events - Fixed singleton_type database-to-runtime connection - Fixed scene-wide and circle region geometry - Fixed region cleanup outside debounce - Value-change optimization for memory efficiency
This commit addresses multiple issues discovered during testing of the singleton sensor implementation on Feb 17, 2026: Event Publishing Fixes: - Fix KeyError crash in _buildEnteredObjsList when sensor objects not in detections_dict (occurs during sensor MQTT value events) - Fix empty entered/exited arrays by clearing stale events after publishing while preserving sensor 'value' events - Remove redundant sensor "value" event publishing (sensor data already included in object entry/exit events via sensors field) Exposure Calculation Fixes: - Set scene.when timestamp in all message handlers (handleSensorMessage, handleMovingObjectMessage, handleSceneDataMessage) to enable exposure calculation in detections_builder - Use epoch time directly instead of string conversion when initializing sensor state to avoid precision loss in exposure calculations - Exposure now correctly calculates as: value × (exit_time - entry_time) Sensor Cache Resilience: - Preserve sensor cache (value, lastValue, lastWhen) during region geometry updates in scene._updateRegions() - Preserve sensor cache across scene invalidation/recreation in cache_manager by storing old cache during invalidate() and restoring sensor values when scene is deserialized - Preserve region state (entered, exited, objects, when) during updates Testing verified: - Objects entering/exiting sensor regions receive correct sensor data - Exposure accumulation is precise (matches manual calculation) - Sensor cache persists through all geometry changes (circle ↔ polygon) - No crashes during sensor MQTT message handling - Event data includes correct entered/exited object lists Files modified: - controller/src/controller/scene.py - controller/src/controller/scene_controller.py - controller/src/controller/cache_manager.py
There was a problem hiding this comment.
Pull request overview
This PR restores and enhances singleton sensor tagging for tracked objects in the SceneScape controller. It addresses issue #1002 where sensors were not properly tagging objects with data. The implementation adds support for two sensor types: environmental sensors (scene-wide ambient conditions like temperature, with cumulative exposure tracking via trapezoid integration) and attribute sensors (event-based data like card readers, with persistent event history).
Changes:
- Restored database-to-runtime linkage for singleton_type field enabling sensor type classification
- Implemented cross-detection-type tagging so sensors work with all object types (person, vehicle, etc.)
- Added sensor cache persistence across geometry changes and scene reloads
- Fixed circular region geometry handling and scene-wide sensor support
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| scene_common/src/scene_common/geometry.py | Fixes circle region handling by checking explicit area type before inferring from hasPointsArray |
| manager/src/django/models.py | Passes singleton_type from database to runtime Region objects |
| controller/src/controller/scene_controller.py | Adds include_sensors parameter to control sensor data publishing on different topics (full-rate vs regulated/external) |
| controller/src/controller/scene.py | Core sensor processing logic with exposure calculation, cross-detection-type support, and sensor state initialization |
| controller/src/controller/moving_object.py | Refactors ChainData to use separate dicts for environmental and attribute sensors instead of flat sensors dict |
| controller/src/controller/detections_builder.py | Builds structured sensor output with values and exposure for environmental sensors, values only for attribute sensors |
| controller/src/controller/cache_manager.py | Preserves sensor cache values (value, lastValue, lastWhen) across scene refreshes |
Convert cur_value to float once at the beginning to ensure consistent type comparison when checking if sensor values have changed. This prevents false positives/negatives in value comparison that could occur when mixing string and numeric types in the readings array.
Address code quality and robustness concerns identified in PR review: - Type consistency: Convert sensor values to appropriate types (float for environmental, string for attribute) once and use consistently throughout - Negative exposure prevention: Add dt > 0 checks in all exposure calculations to guard against out-of-order messages or clock skew - Analytics-only mode: Add tracker null check to prevent crashes when tracker is not initialized - Circle region validation: Improve error messages to distinguish missing vs invalid center values - Docstring accuracy: Update _clearSensorValuesOnExit to reflect actual behavior - Cache restoration: Use sentinel value to properly handle None as valid cached value vs attribute not existing - Performance optimization: Skip redundant isPointWithin checks for scene-wide sensors, remove unused objects_by_type tracking - Scene.when initialization: Add explicit None initialization in __init__ - Observability: Add debug logging for sensor cache restoration - TODO comments: Document unbounded cache growth and performance optimization opportunities for future work
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
a9e45bb to
d012fd1
Compare
- Remove all exposure tracking and calculation code - Environmental sensors now only store timestamped readings - Simplify sensor state structure (remove exposure fields) - Remove unused scene.when attribute - Update comments to reflect simplified sensor data model - Sensor output now contains only 'values' array without 'exposure' field
- Creates tc_singleton_sensor_tagging.py with 5 test scenarios: 1. Environmental sensor entry with cached reading 2. Environmental sensor exit with reading removal 3. Environmental sensor re-entry with cache 4. Attribute sensor entry/exit with persistence 5. Attribute sensor re-entry without cache (event-based only) - Adds make target 'singleton-sensor-tagging' to Makefile.functional - Test validates simplified sensor model (timestamped readings only) - Auto-cleanup of existing sensors before test and after completion
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: scenescapecicd <sys_scenescape_ci@intel.com> Co-authored-by: Dmytro Yermolenko <dmytro.yermolenko@intel.com>
9227ba4 to
e746441
Compare
eea8bda to
4419915
Compare
4419915 to
623725a
Compare
| # Copy sensor data while holding lock, then release | ||
| with chain_data._lock: | ||
| env_state_copy = dict(chain_data.env_sensor_state) | ||
| attr_events_copy = dict(chain_data.attr_sensor_events) | ||
|
|
||
| # Environmental sensors: timestamped readings | ||
| for sensor_id, state in env_state_copy.items(): | ||
| values = state['readings'] if 'readings' in state and state['readings'] else [] | ||
|
|
There was a problem hiding this comment.
prepareObjDict() releases chain_data._lock after a shallow dict(...) copy of env_sensor_state / attr_sensor_events, but the copied dict values still reference the same underlying readings / events lists. Another thread can mutate those lists while serialization is iterating them (via orjson), leading to inconsistent output or hard-to-reproduce runtime errors. Copy the nested lists (and/or state dicts) while holding the lock (e.g., clone state['readings'] and events), or keep the lock held until the sensor payload is fully assembled.
📝 Description
This PR restores and enhances singleton sensor tagging for tracked objects, addressing multiple issues that broke the feature. Enables two types of sensors:
Environmental Sensors: Scene-wide sensors (temperature, noise, air quality) that track timestamped readings. Objects maintain a history of sensor values with timestamps while in the sensor region.
Attribute Sensors: Event-based sensors (card readers, barcode, weight, license plate) that tag objects with timestamped attribute values when MQTT messages arrive.
Key Features
[["2026-02-18T22:06:47.652Z", 20.5]])Major Fixes
Additional Bug Fixes
_buildEnteredObjsListwhen sensor objects not in detections_dictArchitecture Simplification
[(timestamp, value), ...]arraysscene.whenattribute and related tracking codevaluesarray without complexity of exposure trackingKnown Limitations
env_sensor_state[sensor_id]['readings']andattr_sensor_events[sensor_id]). For long-running objects that remain in sensor regions with frequent updates, these lists can grow indefinitely. For example, an object in a sensor for 24 hours with readings every second would accumulate 86,400 entries. The timestamp update optimization helps when values don't change, but frequent value changes can still cause memory exhaustion. Future work should implement bounded cache with FIFO eviction, time-based cleanup, or periodic consolidation. TODO comments added in code.Fixes #1002
✨ Type of Change
🧪 Testing Scenarios
✅ Checklist