mtchart-sdk 0.1.0__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.
- mtchart_sdk/__init__.py +31 -0
- mtchart_sdk/cli.py +87 -0
- mtchart_sdk/models.py +63 -0
- mtchart_sdk/rules.py +101 -0
- mtchart_sdk/service.py +51 -0
- mtchart_sdk/storage.py +98 -0
- mtchart_sdk-0.1.0.dist-info/METADATA +123 -0
- mtchart_sdk-0.1.0.dist-info/RECORD +12 -0
- mtchart_sdk-0.1.0.dist-info/WHEEL +5 -0
- mtchart_sdk-0.1.0.dist-info/entry_points.txt +2 -0
- mtchart_sdk-0.1.0.dist-info/licenses/LICENSE.md +15 -0
- mtchart_sdk-0.1.0.dist-info/top_level.txt +1 -0
mtchart_sdk/__init__.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from mtchart_sdk.models import (
|
|
2
|
+
PartItem,
|
|
3
|
+
PenConfig,
|
|
4
|
+
ProcessInput,
|
|
5
|
+
ProcessRecord,
|
|
6
|
+
ReadingEvaluation,
|
|
7
|
+
)
|
|
8
|
+
from mtchart_sdk.rules import (
|
|
9
|
+
calculate_exit_timing,
|
|
10
|
+
clean_identifier,
|
|
11
|
+
evaluate_temperature,
|
|
12
|
+
normalize_item,
|
|
13
|
+
total_quantity,
|
|
14
|
+
)
|
|
15
|
+
from mtchart_sdk.service import MTChartService
|
|
16
|
+
from mtchart_sdk.storage import PartsCatalog
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"MTChartService",
|
|
20
|
+
"PartItem",
|
|
21
|
+
"PartsCatalog",
|
|
22
|
+
"PenConfig",
|
|
23
|
+
"ProcessInput",
|
|
24
|
+
"ProcessRecord",
|
|
25
|
+
"ReadingEvaluation",
|
|
26
|
+
"calculate_exit_timing",
|
|
27
|
+
"clean_identifier",
|
|
28
|
+
"evaluate_temperature",
|
|
29
|
+
"normalize_item",
|
|
30
|
+
"total_quantity",
|
|
31
|
+
]
|
mtchart_sdk/cli.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from mtchart_sdk.models import PartItem, PenConfig, ProcessInput
|
|
9
|
+
from mtchart_sdk.service import MTChartService
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="mtchart-sdk-demo",
|
|
15
|
+
description="Executa uma demonstracao local do MTChart SDK.",
|
|
16
|
+
)
|
|
17
|
+
parser.add_argument("--catalog-db", default="mtchart_sdk_demo.db", help="Caminho do catalogo SQLite.")
|
|
18
|
+
parser.add_argument("--report-number", default="CH-DEMO-001", help="Numero do relatorio.")
|
|
19
|
+
parser.add_argument("--project", default="OS-DEMO", help="Projeto ou ordem de servico.")
|
|
20
|
+
parser.add_argument("--process-name", default="Alivio de fragilizacao", help="Nome do processo.")
|
|
21
|
+
parser.add_argument("--oven", default="Forno Demo", help="Nome do forno.")
|
|
22
|
+
parser.add_argument("--relief-hours", type=float, default=3.0, help="Horas de permanencia do processo.")
|
|
23
|
+
parser.add_argument("--pen-id", default="1", help="Identificador da pena.")
|
|
24
|
+
parser.add_argument("--target", type=float, default=189.0, help="Temperatura alvo para iniciar processo.")
|
|
25
|
+
parser.add_argument("--low-limit", type=float, default=175.9, help="Limite inferior de temperatura.")
|
|
26
|
+
parser.add_argument("--high-limit", type=float, default=220.0, help="Limite superior de temperatura.")
|
|
27
|
+
parser.add_argument("--value", default="188.7", help="Leitura de temperatura a avaliar.")
|
|
28
|
+
parser.add_argument("--part-name", default="Suporte Demo", help="Nome da peca.")
|
|
29
|
+
parser.add_argument("--pn", default="PN-DEMO-001", help="Part number da peca.")
|
|
30
|
+
parser.add_argument("--sn", default="SN-DEMO-001", help="Serial number da peca.")
|
|
31
|
+
parser.add_argument("--qty", type=int, default=1, help="Quantidade da peca.")
|
|
32
|
+
return parser
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def run_demo(args: argparse.Namespace) -> dict[str, object]:
|
|
36
|
+
service = MTChartService(catalog_db=Path(args.catalog_db))
|
|
37
|
+
started_at = datetime.now().replace(microsecond=0)
|
|
38
|
+
process = service.create_process(
|
|
39
|
+
ProcessInput(
|
|
40
|
+
report_number=args.report_number,
|
|
41
|
+
project=args.project,
|
|
42
|
+
process_name=args.process_name,
|
|
43
|
+
oven=args.oven,
|
|
44
|
+
relief_hours=args.relief_hours,
|
|
45
|
+
pen=PenConfig(
|
|
46
|
+
id=args.pen_id,
|
|
47
|
+
name=f"Pena {args.pen_id}",
|
|
48
|
+
stabilization_target=args.target,
|
|
49
|
+
low_limit=args.low_limit,
|
|
50
|
+
high_limit=args.high_limit,
|
|
51
|
+
),
|
|
52
|
+
items=[
|
|
53
|
+
PartItem(
|
|
54
|
+
name=args.part_name,
|
|
55
|
+
pn=args.pn,
|
|
56
|
+
sn=args.sn,
|
|
57
|
+
qty=args.qty,
|
|
58
|
+
)
|
|
59
|
+
],
|
|
60
|
+
started_at=started_at,
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
reading = service.evaluate_reading(process, args.value, now=started_at)
|
|
64
|
+
return {
|
|
65
|
+
"report_number": process.report_number,
|
|
66
|
+
"project": process.project,
|
|
67
|
+
"expected_exit_at": process.expected_exit_at.isoformat(),
|
|
68
|
+
"total_quantity": process.total_quantity,
|
|
69
|
+
"reading": {
|
|
70
|
+
"value": reading.value,
|
|
71
|
+
"status": reading.status,
|
|
72
|
+
"can_start_process": reading.can_start_process,
|
|
73
|
+
"remaining_seconds": reading.remaining_seconds,
|
|
74
|
+
},
|
|
75
|
+
"catalog_matches": service.search_parts(args.pn, limit=5),
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def main(argv: list[str] | None = None) -> int:
|
|
80
|
+
parser = _build_parser()
|
|
81
|
+
result = run_demo(parser.parse_args(argv))
|
|
82
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
83
|
+
return 0
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
raise SystemExit(main())
|
mtchart_sdk/models.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class PartItem:
|
|
10
|
+
name: str = ""
|
|
11
|
+
pn: str = ""
|
|
12
|
+
sn: str = ""
|
|
13
|
+
qty: int = 1
|
|
14
|
+
project: str = ""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class PenConfig:
|
|
19
|
+
id: str
|
|
20
|
+
name: str = ""
|
|
21
|
+
stabilization_target: float | None = None
|
|
22
|
+
low_limit: float | None = None
|
|
23
|
+
high_limit: float | None = None
|
|
24
|
+
tolerance: float = 0.5
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class ProcessInput:
|
|
29
|
+
report_number: str
|
|
30
|
+
project: str
|
|
31
|
+
process_name: str
|
|
32
|
+
oven: str
|
|
33
|
+
relief_hours: float
|
|
34
|
+
pen: PenConfig
|
|
35
|
+
items: list[PartItem | dict[str, Any]] = field(default_factory=list)
|
|
36
|
+
started_at: datetime | None = None
|
|
37
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class ProcessRecord:
|
|
42
|
+
report_number: str
|
|
43
|
+
project: str
|
|
44
|
+
process_name: str
|
|
45
|
+
oven: str
|
|
46
|
+
relief_hours: float
|
|
47
|
+
pen: PenConfig
|
|
48
|
+
items: list[PartItem]
|
|
49
|
+
started_at: datetime
|
|
50
|
+
expected_exit_at: datetime
|
|
51
|
+
total_quantity: int
|
|
52
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(frozen=True)
|
|
56
|
+
class ReadingEvaluation:
|
|
57
|
+
value: float | None
|
|
58
|
+
status: str
|
|
59
|
+
is_numeric: bool
|
|
60
|
+
is_within_limits: bool
|
|
61
|
+
is_low_temperature: bool
|
|
62
|
+
can_start_process: bool
|
|
63
|
+
remaining_seconds: float
|
mtchart_sdk/rules.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from mtchart_sdk.models import PartItem, PenConfig, ReadingEvaluation
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def to_float_or_none(value: Any) -> float | None:
|
|
11
|
+
try:
|
|
12
|
+
if value in ("", None):
|
|
13
|
+
return None
|
|
14
|
+
return float(value)
|
|
15
|
+
except (TypeError, ValueError):
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def clean_identifier(value: Any) -> str:
|
|
20
|
+
text = str(value or "").strip()
|
|
21
|
+
return re.sub(r"^\s*(PN|P/N|LOTE|BATCH)\s*:\s*", "", text, flags=re.IGNORECASE).strip()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def normalize_item(item: PartItem | dict[str, Any] | str) -> PartItem:
|
|
25
|
+
if isinstance(item, PartItem):
|
|
26
|
+
return item
|
|
27
|
+
if isinstance(item, dict):
|
|
28
|
+
try:
|
|
29
|
+
qty = max(1, int(str(item.get("qty", 1)).strip() or "1"))
|
|
30
|
+
except (TypeError, ValueError):
|
|
31
|
+
qty = 1
|
|
32
|
+
return PartItem(
|
|
33
|
+
name=str(item.get("name", item.get("nome", ""))).strip(),
|
|
34
|
+
pn=clean_identifier(item.get("pn", "")),
|
|
35
|
+
sn=str(item.get("sn", "")).strip(),
|
|
36
|
+
qty=qty,
|
|
37
|
+
project=str(item.get("project", item.get("projeto", ""))).strip(),
|
|
38
|
+
)
|
|
39
|
+
return PartItem(sn=str(item or "").strip())
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def total_quantity(items: list[PartItem | dict[str, Any] | str]) -> int:
|
|
43
|
+
return sum(normalize_item(item).qty for item in items or [])
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def calculate_exit_timing(started_at: datetime, relief_hours: float, now: datetime | None = None) -> tuple[datetime, float]:
|
|
47
|
+
now = now or datetime.now()
|
|
48
|
+
expected_exit_at = started_at + timedelta(hours=float(relief_hours or 0))
|
|
49
|
+
return expected_exit_at, (expected_exit_at - now).total_seconds()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def evaluate_temperature(
|
|
53
|
+
value: Any,
|
|
54
|
+
pen: PenConfig,
|
|
55
|
+
started_at: datetime,
|
|
56
|
+
relief_hours: float,
|
|
57
|
+
now: datetime | None = None,
|
|
58
|
+
) -> ReadingEvaluation:
|
|
59
|
+
numeric_value = to_float_or_none(value)
|
|
60
|
+
expected_exit_at, remaining_seconds = calculate_exit_timing(started_at, relief_hours, now)
|
|
61
|
+
del expected_exit_at
|
|
62
|
+
|
|
63
|
+
if numeric_value is None:
|
|
64
|
+
return ReadingEvaluation(
|
|
65
|
+
value=None,
|
|
66
|
+
status="N/A",
|
|
67
|
+
is_numeric=False,
|
|
68
|
+
is_within_limits=False,
|
|
69
|
+
is_low_temperature=False,
|
|
70
|
+
can_start_process=False,
|
|
71
|
+
remaining_seconds=remaining_seconds,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
low_limit = pen.low_limit
|
|
75
|
+
high_limit = pen.high_limit
|
|
76
|
+
has_low = low_limit is not None
|
|
77
|
+
has_high = high_limit is not None
|
|
78
|
+
is_low = has_low and numeric_value < float(low_limit)
|
|
79
|
+
is_high = has_high and numeric_value > float(high_limit)
|
|
80
|
+
is_within = not is_low and not is_high
|
|
81
|
+
target = pen.stabilization_target
|
|
82
|
+
can_start = target is not None and numeric_value >= float(target) - float(pen.tolerance)
|
|
83
|
+
|
|
84
|
+
if is_low:
|
|
85
|
+
status = "LOW"
|
|
86
|
+
elif is_high:
|
|
87
|
+
status = "HIGH"
|
|
88
|
+
elif is_within:
|
|
89
|
+
status = "OK"
|
|
90
|
+
else:
|
|
91
|
+
status = "UNKNOWN"
|
|
92
|
+
|
|
93
|
+
return ReadingEvaluation(
|
|
94
|
+
value=numeric_value,
|
|
95
|
+
status=status,
|
|
96
|
+
is_numeric=True,
|
|
97
|
+
is_within_limits=is_within,
|
|
98
|
+
is_low_temperature=is_low,
|
|
99
|
+
can_start_process=can_start,
|
|
100
|
+
remaining_seconds=remaining_seconds,
|
|
101
|
+
)
|
mtchart_sdk/service.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from mtchart_sdk.models import PartItem, ProcessInput, ProcessRecord, ReadingEvaluation
|
|
7
|
+
from mtchart_sdk.rules import calculate_exit_timing, evaluate_temperature, normalize_item, total_quantity
|
|
8
|
+
from mtchart_sdk.storage import PartsCatalog
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MTChartService:
|
|
12
|
+
def __init__(self, catalog_db: str | Path | None = None) -> None:
|
|
13
|
+
self.catalog = PartsCatalog(catalog_db or "mtchart_sdk.db")
|
|
14
|
+
|
|
15
|
+
def create_process(self, data: ProcessInput) -> ProcessRecord:
|
|
16
|
+
started_at = data.started_at or datetime.now()
|
|
17
|
+
items = [normalize_item(item) for item in data.items]
|
|
18
|
+
for item in items:
|
|
19
|
+
if item.name and item.pn:
|
|
20
|
+
self.catalog.save(item.name, item.pn)
|
|
21
|
+
expected_exit_at, _remaining = calculate_exit_timing(started_at, data.relief_hours, started_at)
|
|
22
|
+
return ProcessRecord(
|
|
23
|
+
report_number=data.report_number,
|
|
24
|
+
project=data.project,
|
|
25
|
+
process_name=data.process_name,
|
|
26
|
+
oven=data.oven,
|
|
27
|
+
relief_hours=float(data.relief_hours or 0),
|
|
28
|
+
pen=data.pen,
|
|
29
|
+
items=items,
|
|
30
|
+
started_at=started_at,
|
|
31
|
+
expected_exit_at=expected_exit_at,
|
|
32
|
+
total_quantity=total_quantity(items),
|
|
33
|
+
metadata=dict(data.metadata or {}),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def evaluate_reading(
|
|
37
|
+
self,
|
|
38
|
+
process: ProcessRecord,
|
|
39
|
+
value: float | str | None,
|
|
40
|
+
now: datetime | None = None,
|
|
41
|
+
) -> ReadingEvaluation:
|
|
42
|
+
return evaluate_temperature(
|
|
43
|
+
value=value,
|
|
44
|
+
pen=process.pen,
|
|
45
|
+
started_at=process.started_at,
|
|
46
|
+
relief_hours=process.relief_hours,
|
|
47
|
+
now=now,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def search_parts(self, term: str = "", limit: int = 100) -> list[dict[str, object]]:
|
|
51
|
+
return self.catalog.search(term, limit)
|
mtchart_sdk/storage.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sqlite3
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Iterator
|
|
8
|
+
|
|
9
|
+
from mtchart_sdk.rules import clean_identifier
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PartsCatalog:
|
|
13
|
+
def __init__(self, db_path: str | Path = "mtchart_sdk.db") -> None:
|
|
14
|
+
self.db_path = Path(db_path)
|
|
15
|
+
if self.db_path.parent != Path("."):
|
|
16
|
+
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
17
|
+
self.init_db()
|
|
18
|
+
|
|
19
|
+
@contextmanager
|
|
20
|
+
def connect(self) -> Iterator[sqlite3.Connection]:
|
|
21
|
+
conn = sqlite3.connect(self.db_path)
|
|
22
|
+
try:
|
|
23
|
+
yield conn
|
|
24
|
+
conn.commit()
|
|
25
|
+
except Exception:
|
|
26
|
+
conn.rollback()
|
|
27
|
+
raise
|
|
28
|
+
finally:
|
|
29
|
+
conn.close()
|
|
30
|
+
|
|
31
|
+
def init_db(self) -> None:
|
|
32
|
+
with self.connect() as conn:
|
|
33
|
+
conn.execute(
|
|
34
|
+
"""
|
|
35
|
+
CREATE TABLE IF NOT EXISTS catalog_parts (
|
|
36
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37
|
+
name TEXT NOT NULL,
|
|
38
|
+
pn TEXT NOT NULL,
|
|
39
|
+
name_norm TEXT NOT NULL,
|
|
40
|
+
pn_norm TEXT NOT NULL,
|
|
41
|
+
use_count INTEGER DEFAULT 1,
|
|
42
|
+
last_used_at TEXT NOT NULL,
|
|
43
|
+
UNIQUE(name_norm, pn_norm)
|
|
44
|
+
)
|
|
45
|
+
"""
|
|
46
|
+
)
|
|
47
|
+
conn.execute("CREATE INDEX IF NOT EXISTS idx_catalog_parts_name ON catalog_parts(name_norm)")
|
|
48
|
+
conn.execute("CREATE INDEX IF NOT EXISTS idx_catalog_parts_pn ON catalog_parts(pn_norm)")
|
|
49
|
+
|
|
50
|
+
def save(self, name: str, pn: str, increment: bool = True) -> None:
|
|
51
|
+
name = clean_identifier(name)
|
|
52
|
+
pn = clean_identifier(pn)
|
|
53
|
+
if not name or not pn:
|
|
54
|
+
raise ValueError("name and pn are required")
|
|
55
|
+
name_norm = name.upper()
|
|
56
|
+
pn_norm = pn.upper()
|
|
57
|
+
increment_by = 1 if increment else 0
|
|
58
|
+
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
59
|
+
with self.connect() as conn:
|
|
60
|
+
conn.execute(
|
|
61
|
+
"""
|
|
62
|
+
INSERT INTO catalog_parts (name, pn, name_norm, pn_norm, use_count, last_used_at)
|
|
63
|
+
VALUES (?, ?, ?, ?, 1, ?)
|
|
64
|
+
ON CONFLICT(name_norm, pn_norm) DO UPDATE SET
|
|
65
|
+
name = excluded.name,
|
|
66
|
+
pn = excluded.pn,
|
|
67
|
+
use_count = catalog_parts.use_count + ?,
|
|
68
|
+
last_used_at = excluded.last_used_at
|
|
69
|
+
""",
|
|
70
|
+
(name, pn, name_norm, pn_norm, now, increment_by),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def search(self, term: str = "", limit: int = 100) -> list[dict[str, object]]:
|
|
74
|
+
term_norm = clean_identifier(term).upper()
|
|
75
|
+
limit = max(1, min(1000, int(limit or 100)))
|
|
76
|
+
query = """
|
|
77
|
+
SELECT id, name, pn, use_count, last_used_at
|
|
78
|
+
FROM catalog_parts
|
|
79
|
+
"""
|
|
80
|
+
params: tuple[object, ...]
|
|
81
|
+
if term_norm:
|
|
82
|
+
query += " WHERE name_norm LIKE ? OR pn_norm LIKE ?"
|
|
83
|
+
params = (f"%{term_norm}%", f"%{term_norm}%", limit)
|
|
84
|
+
else:
|
|
85
|
+
params = (limit,)
|
|
86
|
+
query += " ORDER BY use_count DESC, id DESC LIMIT ?"
|
|
87
|
+
with self.connect() as conn:
|
|
88
|
+
rows = conn.execute(query, params).fetchall()
|
|
89
|
+
return [
|
|
90
|
+
{
|
|
91
|
+
"id": row[0],
|
|
92
|
+
"name": row[1],
|
|
93
|
+
"pn": row[2],
|
|
94
|
+
"use_count": row[3],
|
|
95
|
+
"last_used_at": row[4],
|
|
96
|
+
}
|
|
97
|
+
for row in rows
|
|
98
|
+
]
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mtchart-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: SDK para criar sistemas de monitoramento termico, rastreabilidade e relatorios derivados do MTChart Pro.
|
|
5
|
+
Author: MTD Softwares
|
|
6
|
+
License-Expression: LicenseRef-Proprietary
|
|
7
|
+
Project-URL: Homepage, https://github.com/Romero-Softwares/mtchart_sdk
|
|
8
|
+
Project-URL: Repository, https://github.com/Romero-Softwares/mtchart_sdk
|
|
9
|
+
Project-URL: Documentation, https://github.com/Romero-Softwares/mtchart_sdk#readme
|
|
10
|
+
Project-URL: Issues, https://github.com/Romero-Softwares/mtchart_sdk/issues
|
|
11
|
+
Keywords: monitoramento,processo-termico,rastreabilidade,aviacao,industrial
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE.md
|
|
22
|
+
Provides-Extra: reports
|
|
23
|
+
Requires-Dist: openpyxl>=3.1; extra == "reports"
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# MTChart SDK
|
|
29
|
+
|
|
30
|
+
SDK inicial para desenvolvedores criarem sistemas semelhantes ao MTChart Pro usando classes e metodos reutilizaveis.
|
|
31
|
+
|
|
32
|
+
Esta primeira versao fica separada do aplicativo desktop e entrega um nucleo limpo para:
|
|
33
|
+
|
|
34
|
+
- cadastrar processos termicos;
|
|
35
|
+
- validar leituras de temperatura;
|
|
36
|
+
- calcular previsao de saida;
|
|
37
|
+
- registrar catalogo local de pecas e PN;
|
|
38
|
+
- montar dados de rastreabilidade sem depender da interface Flet.
|
|
39
|
+
|
|
40
|
+
## Instalacao
|
|
41
|
+
|
|
42
|
+
```powershell
|
|
43
|
+
python -m pip install mtchart-sdk
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Exemplo rapido
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from datetime import datetime
|
|
50
|
+
|
|
51
|
+
from mtchart_sdk import MTChartService, PartItem, PenConfig, ProcessInput
|
|
52
|
+
|
|
53
|
+
service = MTChartService()
|
|
54
|
+
|
|
55
|
+
process = service.create_process(
|
|
56
|
+
ProcessInput(
|
|
57
|
+
report_number="CH-0001",
|
|
58
|
+
project="OS-123",
|
|
59
|
+
process_name="Alivio de fragilizacao",
|
|
60
|
+
oven="Forno 01",
|
|
61
|
+
relief_hours=3,
|
|
62
|
+
pen=PenConfig(id="1", name="Pena 1", stabilization_target=189, low_limit=175.9),
|
|
63
|
+
items=[
|
|
64
|
+
PartItem(name="Suporte", pn="PN-001", sn="SN-001", qty=1),
|
|
65
|
+
],
|
|
66
|
+
started_at=datetime(2026, 6, 28, 8, 0, 0),
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
reading = service.evaluate_reading(process, value=188.7)
|
|
71
|
+
|
|
72
|
+
print(process.report_number)
|
|
73
|
+
print(reading.status)
|
|
74
|
+
print(reading.can_start_process)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Estrutura
|
|
78
|
+
|
|
79
|
+
- `mtchart_sdk.models`: modelos de dados do processo.
|
|
80
|
+
- `mtchart_sdk.rules`: regras puras de temperatura e tempo.
|
|
81
|
+
- `mtchart_sdk.storage`: catalogo SQLite local de pecas.
|
|
82
|
+
- `mtchart_sdk.service`: fachada principal para uso por outros sistemas.
|
|
83
|
+
- `mtchart_sdk.cli`: demonstracao de linha de comando para validar instalacao.
|
|
84
|
+
- `examples/basic_process.py`: exemplo minimo executavel.
|
|
85
|
+
|
|
86
|
+
## API principal
|
|
87
|
+
|
|
88
|
+
- `MTChartService.create_process(data)`: normaliza pecas, calcula quantidade total e previsao de saida.
|
|
89
|
+
- `MTChartService.evaluate_reading(process, value)`: classifica leitura como `OK`, `LOW`, `HIGH` ou `N/A`.
|
|
90
|
+
- `MTChartService.search_parts(term)`: consulta o catalogo local de pecas por nome ou PN.
|
|
91
|
+
- `clean_identifier(value)`: remove prefixos comuns como `PN:`, `P/N:`, `LOTE:` e `BATCH:`.
|
|
92
|
+
|
|
93
|
+
## CLI de demonstracao
|
|
94
|
+
|
|
95
|
+
Depois de instalar localmente, rode:
|
|
96
|
+
|
|
97
|
+
```powershell
|
|
98
|
+
mtchart-sdk-demo --value 188.7
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Ou sem instalar como script:
|
|
102
|
+
|
|
103
|
+
```powershell
|
|
104
|
+
python -m mtchart_sdk.cli --catalog-db .tmp_demo.db --value 188.7
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
O comando cria um processo ficticio, avalia a leitura e retorna um JSON com
|
|
108
|
+
status, previsao de saida e resultados do catalogo local.
|
|
109
|
+
|
|
110
|
+
## Validacao local
|
|
111
|
+
|
|
112
|
+
Para validar uma copia local do SDK durante desenvolvimento:
|
|
113
|
+
|
|
114
|
+
```powershell
|
|
115
|
+
python tools/validate_package.py
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
O validador confere metadados, compila os modulos, roda testes e executa o
|
|
119
|
+
exemplo/CLI de demonstracao.
|
|
120
|
+
|
|
121
|
+
## Status
|
|
122
|
+
|
|
123
|
+
Versao inicial. A API esta pronta para instalacao, testes locais e evolucao incremental.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
mtchart_sdk/__init__.py,sha256=IJ8bMwv2YOQ6PmPSF3GH5ytZuf2ynCVcZf471KlJ7q4,677
|
|
2
|
+
mtchart_sdk/cli.py,sha256=Jq9QbhOSy4ItCc4Cw_mpMv6-tdBlqoChs71KdvvdBuM,3759
|
|
3
|
+
mtchart_sdk/models.py,sha256=f-BmGrFEfbOOHK3ueki1cjq4tvbyfv03D2yrX5gaJb4,1437
|
|
4
|
+
mtchart_sdk/rules.py,sha256=JgsVtwJ6OIqcGiwNVhuj_CcKfunfForPXY65ar2Yiro,3265
|
|
5
|
+
mtchart_sdk/service.py,sha256=GIB8Jan4UoVhl4hxXSU-HUVeXWwRk9DrPCoVlM-iRUE,1954
|
|
6
|
+
mtchart_sdk/storage.py,sha256=4K9iwyp7gk2CieRSS0O6iFShBabxqgiHiVKSg2c2VF8,3614
|
|
7
|
+
mtchart_sdk-0.1.0.dist-info/licenses/LICENSE.md,sha256=qiHPDS6FSlbg5G-Eoh7dFcOtXLOBvX9hXigb-El1LhE,667
|
|
8
|
+
mtchart_sdk-0.1.0.dist-info/METADATA,sha256=R6SiwpPqQD5mJfLJX2OSMcRI1-gek4IukCq3ogb2SXM,4110
|
|
9
|
+
mtchart_sdk-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
10
|
+
mtchart_sdk-0.1.0.dist-info/entry_points.txt,sha256=g2AdcwosARJ0uoEVK4gwINHguvPstiD-IcYEL0FGXC4,58
|
|
11
|
+
mtchart_sdk-0.1.0.dist-info/top_level.txt,sha256=msH_FVGlPkDhfnxYswk6bdyN936yoMv7sjS6vSpnLm0,12
|
|
12
|
+
mtchart_sdk-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Proprietary Commercial License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MTD Softwares.
|
|
4
|
+
|
|
5
|
+
This SDK is provided as a commercial/proprietary component derived from
|
|
6
|
+
MTChart Pro. Use, redistribution, sublicensing, resale, or incorporation into
|
|
7
|
+
third-party products requires written authorization from MTD Softwares.
|
|
8
|
+
|
|
9
|
+
Developers may use this local copy only for evaluation, internal testing, and
|
|
10
|
+
integration planning unless a separate commercial license grants broader
|
|
11
|
+
rights.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mtchart_sdk
|