Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add concepts for production order, production run and product #10

Merged
merged 26 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a6d15f5
draft of production runs, production run, quantities and metrics
denizs Jul 20, 2023
293332a
remove production run from docstrings
denizs Jul 20, 2023
cd9db4f
set default for Metrics and Quantities
denizs Jul 20, 2023
88257fd
run pyproject-fmt
denizs Jul 20, 2023
af984ab
Align modelling of production runs after remodelling of API (#9)
daniel-k Jul 20, 2023
4a10d7b
docs: add concepts for production order, production run and product
daniel-k Jul 20, 2023
21c9cf7
Update docs/concepts.rst
daniel-k Jul 21, 2023
9cba52c
Update docs/concepts.rst
daniel-k Jul 21, 2023
9dbcdb2
add "This is how operators are told how much of which product to prod…
daniel-k Jul 21, 2023
2c8948b
Update docs/concepts.rst
denizs Oct 10, 2023
2ac763f
add missing "next" field to response mocks
denizs Sep 22, 2023
3915e4f
exclude pydantic members from docs
denizs Sep 22, 2023
42368c3
Implement `ApiBaseClient` and derive `TimeseriesApiClient` from it (#14)
denizs Sep 29, 2023
c5784d5
Add `ProductionRunsApiClient` (#15)
denizs Sep 29, 2023
a650dc4
Revert "Align modelling of production runs after remodelling of API (…
denizs Oct 10, 2023
75246bd
Revert "draft of production runs, production run, quantities and metr…
denizs Oct 10, 2023
0448296
add Betriebsdatenerfassung to spelling wordlist
denizs Oct 10, 2023
e952cd2
rephrase concepts
denizs Oct 10, 2023
0833988
Merge branch 'feature/production-runs' into docs/production-runs
denizs Oct 10, 2023
3cd10ba
Update docs/concepts.rst
denizs Oct 10, 2023
4569019
Update docs/concepts.rst
denizs Oct 10, 2023
1f91c68
Update docs/concepts.rst
denizs Oct 10, 2023
c2345af
Update docs/concepts.rst
denizs Oct 10, 2023
32b36ea
Update docs/concepts.rst
denizs Oct 10, 2023
3312288
Update docs/concepts.rst
denizs Oct 10, 2023
77a0a4e
format docs
denizs Oct 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/concepts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,53 @@ Variable
A *variable* represents a process measure of one :ref:`appliance <appliance>` of which
timeseries data is captured and stored in the ENLYZE platform. One appliance may have
many variables, whereas one variable is only associated with one appliance.


.. _production_order:

Production Order
daniel-k marked this conversation as resolved.
Show resolved Hide resolved
----------------

A *production order* represents the goal of producing a certain quantity of a
given :ref:`product <product>`. Production orders are usually created in an ERP
system or MES of the customer and then synchronized into the ENLYZE platform.
daniel-k marked this conversation as resolved.
Show resolved Hide resolved
daniel-k marked this conversation as resolved.
Show resolved Hide resolved
They are referenced by an identifier which oftentimes is a short combination of
numbers and/or characters, like FA23000123 or 332554.

In the ENLYZE platform, a production order always encompasses the production of
one single :ref:`product <product>` on one single :ref:`appliance <appliance>`.


.. _production_run:

Production Run
--------------

A *production run* represents the real allocation of a :ref:`production order
denizs marked this conversation as resolved.
Show resolved Hide resolved
<production_order>` on an :ref:`appliance <appliance>`. Usually, the operator of
denizs marked this conversation as resolved.
Show resolved Hide resolved
the appliance uses some kind of interface to log the time when a certain
production order has been worked on. A production order oftentimes is not
denizs marked this conversation as resolved.
Show resolved Hide resolved
allocated continously on an appliance due to interruptions like a breakdown or
weekend. Each of these individual, continous allocations is called a *production
run* in the ENLYZE platform. It always has a beginning and, if it's not still
running, it also has an end. The ENLYZE platform calculates different aggregates
from the timeseries data of the appliance for each production run.


.. _product:

Product
-------

A *product* is the output of the production process which is executed by an
:ref:`appliance <appliance>`, driven by a :ref:`production order
<production_order>`. In the real world, an appliance might have some additonal
outputs, but only the main output (the product) modelled in the ENLYZE platform.
Similarly to the production order, a product is referenced by an identifier
originating from a system of the customer, which is synchronized into the ENLYZE
daniel-k marked this conversation as resolved.
Show resolved Hide resolved
platform.

During the integration into the ENLYZE platform, the product identifier is
chosen in such a way that :ref:`production runs <production_run>` of the same
product are comparable with one another. This is the foundation for constantly
improving the production of recurring products over time.
12 changes: 12 additions & 0 deletions docs/models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,15 @@ Data models
.. autoclass:: ResamplingMethod()
:members:
:undoc-members:

.. autoclass:: ProductionRun()
:members:
:undoc-members:

.. autoclass:: OEEScore()
:members:
:undoc-members:

.. autoclass:: Quantity()
:members:
:undoc-members:
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ readme = "README.rst"
license = {text = "MIT"}
authors = [{name = "ENLYZE GmbH", email = "[email protected]"},]
requires-python = ">=3.10"
classifiers = [
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
dynamic = [
'version',
]
Expand Down
103 changes: 101 additions & 2 deletions src/enlyze/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass
from datetime import date, datetime, timezone
from dataclasses import asdict, dataclass
from datetime import date, datetime, timedelta, timezone
from enum import Enum
from itertools import chain
from typing import Any, Iterator, Optional, Sequence
Expand Down Expand Up @@ -197,3 +197,102 @@ def to_dataframe(self, use_display_names: bool = False) -> pandas.DataFrame:
)
df.index = pandas.to_datetime(df.index, utc=True, format="ISO8601")
return df


@dataclass(frozen=True)
class OEEScore:
"""Individual Overall Equipment Effectiveness (OEE) score

This is calculated by the ENLYZE Platform based on a combination of real
machine data and production order booking information provided by the
customer.

For more information, please check out https://www.oee.com
"""

#: The score is expressed as a ratio between 0 and 1.0, with 1.0 meaning 100 %.
score: float

#: Unproductive time due to non-ideal production.
time_loss: timedelta


@dataclass(frozen=True)
class Quantity:
"""Representation of a physical quantity"""

#: Physical unit of quantity
unit: str

#: The quantity expressed in `unit`
value: float


@dataclass(frozen=True)
class ProductionRun:
"""Representation of a :ref:`production run <production_run>` in the ENLYZE
platform.

Contains details about the production run.

"""

#: The UUID of the appliance the production run was exeucted on.
appliance: UUID

#: The average throughput of the production run excluding downtimes.
average_throughput: Optional[float]

#: The identifier of the production order.
production_order: str

#: The identifier of the product that was produced.
product: str

#: The begin of the production run.
begin: datetime

#: The end of the production run.
end: Optional[datetime]

#: This is the sum of scrap and yield.
quantity_total: Optional[Quantity]

#: The amount of product produced that doesn't meet quality criteria.
quantity_scrap: Optional[Quantity]

#: The amount of product produced that can be sold.
quantity_yield: Optional[Quantity]

#: OEE component that reflects when the appliance did not produce.
availability: Optional[OEEScore]

#: OEE component that reflects how fast the appliance has run.
performance: Optional[OEEScore]

#: OEE component that reflects how much defects have been produced.
quality: Optional[OEEScore]

#: Aggregate OEE score that comprises availability, performance and quality.
productivity: Optional[OEEScore]


class ProductionRuns(list[ProductionRun]):
"""Representation of multiple :ref:`production runs <production_run>`."""

def to_dataframe(self) -> pandas.DataFrame:
"""Convert production runs into :py:class:`pandas.DataFrame`

Each row in the data frame will represent one production run.
The ``begin`` and ``end`` of every production run will be
represented as :ref:`timezone-aware <python:datetime-naive-aware>`
:py:class:`datetime.datetime` localized in UTC.

:returns: DataFrame with production runs

"""

df = pandas.json_normalize([asdict(run) for run in self])
df.begin = pandas.to_datetime(df.begin, utc=True, format="ISO8601")
df.end = pandas.to_datetime(df.end, utc=True, format="ISO8601")
return df