isar 1.20.2__py3-none-any.whl → 1.34.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- isar/apis/api.py +135 -86
- isar/apis/models/__init__.py +0 -1
- isar/apis/models/models.py +21 -11
- isar/apis/models/start_mission_definition.py +115 -170
- isar/apis/robot_control/robot_controller.py +41 -0
- isar/apis/schedule/scheduling_controller.py +123 -187
- isar/apis/security/authentication.py +5 -5
- isar/config/certs/ca-cert.pem +33 -31
- isar/config/keyvault/keyvault_service.py +4 -2
- isar/config/log.py +45 -40
- isar/config/logging.conf +16 -31
- isar/config/open_telemetry.py +102 -0
- isar/config/settings.py +74 -117
- isar/eventhandlers/eventhandler.py +123 -0
- isar/models/events.py +184 -0
- isar/models/status.py +22 -0
- isar/modules.py +117 -200
- isar/robot/robot.py +383 -0
- isar/robot/robot_battery.py +60 -0
- isar/robot/robot_monitor_mission.py +357 -0
- isar/robot/robot_pause_mission.py +74 -0
- isar/robot/robot_resume_mission.py +67 -0
- isar/robot/robot_start_mission.py +66 -0
- isar/robot/robot_status.py +61 -0
- isar/robot/robot_stop_mission.py +68 -0
- isar/robot/robot_upload_inspection.py +75 -0
- isar/script.py +58 -41
- isar/services/service_connections/mqtt/mqtt_client.py +47 -11
- isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +5 -2
- isar/services/service_connections/mqtt/robot_info_publisher.py +3 -3
- isar/services/service_connections/persistent_memory.py +69 -0
- isar/services/utilities/mqtt_utilities.py +93 -0
- isar/services/utilities/robot_utilities.py +20 -0
- isar/services/utilities/scheduling_utilities.py +386 -100
- isar/state_machine/state_machine.py +242 -539
- isar/state_machine/states/__init__.py +0 -8
- isar/state_machine/states/await_next_mission.py +114 -0
- isar/state_machine/states/blocked_protective_stop.py +60 -0
- isar/state_machine/states/going_to_lockdown.py +95 -0
- isar/state_machine/states/going_to_recharging.py +92 -0
- isar/state_machine/states/home.py +115 -0
- isar/state_machine/states/intervention_needed.py +77 -0
- isar/state_machine/states/lockdown.py +38 -0
- isar/state_machine/states/maintenance.py +43 -0
- isar/state_machine/states/monitor.py +137 -247
- isar/state_machine/states/offline.py +51 -53
- isar/state_machine/states/paused.py +92 -23
- isar/state_machine/states/pausing.py +48 -0
- isar/state_machine/states/pausing_return_home.py +48 -0
- isar/state_machine/states/recharging.py +80 -0
- isar/state_machine/states/resuming.py +57 -0
- isar/state_machine/states/resuming_return_home.py +64 -0
- isar/state_machine/states/return_home_paused.py +109 -0
- isar/state_machine/states/returning_home.py +217 -0
- isar/state_machine/states/stopping.py +69 -0
- isar/state_machine/states/stopping_due_to_maintenance.py +61 -0
- isar/state_machine/states/stopping_go_to_lockdown.py +60 -0
- isar/state_machine/states/stopping_go_to_recharge.py +51 -0
- isar/state_machine/states/stopping_paused_mission.py +36 -0
- isar/state_machine/states/stopping_paused_return_home.py +59 -0
- isar/state_machine/states/stopping_return_home.py +59 -0
- isar/state_machine/states/unknown_status.py +74 -0
- isar/state_machine/states_enum.py +23 -5
- isar/state_machine/transitions/mission.py +225 -0
- isar/state_machine/transitions/return_home.py +108 -0
- isar/state_machine/transitions/robot_status.py +87 -0
- isar/state_machine/utils/common_event_handlers.py +138 -0
- isar/storage/blob_storage.py +70 -52
- isar/storage/local_storage.py +25 -12
- isar/storage/storage_interface.py +28 -7
- isar/storage/uploader.py +174 -55
- isar/storage/utilities.py +32 -29
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/METADATA +119 -123
- isar-1.34.13.dist-info/RECORD +120 -0
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/WHEEL +1 -1
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/entry_points.txt +1 -0
- robot_interface/models/exceptions/robot_exceptions.py +91 -41
- robot_interface/models/inspection/__init__.py +0 -13
- robot_interface/models/inspection/inspection.py +42 -33
- robot_interface/models/mission/mission.py +14 -15
- robot_interface/models/mission/status.py +20 -26
- robot_interface/models/mission/task.py +154 -121
- robot_interface/models/robots/battery_state.py +6 -0
- robot_interface/models/robots/media.py +13 -0
- robot_interface/models/robots/robot_model.py +7 -7
- robot_interface/robot_interface.py +119 -84
- robot_interface/telemetry/mqtt_client.py +74 -12
- robot_interface/telemetry/payloads.py +91 -13
- robot_interface/utilities/json_service.py +7 -1
- isar/config/configuration_error.py +0 -2
- isar/config/keyvault/keyvault_error.py +0 -2
- isar/config/predefined_mission_definition/__init__.py +0 -0
- isar/config/predefined_mission_definition/default_exr.json +0 -51
- isar/config/predefined_mission_definition/default_mission.json +0 -91
- isar/config/predefined_mission_definition/default_turtlebot.json +0 -124
- isar/config/predefined_missions/__init__.py +0 -0
- isar/config/predefined_missions/default.json +0 -92
- isar/config/predefined_missions/default_turtlebot.json +0 -110
- isar/config/predefined_poses/__init__.py +0 -0
- isar/config/predefined_poses/predefined_poses.py +0 -616
- isar/config/settings.env +0 -25
- isar/mission_planner/__init__.py +0 -0
- isar/mission_planner/local_planner.py +0 -82
- isar/mission_planner/mission_planner_interface.py +0 -26
- isar/mission_planner/sequential_task_selector.py +0 -23
- isar/mission_planner/task_selector_interface.py +0 -31
- isar/models/communication/__init__.py +0 -0
- isar/models/communication/message.py +0 -12
- isar/models/communication/queues/__init__.py +0 -4
- isar/models/communication/queues/queue_io.py +0 -12
- isar/models/communication/queues/queue_timeout_error.py +0 -2
- isar/models/communication/queues/queues.py +0 -19
- isar/models/communication/queues/status_queue.py +0 -20
- isar/models/mission_metadata/__init__.py +0 -0
- isar/services/auth/__init__.py +0 -0
- isar/services/auth/azure_credentials.py +0 -14
- isar/services/readers/__init__.py +0 -0
- isar/services/readers/base_reader.py +0 -37
- isar/services/service_connections/request_handler.py +0 -153
- isar/services/service_connections/stid/__init__.py +0 -0
- isar/services/utilities/queue_utilities.py +0 -39
- isar/services/utilities/threaded_request.py +0 -68
- isar/state_machine/states/idle.py +0 -85
- isar/state_machine/states/initialize.py +0 -71
- isar/state_machine/states/initiate.py +0 -142
- isar/state_machine/states/off.py +0 -18
- isar/state_machine/states/stop.py +0 -95
- isar/storage/slimm_storage.py +0 -191
- isar-1.20.2.dist-info/RECORD +0 -116
- robot_interface/models/initialize/__init__.py +0 -1
- robot_interface/models/initialize/initialize_params.py +0 -9
- robot_interface/models/mission/step.py +0 -234
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info/licenses}/LICENSE +0 -0
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/top_level.txt +0 -0
isar/config/log.py
CHANGED
|
@@ -1,66 +1,71 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import logging.config
|
|
3
|
+
import os
|
|
3
4
|
from importlib.resources import as_file, files
|
|
4
5
|
|
|
5
6
|
import yaml
|
|
6
|
-
from opencensus.ext.azure.log_exporter import AzureLogHandler
|
|
7
7
|
from uvicorn.logging import ColourizedFormatter
|
|
8
8
|
|
|
9
|
-
from isar.config.configuration_error import ConfigurationError
|
|
10
|
-
from isar.config.keyvault.keyvault_error import KeyvaultError
|
|
11
|
-
from isar.config.keyvault.keyvault_service import Keyvault
|
|
12
9
|
from isar.config.settings import settings
|
|
13
10
|
|
|
11
|
+
from .settings import Settings
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
with as_file(source) as f:
|
|
19
|
-
log_config = yaml.safe_load(open(f))
|
|
13
|
+
|
|
14
|
+
def setup_loggers() -> None:
|
|
15
|
+
log_config = load_log_config()
|
|
20
16
|
|
|
21
17
|
logging.config.dictConfig(log_config)
|
|
22
18
|
|
|
19
|
+
env_log_levels = {}
|
|
20
|
+
for env_var, value in os.environ.items():
|
|
21
|
+
if env_var.endswith("_LOG_LEVEL"):
|
|
22
|
+
log_name = env_var.split("_LOG_LEVEL")[0].lower()
|
|
23
|
+
env_log_levels[log_name] = value.upper()
|
|
24
|
+
|
|
23
25
|
handlers = []
|
|
24
26
|
if settings.LOG_HANDLER_LOCAL_ENABLED:
|
|
25
|
-
handlers.append(configure_console_handler(log_config=log_config))
|
|
26
|
-
if settings.LOG_HANDLER_APPLICATION_INSIGHTS_ENABLED:
|
|
27
27
|
handlers.append(
|
|
28
|
-
|
|
28
|
+
configure_console_handler(log_config=log_config, settings=settings)
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
for log_handler in handlers:
|
|
32
|
-
for
|
|
33
|
-
logging.getLogger(
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
for logger_name, logger_config in log_config["loggers"].items():
|
|
33
|
+
logger = logging.getLogger(logger_name)
|
|
34
|
+
logger.addHandler(log_handler)
|
|
35
|
+
if "level" in logger_config:
|
|
36
|
+
logger.setLevel(logger_config["level"])
|
|
37
|
+
if logger_name in env_log_levels:
|
|
38
|
+
logger.setLevel(env_log_levels[logger_name])
|
|
39
|
+
root_logger = logging.getLogger()
|
|
40
|
+
root_logger.addHandler(log_handler)
|
|
41
|
+
if "level" in log_config.get("root", {}):
|
|
42
|
+
root_logger.setLevel(log_config["root"]["level"])
|
|
36
43
|
|
|
37
44
|
|
|
38
|
-
def
|
|
45
|
+
def load_log_config():
|
|
46
|
+
source = files("isar").joinpath("config").joinpath("logging.conf")
|
|
47
|
+
with as_file(source) as f:
|
|
48
|
+
log_config = yaml.safe_load(open(f))
|
|
49
|
+
return log_config
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def configure_console_handler(log_config: dict, settings: Settings) -> logging.Handler:
|
|
39
53
|
handler = logging.StreamHandler()
|
|
40
54
|
handler.setLevel(log_config["root"]["level"])
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
if settings.DEBUG_LOG_FORMATTER:
|
|
56
|
+
handler.setFormatter(
|
|
57
|
+
ColourizedFormatter(
|
|
58
|
+
log_config["formatters"]["debug-formatter"]["format"],
|
|
59
|
+
style="{",
|
|
60
|
+
use_colors=True,
|
|
61
|
+
)
|
|
46
62
|
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
connection_string = keyvault.get_secret(
|
|
55
|
-
"application-insights-connection-string"
|
|
56
|
-
).value
|
|
57
|
-
except KeyvaultError:
|
|
58
|
-
message: str = (
|
|
59
|
-
f"CRITICAL ERROR: Missing connection string for Application Insights in key vault '{keyvault.name}'."
|
|
63
|
+
else:
|
|
64
|
+
handler.setFormatter(
|
|
65
|
+
ColourizedFormatter(
|
|
66
|
+
log_config["formatters"]["colourized"]["format"],
|
|
67
|
+
style="{",
|
|
68
|
+
use_colors=True,
|
|
69
|
+
)
|
|
60
70
|
)
|
|
61
|
-
print(f"\n{message} \n")
|
|
62
|
-
raise ConfigurationError(message)
|
|
63
|
-
|
|
64
|
-
handler = AzureLogHandler(connection_string=connection_string)
|
|
65
|
-
handler.setLevel(log_config["root"]["level"])
|
|
66
71
|
return handler
|
isar/config/logging.conf
CHANGED
|
@@ -5,54 +5,39 @@ formatters:
|
|
|
5
5
|
colourized:
|
|
6
6
|
style: "{"
|
|
7
7
|
format: "{asctime} - {levelprefix:<8} - {name} - {message}"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
formatter: simple
|
|
12
|
-
filename: api.log
|
|
13
|
-
main:
|
|
14
|
-
class: logging.FileHandler
|
|
15
|
-
formatter: simple
|
|
16
|
-
filename: main.log
|
|
17
|
-
mqtt:
|
|
18
|
-
class: logging.FileHandler
|
|
19
|
-
formatter: simple
|
|
20
|
-
filename: mqtt.log
|
|
21
|
-
state_machine:
|
|
22
|
-
class: logging.FileHandler
|
|
23
|
-
formatter: simple
|
|
24
|
-
filename: state_machine.log
|
|
25
|
-
uploader:
|
|
26
|
-
class: logging.FileHandler
|
|
27
|
-
formatter: simple
|
|
28
|
-
filename: uploader.log
|
|
8
|
+
debug-formatter:
|
|
9
|
+
style: "{"
|
|
10
|
+
format: "\x1b[2m{asctime}\x1b[22m - {levelprefix:<8} - \x1b[2m{filename}:{lineno:<4} - {funcName:<15} - {name}\x1b[22m\n{message}"
|
|
29
11
|
loggers:
|
|
30
12
|
console:
|
|
31
13
|
handlers: []
|
|
32
14
|
propagate: no
|
|
33
15
|
main:
|
|
34
|
-
handlers: [
|
|
16
|
+
handlers: []
|
|
35
17
|
propagate: no
|
|
36
18
|
api:
|
|
37
|
-
handlers: [
|
|
19
|
+
handlers: []
|
|
38
20
|
propagate: no
|
|
39
21
|
mqtt:
|
|
40
|
-
handlers: [
|
|
41
|
-
propagate:
|
|
22
|
+
handlers: []
|
|
23
|
+
propagate: no
|
|
42
24
|
state_machine:
|
|
43
|
-
handlers: [
|
|
44
|
-
propagate:
|
|
25
|
+
handlers: []
|
|
26
|
+
propagate: no
|
|
45
27
|
uploader:
|
|
46
|
-
handlers: [
|
|
47
|
-
propagate:
|
|
28
|
+
handlers: []
|
|
29
|
+
propagate: no
|
|
48
30
|
urllib3:
|
|
49
31
|
handlers: []
|
|
32
|
+
level: WARNING
|
|
50
33
|
uvicorn:
|
|
51
|
-
handlers: [
|
|
34
|
+
handlers: []
|
|
52
35
|
propagate: no
|
|
36
|
+
level: WARNING
|
|
53
37
|
azure:
|
|
54
38
|
handlers: []
|
|
55
39
|
propagate: no
|
|
40
|
+
level: WARNING
|
|
56
41
|
root:
|
|
57
|
-
level:
|
|
42
|
+
level: INFO
|
|
58
43
|
handlers: []
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from urllib.parse import urljoin
|
|
3
|
+
|
|
4
|
+
from azure.monitor.opentelemetry.exporter import (
|
|
5
|
+
AzureMonitorLogExporter,
|
|
6
|
+
AzureMonitorTraceExporter,
|
|
7
|
+
)
|
|
8
|
+
from fastapi import FastAPI
|
|
9
|
+
from opentelemetry import trace
|
|
10
|
+
from opentelemetry._logs import set_logger_provider
|
|
11
|
+
from opentelemetry.exporter.otlp.proto.http._log_exporter import (
|
|
12
|
+
OTLPLogExporter as OTLPHttpLogExporter,
|
|
13
|
+
)
|
|
14
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
15
|
+
OTLPSpanExporter as OTLPHttpSpanExporter,
|
|
16
|
+
)
|
|
17
|
+
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
|
18
|
+
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
|
|
19
|
+
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
|
|
20
|
+
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|
21
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
22
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
23
|
+
|
|
24
|
+
from isar.config.log import load_log_config
|
|
25
|
+
from isar.config.settings import settings
|
|
26
|
+
|
|
27
|
+
logging.getLogger("opentelemetry.sdk").setLevel(logging.CRITICAL)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def setup_open_telemetry(app: FastAPI) -> None:
|
|
31
|
+
|
|
32
|
+
service_name = settings.ROBOT_NAME
|
|
33
|
+
resource = Resource.create({SERVICE_NAME: service_name})
|
|
34
|
+
|
|
35
|
+
tracer_provider = TracerProvider(resource=resource)
|
|
36
|
+
log_provider = LoggerProvider(resource=resource)
|
|
37
|
+
|
|
38
|
+
if settings.LOG_HANDLER_APPLICATION_INSIGHTS_ENABLED:
|
|
39
|
+
print("[OTEL] Azure Monitor exporters enabled")
|
|
40
|
+
azure_monitor_trace_exporter, azure_monitor_log_exporter = (
|
|
41
|
+
get_azure_monitor_exporters()
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
tracer_provider.add_span_processor(
|
|
45
|
+
BatchSpanProcessor(azure_monitor_trace_exporter)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
log_provider.add_log_record_processor(
|
|
49
|
+
BatchLogRecordProcessor(azure_monitor_log_exporter)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
otlp_exporter_endpoint = settings.OPEN_TELEMETRY_OTLP_EXPORTER_ENDPOINT
|
|
53
|
+
if otlp_exporter_endpoint:
|
|
54
|
+
print(f"[OTEL] OTLP exporters enabled, endpoint={otlp_exporter_endpoint}")
|
|
55
|
+
otlp_trace_exporter, otlp_log_exporter = get_otlp_exporters(
|
|
56
|
+
otlp_exporter_endpoint
|
|
57
|
+
)
|
|
58
|
+
tracer_provider.add_span_processor(BatchSpanProcessor(otlp_trace_exporter))
|
|
59
|
+
|
|
60
|
+
log_provider.add_log_record_processor(
|
|
61
|
+
BatchLogRecordProcessor(otlp_log_exporter)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
set_logger_provider(log_provider)
|
|
65
|
+
trace.set_tracer_provider(tracer_provider)
|
|
66
|
+
|
|
67
|
+
handler = LoggingHandler(logger_provider=log_provider)
|
|
68
|
+
attach_loggers_for_open_telemetry(handler)
|
|
69
|
+
|
|
70
|
+
FastAPIInstrumentor.instrument_app(app, tracer_provider=tracer_provider)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def attach_loggers_for_open_telemetry(handler: LoggingHandler):
|
|
74
|
+
log_config = load_log_config()
|
|
75
|
+
|
|
76
|
+
for logger_name in log_config["loggers"].keys():
|
|
77
|
+
logger = logging.getLogger(logger_name)
|
|
78
|
+
logger.addHandler(handler)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_azure_monitor_exporters() -> (
|
|
82
|
+
tuple[AzureMonitorTraceExporter, AzureMonitorLogExporter]
|
|
83
|
+
):
|
|
84
|
+
connection_string = settings.APPLICATIONINSIGHTS_CONNECTION_STRING
|
|
85
|
+
trace_exporter = AzureMonitorTraceExporter(connection_string=connection_string)
|
|
86
|
+
log_exporter = AzureMonitorLogExporter(connection_string=connection_string)
|
|
87
|
+
|
|
88
|
+
return trace_exporter, log_exporter
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_otlp_exporters(
|
|
92
|
+
endpoint: str,
|
|
93
|
+
) -> tuple[OTLPHttpSpanExporter, OTLPHttpLogExporter]:
|
|
94
|
+
base = endpoint.rstrip("/") + "/"
|
|
95
|
+
trace_ep = urljoin(base, "v1/traces")
|
|
96
|
+
log_ep = urljoin(base, "v1/logs")
|
|
97
|
+
|
|
98
|
+
print("[OTEL] Using HTTP/Protobuf protocol for OpenTelemetry export")
|
|
99
|
+
print(f"[OTEL] traces → {trace_ep}")
|
|
100
|
+
print(f"[OTEL] logs → {log_ep}")
|
|
101
|
+
|
|
102
|
+
return OTLPHttpSpanExporter(endpoint=trace_ep), OTLPHttpLogExporter(endpoint=log_ep)
|
isar/config/settings.py
CHANGED
|
@@ -1,33 +1,27 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from importlib.resources import as_file, files
|
|
3
|
-
from typing import Any, List
|
|
3
|
+
from typing import Any, List
|
|
4
4
|
|
|
5
5
|
from dotenv import load_dotenv
|
|
6
6
|
from pydantic import Field, ValidationInfo, field_validator
|
|
7
7
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
8
8
|
|
|
9
|
-
from isar.config import predefined_missions
|
|
10
9
|
from robot_interface.models.robots.robot_model import RobotModel
|
|
11
|
-
from robot_interface.telemetry.payloads import
|
|
10
|
+
from robot_interface.telemetry.payloads import DocumentInfo
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class Settings(BaseSettings):
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
env_file = None
|
|
22
|
-
super().__init__(_env_file=env_file)
|
|
14
|
+
# Endpoint open telemetry will export telemetry in the otlp protocol to
|
|
15
|
+
OPEN_TELEMETRY_OTLP_EXPORTER_ENDPOINT: str = Field(default="http://localhost:4318")
|
|
16
|
+
|
|
17
|
+
# Connection string for Azure Application Insights
|
|
18
|
+
# This is optional and it will use managed identity if not set
|
|
19
|
+
APPLICATIONINSIGHTS_CONNECTION_STRING: str = Field(default="")
|
|
23
20
|
|
|
24
21
|
# Determines which robot package ISAR will attempt to import
|
|
25
22
|
# Name must match with an installed python package in the local environment
|
|
26
23
|
ROBOT_PACKAGE: str = Field(default="isar_robot")
|
|
27
24
|
|
|
28
|
-
# The run mode of the robot (stepwise or full mission)
|
|
29
|
-
RUN_MISSION_STEPWISE: bool = Field(default=True)
|
|
30
|
-
|
|
31
25
|
# Determines the local path in which results from missions are stored
|
|
32
26
|
LOCAL_STORAGE_PATH: str = Field(default="./results")
|
|
33
27
|
|
|
@@ -41,27 +35,24 @@ class Settings(BaseSettings):
|
|
|
41
35
|
# The sleep is used to throttle the system on every iteration in the loop
|
|
42
36
|
FSM_SLEEP_TIME: float = Field(default=0.1)
|
|
43
37
|
|
|
44
|
-
# Location of JSON files containing predefined missions for the Local Planner to use
|
|
45
|
-
path: str = os.path.dirname(predefined_missions.__file__)
|
|
46
|
-
PREDEFINED_MISSIONS_FOLDER: str = Field(default=path + "/")
|
|
47
|
-
|
|
48
38
|
# Name of default map transformation
|
|
49
39
|
DEFAULT_MAP: str = Field(default="default_map")
|
|
50
40
|
|
|
51
|
-
# Location of JSON files containing predefined maps
|
|
52
|
-
MAPS_FOLDER: str = Field(default="src/isar/config/maps/")
|
|
53
|
-
|
|
54
41
|
# Determines the number of state transitions that are kept in the log
|
|
55
42
|
STATE_TRANSITIONS_LOG_LENGTH: int = Field(default=20)
|
|
56
43
|
|
|
57
|
-
# Number of attempts to
|
|
58
|
-
INITIATE_FAILURE_COUNTER_LIMIT: int = Field(default=10)
|
|
59
|
-
|
|
60
|
-
# Number of attempts to request a step status in monitor before cancelling
|
|
44
|
+
# Number of attempts to request a task status in monitor before cancelling
|
|
61
45
|
REQUEST_STATUS_FAILURE_COUNTER_LIMIT: int = Field(default=3)
|
|
62
46
|
|
|
47
|
+
# Time allocated to reconnect when failing to retrieve status due to communication
|
|
48
|
+
# issues
|
|
49
|
+
REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY: float = Field(default=10)
|
|
50
|
+
|
|
51
|
+
# Number of attempts for state transitions resume and pause if failed
|
|
52
|
+
STATE_TRANSITION_NUM_RETIRES: int = Field(default=10)
|
|
53
|
+
|
|
63
54
|
# Number of attempts to stop the robot before giving up
|
|
64
|
-
STOP_ROBOT_ATTEMPTS_LIMIT: int = Field(default=
|
|
55
|
+
STOP_ROBOT_ATTEMPTS_LIMIT: int = Field(default=3)
|
|
65
56
|
|
|
66
57
|
# Number of attempts to stop the robot before giving up
|
|
67
58
|
UPLOAD_FAILURE_ATTEMPTS_LIMIT: int = Field(default=10)
|
|
@@ -70,10 +61,20 @@ class Settings(BaseSettings):
|
|
|
70
61
|
UPLOAD_FAILURE_MAX_WAIT: int = Field(default=60)
|
|
71
62
|
|
|
72
63
|
# ISAR telemetry intervals
|
|
73
|
-
ROBOT_STATUS_PUBLISH_INTERVAL: float = Field(default=1)
|
|
74
64
|
ROBOT_HEARTBEAT_PUBLISH_INTERVAL: float = Field(default=1)
|
|
75
65
|
ROBOT_INFO_PUBLISH_INTERVAL: float = Field(default=5)
|
|
66
|
+
ROBOT_API_BATTERY_POLL_INTERVAL: float = Field(default=5)
|
|
76
67
|
ROBOT_API_STATUS_POLL_INTERVAL: float = Field(default=5)
|
|
68
|
+
THREAD_CHECK_INTERVAL: float = Field(default=0.01)
|
|
69
|
+
|
|
70
|
+
# Determines the minimum battery level the robot must have to start a mission
|
|
71
|
+
# If it drops below this level it will recharge to the value set by
|
|
72
|
+
# ROBOT_BATTERY_RECHARGE_THRESHOLD before starting new missions
|
|
73
|
+
ROBOT_MISSION_BATTERY_START_THRESHOLD: float = Field(default=25.0)
|
|
74
|
+
|
|
75
|
+
# Determines the minimum battery threshold to consider the robot recharged
|
|
76
|
+
# and ready for more missions, after having run low on charge
|
|
77
|
+
ROBOT_BATTERY_RECHARGE_THRESHOLD: float = Field(default=80.0)
|
|
77
78
|
|
|
78
79
|
# FastAPI host
|
|
79
80
|
API_HOST_VIEWED_EXTERNALLY: str = Field(default="0.0.0.0")
|
|
@@ -81,12 +82,11 @@ class Settings(BaseSettings):
|
|
|
81
82
|
# FastAPI port
|
|
82
83
|
API_PORT: int = Field(default=3000)
|
|
83
84
|
|
|
84
|
-
# Determines
|
|
85
|
-
|
|
85
|
+
# Determines how long delay time should be allowed before returning home
|
|
86
|
+
RETURN_HOME_DELAY: int = Field(default=10)
|
|
86
87
|
|
|
87
|
-
#
|
|
88
|
-
|
|
89
|
-
TASK_SELECTOR: str = Field(default="sequential")
|
|
88
|
+
# Sets how many times the robot should try to return home if a return home fails
|
|
89
|
+
RETURN_HOME_RETRY_LIMIT: int = Field(default=5)
|
|
90
90
|
|
|
91
91
|
# Determines which storage modules are used by ISAR
|
|
92
92
|
# Multiple storage modules can be chosen
|
|
@@ -94,7 +94,6 @@ class Settings(BaseSettings):
|
|
|
94
94
|
# Selecting a different storage module than local may require certain access rights
|
|
95
95
|
STORAGE_LOCAL_ENABLED: bool = Field(default=True)
|
|
96
96
|
STORAGE_BLOB_ENABLED: bool = Field(default=False)
|
|
97
|
-
STORAGE_SLIMM_ENABLED: bool = Field(default=False)
|
|
98
97
|
|
|
99
98
|
# Determines whether the MQTT publishing module should be enabled or not
|
|
100
99
|
# The publishing module will attempt to connect to the MQTT broker configured in
|
|
@@ -110,7 +109,7 @@ class Settings(BaseSettings):
|
|
|
110
109
|
# Enabling this requires certain resources available for OAuth2 authentication
|
|
111
110
|
# Currently supported authentication is Azure AD
|
|
112
111
|
# (https://github.com/Intility/fastapi-azure-auth)
|
|
113
|
-
AUTHENTICATION_ENABLED: bool = Field(default=
|
|
112
|
+
AUTHENTICATION_ENABLED: bool = Field(default=True)
|
|
114
113
|
|
|
115
114
|
# Tenant ID for the Azure tenant with your Azure Active Directory application
|
|
116
115
|
AZURE_TENANT_ID: str = Field(default="3aa4a235-b6e2-48d5-9195-7fcf05b459b0")
|
|
@@ -140,46 +139,28 @@ class Settings(BaseSettings):
|
|
|
140
139
|
# Keyvault name
|
|
141
140
|
KEYVAULT_NAME: str = Field(default="IsarDevKv")
|
|
142
141
|
|
|
142
|
+
# Determines whether inspections are uploaded asynchronously or get_inspections in robotinterface
|
|
143
|
+
UPLOAD_INSPECTIONS_ASYNC: bool = Field(default=False)
|
|
144
|
+
|
|
143
145
|
# URL to storage account for Azure Blob Storage
|
|
144
|
-
|
|
145
|
-
default="https://eqrobotdevstorage.blob.core.windows.net"
|
|
146
|
-
)
|
|
146
|
+
BLOB_STORAGE_ACCOUNT: str = Field(default="")
|
|
147
147
|
|
|
148
148
|
# Name of blob container in Azure Blob Storage [slimm test]
|
|
149
149
|
BLOB_CONTAINER: str = Field(default="test")
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
SLIMM_CLIENT_ID: str = Field(default="c630ca4d-d8d6-45ab-8cc6-68a363d0de9e")
|
|
153
|
-
|
|
154
|
-
# Scope for access to SLIMM Ingestion API
|
|
155
|
-
SLIMM_APP_SCOPE: str = Field(default=".default")
|
|
156
|
-
|
|
157
|
-
# URL for SLIMM endpoint
|
|
158
|
-
SLIMM_API_URL: str = Field(
|
|
159
|
-
default="https://scinspectioningestapitest.azurewebsites.net/Ingest"
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
# Whether the results should be copied directly into the SLIMM datalake or only the
|
|
163
|
-
# metadata
|
|
164
|
-
COPY_FILES_TO_SLIMM_DATALAKE: bool = Field(default=False)
|
|
151
|
+
PERSISTENT_STORAGE_CONNECTION_STRING: str = Field(default="")
|
|
165
152
|
|
|
166
153
|
# The configuration of this section is tightly coupled with the metadata that is
|
|
167
154
|
# submitted with the results once they have been uploaded.
|
|
168
155
|
|
|
169
156
|
# Four digit code indicating facility
|
|
170
|
-
PLANT_CODE: str = Field(default="
|
|
157
|
+
PLANT_CODE: str = Field(default="1210")
|
|
171
158
|
|
|
172
159
|
# Name of the facility the robot is operating in
|
|
173
|
-
PLANT_NAME: str = Field(default="
|
|
160
|
+
PLANT_NAME: str = Field(default="Huldra")
|
|
174
161
|
|
|
175
162
|
# Shortname of the facility the robot is operating in
|
|
176
|
-
PLANT_SHORT_NAME: str = Field(default="
|
|
177
|
-
|
|
178
|
-
# Country the robot is operating in
|
|
179
|
-
COUNTRY: str = Field(default="Norway")
|
|
180
|
-
|
|
181
|
-
# Type of robot ISAR is monitoring
|
|
182
|
-
ROBOT_TYPE: str = Field(default="robot")
|
|
163
|
+
PLANT_SHORT_NAME: str = Field(default="HUA")
|
|
183
164
|
|
|
184
165
|
# Name of robot
|
|
185
166
|
ROBOT_NAME: str = Field(default="Placebot")
|
|
@@ -190,25 +171,8 @@ class Settings(BaseSettings):
|
|
|
190
171
|
# Serial number of the robot ISAR is connected to
|
|
191
172
|
SERIAL_NUMBER: str = Field(default="0001")
|
|
192
173
|
|
|
193
|
-
#
|
|
194
|
-
|
|
195
|
-
default=[
|
|
196
|
-
VideoStream(
|
|
197
|
-
name="Front camera",
|
|
198
|
-
url="http://localhost:5000/videostream/front",
|
|
199
|
-
type="turtlebot",
|
|
200
|
-
),
|
|
201
|
-
VideoStream(
|
|
202
|
-
name="Rear camera",
|
|
203
|
-
url="http://localhost:5000/videostream/rear",
|
|
204
|
-
type="turtlebot",
|
|
205
|
-
),
|
|
206
|
-
]
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
# Data scheme the robot should adhere to
|
|
210
|
-
# Options [DS0001]
|
|
211
|
-
DATA_SCHEME: str = Field(default="DS0001")
|
|
174
|
+
# Info about robot documentation
|
|
175
|
+
DOCUMENTATION: List[DocumentInfo] = Field(default=[])
|
|
212
176
|
|
|
213
177
|
# Coordinate reference system of facility
|
|
214
178
|
COORDINATE_REFERENCE_SYSTEM: str = Field(default="EQUINOR:4100001")
|
|
@@ -220,9 +184,6 @@ class Settings(BaseSettings):
|
|
|
220
184
|
# Options [quaternion]
|
|
221
185
|
MEDIA_ORIENTATION_REFERENCE_SYSTEM: str = Field(default="quaternion")
|
|
222
186
|
|
|
223
|
-
# Contractor who is responsible for robot missions
|
|
224
|
-
CONTRACTOR: str = Field(default="equinor")
|
|
225
|
-
|
|
226
187
|
# Timezone
|
|
227
188
|
TIMEZONE: str = Field(default="UTC+00:00")
|
|
228
189
|
|
|
@@ -232,15 +193,29 @@ class Settings(BaseSettings):
|
|
|
232
193
|
# List of MQTT Topics
|
|
233
194
|
TOPIC_ISAR_STATUS: str = Field(default="status", validate_default=True)
|
|
234
195
|
TOPIC_ISAR_MISSION: str = Field(default="mission", validate_default=True)
|
|
196
|
+
TOPIC_ISAR_MISSION_ABORTED: str = Field(
|
|
197
|
+
default="aborted_mission", validate_default=True
|
|
198
|
+
)
|
|
235
199
|
TOPIC_ISAR_TASK: str = Field(default="task", validate_default=True)
|
|
236
|
-
TOPIC_ISAR_STEP: str = Field(default="step", validate_default=True)
|
|
237
200
|
TOPIC_ISAR_INSPECTION_RESULT: str = Field(
|
|
238
201
|
default="inspection_result", validate_default=True
|
|
239
202
|
)
|
|
203
|
+
TOPIC_ISAR_INSPECTION_VALUE: str = Field(
|
|
204
|
+
default="inspection_value", validate_default=True
|
|
205
|
+
)
|
|
240
206
|
TOPIC_ISAR_ROBOT_INFO: str = Field(default="robot_info", validate_default=True)
|
|
241
207
|
TOPIC_ISAR_ROBOT_HEARTBEAT: str = Field(
|
|
242
208
|
default="robot_heartbeat", validate_default=True
|
|
243
209
|
)
|
|
210
|
+
TOPIC_ISAR_STARTUP: str = Field(default="startup", validate_default=True)
|
|
211
|
+
TOPIC_ISAR_INTERVENTION_NEEDED: str = Field(
|
|
212
|
+
default="intervention_needed", validate_default=True
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# List of MQTT Topics Expiry
|
|
216
|
+
MQTT_ROBOT_HEARTBEAT_EXPIRY: int = Field(default=5)
|
|
217
|
+
MQTT_TELEMETRY_EXPIRY: int = Field(default=10)
|
|
218
|
+
MQTT_MISSION_AND_TASK_EXPIRY: int = Field(default=86400)
|
|
244
219
|
|
|
245
220
|
# Logging
|
|
246
221
|
|
|
@@ -250,47 +225,29 @@ class Settings(BaseSettings):
|
|
|
250
225
|
# Each handler will be called when logging
|
|
251
226
|
# Selecting a different log handler than local may require certain access rights:
|
|
252
227
|
# - The Azure AI logger requires the 'APPLICATIONINSIGHTS_CONNECTION_STRING' to be set as an environment variable.
|
|
228
|
+
# In general logging is configured in logging.conf
|
|
253
229
|
LOG_HANDLER_LOCAL_ENABLED: bool = Field(default=True)
|
|
254
230
|
LOG_HANDLER_APPLICATION_INSIGHTS_ENABLED: bool = Field(default=False)
|
|
255
231
|
|
|
256
|
-
|
|
257
|
-
API_LOG_LEVEL: str = Field(default="INFO")
|
|
258
|
-
MAIN_LOG_LEVEL: str = Field(default="INFO")
|
|
259
|
-
MQTT_LOG_LEVEL: str = Field(default="INFO")
|
|
260
|
-
STATE_MACHINE_LOG_LEVEL: str = Field(default="INFO")
|
|
261
|
-
UPLOADER_LOG_LEVEL: str = Field(default="INFO")
|
|
262
|
-
CONSOLE_LOG_LEVEL: str = Field(default="INFO")
|
|
263
|
-
URLLIB3_LOG_LEVEL: str = Field(default="WARNING")
|
|
264
|
-
UVICORN_LOG_LEVEL: str = Field(default="WARNING")
|
|
265
|
-
AZURE_LOG_LEVEL: str = Field(default="WARNING")
|
|
232
|
+
DEBUG_LOG_FORMATTER: bool = Field(default=False)
|
|
266
233
|
|
|
267
|
-
|
|
234
|
+
# You can set logger levels from environment variables ending with _LOG_LEVEL
|
|
235
|
+
# For example, MQTT_LOG_LEVEL="DEBUG" will set the logger MQTT_LOGGER to DEBUG level
|
|
236
|
+
# Handeled in log.py and only work for loggers defined in logging.conf
|
|
268
237
|
|
|
269
238
|
REQUIRED_ROLE: str = Field(default="Mission.Control")
|
|
270
239
|
|
|
271
|
-
@field_validator("LOG_LEVELS")
|
|
272
|
-
@classmethod
|
|
273
|
-
def set_log_levels(cls, v: Any, info: ValidationInfo) -> dict:
|
|
274
|
-
return {
|
|
275
|
-
"api": info.data["API_LOG_LEVEL"],
|
|
276
|
-
"main": info.data["MAIN_LOG_LEVEL"],
|
|
277
|
-
"mqtt": info.data["MQTT_LOG_LEVEL"],
|
|
278
|
-
"state_machine": info.data["STATE_MACHINE_LOG_LEVEL"],
|
|
279
|
-
"uploader": info.data["UPLOADER_LOG_LEVEL"],
|
|
280
|
-
"console": info.data["CONSOLE_LOG_LEVEL"],
|
|
281
|
-
"urllib3": info.data["URLLIB3_LOG_LEVEL"],
|
|
282
|
-
"uvicorn": info.data["UVICORN_LOG_LEVEL"],
|
|
283
|
-
"azure": info.data["AZURE_LOG_LEVEL"],
|
|
284
|
-
}
|
|
285
|
-
|
|
286
240
|
@field_validator(
|
|
287
241
|
"TOPIC_ISAR_STATUS",
|
|
288
242
|
"TOPIC_ISAR_MISSION",
|
|
289
243
|
"TOPIC_ISAR_TASK",
|
|
290
|
-
"TOPIC_ISAR_STEP",
|
|
291
244
|
"TOPIC_ISAR_ROBOT_INFO",
|
|
292
245
|
"TOPIC_ISAR_ROBOT_HEARTBEAT",
|
|
293
246
|
"TOPIC_ISAR_INSPECTION_RESULT",
|
|
247
|
+
"TOPIC_ISAR_INSPECTION_VALUE",
|
|
248
|
+
"TOPIC_ISAR_STARTUP",
|
|
249
|
+
"TOPIC_ISAR_INTERVENTION_NEEDED",
|
|
250
|
+
"TOPIC_ISAR_MISSION_ABORTED",
|
|
294
251
|
)
|
|
295
252
|
@classmethod
|
|
296
253
|
def prefix_isar_topics(cls, v: Any, info: ValidationInfo):
|
|
@@ -304,7 +261,12 @@ class Settings(BaseSettings):
|
|
|
304
261
|
)
|
|
305
262
|
|
|
306
263
|
|
|
307
|
-
|
|
264
|
+
env = os.environ.get("ISAR_ENV")
|
|
265
|
+
|
|
266
|
+
if env == "test":
|
|
267
|
+
load_dotenv(".env.test", override=True)
|
|
268
|
+
else:
|
|
269
|
+
load_dotenv()
|
|
308
270
|
settings = Settings()
|
|
309
271
|
|
|
310
272
|
|
|
@@ -324,17 +286,12 @@ class RobotSettings(BaseSettings):
|
|
|
324
286
|
|
|
325
287
|
# ISAR steps the robot is capable of performing
|
|
326
288
|
# This should be set in the robot package settings.env file
|
|
327
|
-
CAPABILITIES: List[str] = Field(default=["
|
|
289
|
+
CAPABILITIES: List[str] = Field(default=["take_image"])
|
|
328
290
|
|
|
329
291
|
# Model of the robot which ISAR is connected to
|
|
330
292
|
# This should be set in the robot package settings.env file
|
|
331
293
|
ROBOT_MODEL: RobotModel = Field(default=RobotModel.Robot) # type: ignore
|
|
332
294
|
|
|
333
|
-
# Valid arm poses that the robot may utilize
|
|
334
|
-
# This should be set in the robot package settings.env file
|
|
335
|
-
# Note that if the robot does not support moving an arm this will be None and
|
|
336
|
-
# the functionality will be unavailable
|
|
337
|
-
VALID_ARM_POSES: Optional[List[str]] = Field(default=None)
|
|
338
295
|
model_config = SettingsConfigDict(
|
|
339
296
|
env_file_encoding="utf-8", case_sensitive=True, extra="ignore"
|
|
340
297
|
)
|