Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

Overview

Hint engine rules works similarly to Pre-Processing Functions ✔️, it allows you to fine-tune PackOS automatic data analysis for your needs. By defining a set of functions, you can teach PackOS how to spot interesting patterns in observed data and send you and your crew notifications about them.

Each function defines:

  • Name

  • Trigger - when the function will be executed, you can select an explicit time period like ‘end of hour’ or ‘end of day’. Or run the function when an order or shift ends. The list of currently available triggers (can be extended in the future):

    • Every 10 minutes

    • End of hour

    • After order

    • After shift

    • At midnight - (defined by factory timezone)

    • At end of day - (hour defined by factory setup and timezone)

    • At the end of week - (end of day, before the configured ‘start of week’)

    • At the end of month - (end of day, last day of month)

  • Script - the body of your hint function, allowed statements and examples are described below

  • Test execution box - allows you to execute the script and inspect the result without generating actual hints.

    • Store parameters - when selected, all parameters generated by the script will be persisted in the database

    • Add parameter - let’s you inject/overwrite custom parameters, just for this run

Script

The body of the script should be a C# method, following the syntax and conventions defined by this language. We recommend the official Microsoft documentation:

https://learn.microsoft.com/en-us/dotnet/csharp/

In the script, the following variables are available:

  • DateTime Now - current time

  • Library - set of predefined functions which are available out of the box, constantly extended and tuned by Ilabo team. Described below.

  • IOrderProvider Orders - provider of orders

public interface IOrderProvider
{
    // returns started and completed orders in the specified time period
    public Task<ICollection<Order>> GetExecutedOrders(Guid lineId, DateTime from, DateTime to);
}

public record Order(
    Guid LineId,
    string Status,
    DateTime StartDate,
    DateTime? EndDate);

  • IAssetProvider Assets - provider of factory assets

public interface IAssetProvider
{
    // returns all lines in the factory
    Task<ICollection<Element>> GetLines();

    // returns all machines in the factory
    Task<ICollection<Element>> GetMachines();
}

public record Element(
    Guid Id, 
    Guid? ParentId,
    string Code, 
    string Name, 
    string Path,
    string Type);

  • IProductionProvider Production - provider of production data

public interface IProductionProvider
{
    // Returns bucket with aggregated production, waste and time loss classes 
    Task<BucketInfo> GetBucket(string elementName, DateTime from, DateTime to);
    
    // Returns bucket with aggregated production, waste and time loss classes
    Task<BucketInfo> GetBucket(Guid elementId, DateTime from, DateTime to);

    // Returns aggregated production and waste in multiple time periods
    Task<ICollection<Production>> Get(ICollection<ProductionRequest> requests);

    // Returns aggregated production and waste in selected time period
    Task<ICollection<Production>> Get(ICollection<Guid> elementIds, string? unit, DateTime from, DateTime to);

    // Returns base units for selected elements (lines/machines)
    Task<Dictionary<Guid, string>> GetUnits(ICollection<Guid> elementIds);

    // Returns metadata about elements (lines/machines)
    Task<ICollection<ElementStatus>> GetStatus(ICollection<Guid> elementIds);
}

public record BucketInfo(
    Guid ElementId,
    string Unit,
    double Done,
    double Wasted,
    double Planned,
    DateTime From,
    DateTime To,
    TimeSpan QualityLoss,
    TimeSpan PerformanceLoss,
    TimeSpan AvailabilityLoss,
    TimeSpan UtilizationLoss,
    TimeSpan TotalTime,
    bool IsUnitConversionComplete);

public record Production(
    Guid ElementId,
    DateTime From,
    DateTime To,
    string Unit,
    double Done,
    double Wasted,
    bool IsUnitConversionComplete);

public record ElementStatus(
    Guid ElementId,
    bool IsBaseAvailability,
    bool IsBaseQuantity,
    bool IsDummy,
    bool IsAlive,
    string Kind,
    string Name,
    string Path,
    DateTime KeepAlive);

  • IWorkLogProvider WorkLogs - provider for data about machine states

public interface IWorkLogProvider
{
    // returns aggregated summary of work states in the selected time period
    Task<IEnumerable<AggregatedWorkLog>> GetAggregated(string elementName, DateTime from, DateTime to);

    // returns aggregated summary of work states in the selected time period, divided by different "groupBy" time periods
    // groupBy is an array of tokens from the list:
    // 'hour', 'day', 'week', 'month', 'shift', 'order', 'product', 'shiftInstance'
    Task<IEnumerable<AggregatedWorkLog>> GetSplitBy(string elementName, DateTime from, DateTime to, params string[] groupBy);

    // returns definitions of all defined problems (for all lines or machines)
    Task<IEnumerable<WorkEvent>> GetEventDefinitions();

    // returns a definition of a particular problem
    Task<WorkEvent?> GetEventDefinition(Guid eventId);
}

public record WorkEvent(
    Guid ElementId,
    Guid WorkEventId,
    string Name);
    
public record AggregatedWorkLog(
    DateTime? From, // only if effective time split available
    DateTime? To,// only if effective time split available
    Guid ElementId,
    Guid WorkEventId,
    string WorkStateName,
    Guid? RootElementId,
    Guid? RootWorkEventId,
    string? RootWorkStateName,
    TimeSpan TotalDuration,
    TimeSpan MinorStopDuration,
    TimeSpan WorkDuration,
    TimeSpan UtilizationLossDuration,
    TimeSpan AvailabilityLossDuration,
    TimeSpan PerformanceLossDuration,
    TimeSpan QualityLossDuration,
    int TotalCount,
    int MinorStopCount);

  • IParameterStore ParameterStore - service which allows requesting and persisting custom parameters

public interface IParameterStore
{
    // Get value of a custom parameter
    Parameter Get(string key);

    // Save multiple key/values of parameters
    Task Store(IEnumerable<Parameter> parameter);
    
    // Add temporarily a parameter to the store (won't be peristed)
    void Attach(IReadOnlyCollection<Parameter> additionalParameters);
}

public class Parameter
{
    /**
     * Key of the parameter
     * Accessible from any job in this plant
     */
    public string Key { get; init; }
    
    /**
     * Value of the parameter
     */
    public string? Value { get; set; } = null;

    /**
     * How long will the parameter live in the store
     * Value equal or lower to 0 will be never removed
     */
    public TimeSpan TimeToLive { get; set; } = TimeSpan.Zero;

    public Parameter(string key, string value)
    {
        Key = key;
        Value = value;
    }
}

You can use all of the above variables/providers/services to request data of interest, make calculations and generate hints/warnings for your crew.

The function should return a new object of class HintFunctionOutput containing a list of Hints. Each Hint is defined as:

public class Hint
{
    // Line code or Line/Machine path
    public string Element { get; set; } = null!;

    // Title of the hint
    public string Title { get; set; } = string.Empty;

    // Description of the hint
    public string Description { get; set; } = string.Empty;

    // How long will the hint be displayed to the user
    public TimeSpan TimeToLive { get; set; } = TimeSpan.FromHours(1);
}


Examples

  1. Request work history for the 'Line1' and create a hint with a simple count

var result = new HintFunctionOutput();

var from = DateTime.UtcNow.AddHours(-1);
var to = DateTime.UtcNow;

var elementName = "ILA/OBS/Line1";
var workLogs = await WorkLogs.Get(element, from, to);

result.Hints.Add(new Hint()
{
	Element = elementName,
	Title = "Number of worklogs",
	Description = $"There were {workLogs.Count()} workLogs in from {from:G} to {to:G}"
});

return result;

  1. Use pre-defined library function to generate CounterMismatch hints:

var output = new HintFunctionOutput();

var hints = await Library.CounterMismatch.Run(TimeSpan.FromHours(1), threshold: 20);
Library.CounterMismatch.CreateHints(output, hints);

return output; 

Library functions

The following hints are pre-defined in the library, and can be easily executed:

DowntimeFrequencyIncrease - Detect an increasing number of downtimes of specific type

  • Task Build(TimeSpan timeSpan, string? elementPath = null, int percentile = 95)

    Calculates and stores as a parameter the ‘usual number of downtimes’ for each observed downtime type in the time period defined as ‘timeSpan’.
    In essence, ‘usual number' is calculated by aggregating the number of downtimes of each type for each hour, creating a histogram, and retrieving 95th percentile.
    When executing the Build command, you can choose to run it only for a specific element by providing elementPath or selecting a different percentile cutoff for the algorithm.

  • Task<ICollection<IncreasedDowntimeFrequency>> Run(string? elementPath = null)

    Creates a list of IncreasedDowntimeFrequency objects, each describing an interesting instance of increased downtime frequency. You can filter or aggregate the result, use it to generate new hints, or calculate other parameters. Each entry contains the following details:

    public record IncreasedDowntimeFrequency(
        string ElementName,
        string ElementPath,
        Guid ElementId,
        Guid WorkEventId, 
        string WorkEventName,
        DateTime From, 
        DateTime To, 
        int Count, 
        int CutOff);

    Note that the Run function can only be executed after the Build method pre-calculating statistics. We recommend to separate this process into 2 functions:
    - Build should be executed once a week/ once a month.
    - Run can be executed every hour/after a shift etc.

  • void CreateHints(HintFunctionOutput output, ICollection<IncreasedDowntimeFrequency> increasedFrequency)

    Will add new hints to the output using a default formatter (in english)

CounterMismatch - Detect inconsistent production count for two different machines of the same line

  • Task<ICollection<MachineCounterMismatch>> Run(
      TimeSpan timeSpan,
      double threshold = 20, // acceptable threshold, 20% difference by default 
      string? linePath = null)

    Analyse production count in the defined by timeSpan time period. Production output of each machine is compared to the BaseQuantity machine. Units are converted if necessary. If the difference between counts exceeds the allowed threshold. An object MachineCounterMismatch with details is returned:

    public record MachineCounterMismatch(
        Guid ElementId,
        string ElementPath,
        string ElementName,
        double TotalCounter,
        Guid BaseQuantityId,
        string BaseQuantityName,
        string BaseQuantityPath,
        double BaseQuantityCounter,
        string Unit);
  • void CreateHints(HintFunctionOutput output, ICollection<MachineCounterMismatch> hints)

    Will add new hints to the output using a default formatter (in english)

ProductionWithoutOrder - Detect when the line was producing without any running order

  • // Increasing threshold reduces sensitivity of the hint
    // More production difference between order production and raw line production is acceptable
    Task<ICollection<ProductionWithoutOrderModel>> Run(
      double threshold = 0,
      TimeSpan? checkDuration = null,
      TimeSpan? bucketHourOffset = null)

    Analyse the production and orders in the provided checkDuration. This period of time is analyse in the context of orders and production. If there is some production in this period of time which is not part of any order - a new instance of ProductionWithoutOrderModel is raised with the following details:

    public record ProductionWithoutOrderModel(
            DateTime From,
            DateTime To,
            Guid ElementId,
            string ElementPath,
            string ElementName,
            double TotalCount,
            double TotalCountFromOrders,
            string Unit);
  • void CreateHints(HintFunctionOutput output, ICollection<ProductionWithoutOrderModel> hints)

    Will add new hints to the output using a default formatter (in english)

  • No labels