Skip to content

Commit f6ad949

Browse files
dmytroyekblaszczak-intel
authored andcommitted
[ITEP-83027] Controller with Analytics only mode (open-edge-platform#884)
1 parent 2e83c1f commit f6ad949

File tree

14 files changed

+408
-50
lines changed

14 files changed

+408
-50
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ CONTROLLER_METRICS_EXPORT_INTERVAL_S ?= 60
5656
CONTROLLER_ENABLE_TRACING ?= false
5757
CONTROLLER_TRACING_ENDPOINT ?= otel-collector.scenescape.intel.com:4317
5858
CONTROLLER_TRACING_SAMPLE_RATIO ?= 1.0
59+
CONTROLLER_ENABLE_ANALYTICS_ONLY ?= false
5960

6061
# ========================= Default Target ===========================
6162

@@ -576,6 +577,7 @@ $(DLSTREAMER_SAMPLE_VIDEOS): ./dlstreamer-pipeline-server/convert_video_to_ts.sh
576577
@echo "CONTROLLER_ENABLE_TRACING=$(CONTROLLER_ENABLE_TRACING)" >> $@
577578
@echo "CONTROLLER_TRACING_ENDPOINT=$(CONTROLLER_TRACING_ENDPOINT)" >> $@
578579
@echo "CONTROLLER_TRACING_SAMPLE_RATIO=$(CONTROLLER_TRACING_SAMPLE_RATIO)" >> $@
580+
@echo "CONTROLLER_ENABLE_ANALYTICS_ONLY=$(CONTROLLER_ENABLE_ANALYTICS_ONLY)" >> $@
579581
# ======================= Secrets Management =========================
580582

581583
.PHONY: init-secrets

controller/docs/user-guide/How-to-configure-tracker.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
This document guides users and developers on configuring the tracker for specific use cases during Intel® SceneScape deployment.
44

5+
**Note:** Tracker configuration is not needed when running the Scene Controller in analytics-only mode (`--analytics-only` flag or `CONTROLLER_ENABLE_ANALYTICS_ONLY=true`), as tracking is performed by a separate Tracker service.
6+
57
## Tracker Configuration with Time-Based Parameters
68

79
### Enabling Time-Based Parameters

controller/docs/user-guide/get-started.md

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- The hardware platform must be at least a 10th Generation Intel® Core™ i5 Processor or Intel® Xeon® Scalable processor, with at least 8+GB of RAM and 64+GB of storage.
66
- [How to build Scene Controller from source](How-to-build-source.md)
77

8-
## Running the service using Docker Compose
8+
## Running the service using Docker
99

1010
- **Navigate to the Directory**:
1111

@@ -16,7 +16,7 @@
1616
- **Generate secrets**:
1717

1818
```bash
19-
make build-secrets
19+
make init-secrets
2020
```
2121

2222
- **Start the service**:
@@ -63,3 +63,55 @@
6363
- **Access scene controller output through MQTT**:
6464
- Refer to [scene-controller-api.yaml](api-docs/scene-controller-api.yaml) on how to access scene controller output
6565
- Refer to [scene controller sequence diagram](overview.md#sequence-diagram-scene-controller-workflow)
66+
67+
## Running in Analytics-Only Mode
68+
69+
Analytics-only mode allows the Scene Controller to consume tracked objects from a separate Tracker service via MQTT instead of performing tracking internally. This is useful for distributed deployments where tracking and analytics are handled by separate services.
70+
71+
- **Enable analytics-only mode**:
72+
73+
Add the `--analytics-only` flag to the docker run command:
74+
75+
```bash
76+
docker run --rm \
77+
--init \
78+
--network scenescape \
79+
-v scenescape_vol-media:/home/scenescape/SceneScape/media \
80+
-v $(pwd)/controller/config/tracker-config.json:/home/scenescape/SceneScape/tracker-config.json \
81+
-v $(pwd)/manager/secrets/certs/scenescape-ca.pem:/run/secrets/certs/scenescape-ca.pem:ro \
82+
-v $(pwd)/manager/secrets/django:/run/secrets/django:ro \
83+
-v $(pwd)/manager/secrets/controller.auth:/run/secrets/controller.auth:ro \
84+
--name scene \
85+
scenescape-controller \
86+
controller \
87+
--broker broker.scenescape.intel.com \
88+
--ntp ntpserv \
89+
--analytics-only
90+
```
91+
92+
Alternatively, use the environment variable:
93+
94+
```bash
95+
docker run --rm \
96+
--init \
97+
--network scenescape \
98+
-e CONTROLLER_ENABLE_ANALYTICS_ONLY=true \
99+
-v scenescape_vol-media:/home/scenescape/SceneScape/media \
100+
-v $(pwd)/controller/config/tracker-config.json:/home/scenescape/SceneScape/tracker-config.json \
101+
-v $(pwd)/manager/secrets/certs/scenescape-ca.pem:/run/secrets/certs/scenescape-ca.pem:ro \
102+
-v $(pwd)/manager/secrets/django:/run/secrets/django:ro \
103+
-v $(pwd)/manager/secrets/controller.auth:/run/secrets/controller.auth:ro \
104+
--name scene \
105+
scenescape-controller \
106+
controller \
107+
--broker broker.scenescape.intel.com \
108+
--ntp ntpserv
109+
```
110+
111+
- **Note**: In analytics-only mode (experimental feature):
112+
- The tracker is not initialized
113+
- Camera and scene detection data processing is skipped
114+
- The controller subscribes to tracked object data from MQTT topics published by the Tracker service
115+
- Analytics processing (regions, tripwires, sensors) continues to function normally
116+
- Child scenes are not supported in analytics-only mode
117+
- Sensors in Scene not supported and attribute persistence across moving objects not supported on data/scene MQTT topic (data avaliable on events topic).

controller/docs/user-guide/overview.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ To deploy the scene controller service, refer to the [Get started](get-started.m
3434

3535
`--visibility_topic`: Specifies the topic for publishing visibility information, which includes the visibility of objects in cameras. Options are `unregulated`, `regulated`, or `none`.
3636

37+
`--analytics-only`: Enables analytics-only mode (experimental feature). In this mode, the Scene Controller consumes tracked objects from a separate Tracker service via MQTT instead of performing tracking internally. The tracker is not initialized, and camera/scene data processing is skipped. Child scenes are not supported. This mode can also be enabled via the `CONTROLLER_ENABLE_ANALYTICS_ONLY` environment variable set to `true`.
38+
3739
### Tracker Configuration
3840

3941
For details on how to configure the tracker, see [How to configure tracker](./How-to-configure-tracker.md).

controller/src/controller-cmd

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#!/usr/bin/env python3
22

3-
# SPDX-FileCopyrightText: (C) 2024 - 2025 Intel Corporation
3+
# SPDX-FileCopyrightText: (C) 2024 - 2026 Intel Corporation
44
# SPDX-License-Identifier: Apache-2.0
55

66
import argparse
77
import os
88

99
from controller.scene_controller import SceneController
10+
from controller.controller_mode import ControllerMode
1011
from controller.observability import metrics, tracing
1112

1213
def build_argparser():
@@ -43,10 +44,16 @@ def build_argparser():
4344
parser.add_argument("--visibility_topic", help="Which topic to publish visibility on."
4445
"Valid options are 'unregulated', 'regulated', or 'none'",
4546
default="regulated")
47+
parser.add_argument("--analytics-only", action="store_true",
48+
default=os.getenv("CONTROLLER_ENABLE_ANALYTICS_ONLY") == "true",
49+
help="Enable analytics-only mode. Use this when running a separate Tracker service that publishes tracking data to MQTT.")
4650
return parser
4751

4852
def main():
4953
args = build_argparser().parse_args()
54+
55+
ControllerMode.initialize(analytics_only=args.analytics_only)
56+
5057
metrics.init()
5158
tracing.init()
5259
controller = SceneController(args.rewriteBadTime, args.rewriteAllTime,
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# SPDX-FileCopyrightText: (C) 2026 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from scene_common import log
5+
6+
class ControllerMode:
7+
"""
8+
Static namespace for managing controller's mode.
9+
10+
Usage:
11+
# Initialize once at startup
12+
ControllerMode.initialize(analytics_only=True)
13+
14+
# Access anywhere in the codebase
15+
if ControllerMode.isAnalyticsOnly():
16+
# analytics-only mode
17+
else:
18+
# default mode
19+
"""
20+
21+
_initialized = False
22+
_analytics_only = False
23+
24+
@classmethod
25+
def initialize(cls, analytics_only=False):
26+
"""
27+
Initialize the controller mode. Should be called once at startup.
28+
29+
Args:
30+
analytics_only: If True, controller runs in analytics-only mode
31+
(no tracking, consumes already-tracked objects)
32+
"""
33+
if cls._initialized:
34+
log.warning("ControllerMode already initialized. Ignoring re-initialization.")
35+
return
36+
37+
cls._analytics_only = analytics_only
38+
cls._initialized = True
39+
40+
if analytics_only:
41+
log.info("Controller mode: ANALYTICS-ONLY (tracker disabled)")
42+
else:
43+
log.info("Controller mode: DEFAULT (tracker enabled)")
44+
45+
@classmethod
46+
def isAnalyticsOnly(cls):
47+
"""
48+
Check if controller is running in analytics-only mode.
49+
50+
Returns:
51+
bool: True if analytics-only mode is enabled, False otherwise
52+
"""
53+
if not cls._initialized:
54+
log.warning("ControllerMode not initialized. Defaulting to default mode.")
55+
return False
56+
return cls._analytics_only
57+
58+
@classmethod
59+
def isInitialized(cls):
60+
"""
61+
Check if the controller mode has been initialized.
62+
63+
Returns:
64+
bool: True if initialized, False otherwise
65+
"""
66+
return cls._initialized
67+
68+
@classmethod
69+
def reset(cls):
70+
"""
71+
Reset the singleton state.
72+
"""
73+
cls._initialized = False
74+
cls._analytics_only = False

controller/src/controller/detections_builder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: (C) 2024 - 2025 Intel Corporation
1+
# SPDX-FileCopyrightText: (C) 2024 - 2026 Intel Corporation
22
# SPDX-License-Identifier: Apache-2.0
33

44
import numpy as np
@@ -91,7 +91,7 @@ def computeCameraBounds(scene, aobj, obj_dict):
9191
camera_bounds = {}
9292
for cameraID in obj_dict['visibility']:
9393
bounds = None
94-
if aobj and hasattr(aobj.vectors[0].camera, 'cameraID') \
94+
if aobj and len(aobj.vectors) > 0 and hasattr(aobj.vectors[0].camera, 'cameraID') \
9595
and cameraID == aobj.vectors[0].camera.cameraID:
9696
bounds = getattr(aobj, 'boundingBoxPixels', None)
9797
elif scene:

0 commit comments

Comments
 (0)