Sensors previously only tracked alarm thresholds (alert_min/alert_max). Missing the third piece of standard process control: the SETPOINT — what the heater/chiller controls toward and what dashboards compare against. Without it an operator can't tell whether 89°C is "on target" or "barely still in spec". Schema changes: **fusion.plating.bath.parameter** (shop-wide default) - New `target_value` field — the default setpoint for this parameter across the shop (e.g. 87°C for ENP bath). Parallel to existing target_min / target_max. **fp.tank.sensor** (per-sensor override) - New `target_value_override` — per-sensor override, zero = inherit from parameter. Matches the existing override pattern for alert thresholds so users can fine-tune per-tank without touching the shop-wide spec. - New `effective_target` / `effective_target_unit` computed — resolves override → parameter default, converts to company-preferred unit. - New `_get_setpoint()` helper for internal use. **fp.tank.reading** - New `deviation_from_target` — signed Δ from the sensor's effective setpoint, in the company's preferred unit. Positive = above, negative = below, zero if no setpoint defined. - New `deviation_band` (selection: on/near/far/out/none) — coarse band for fast visual scanning. `on` = within ±1° of target, `near` = ±3°, `far` = beyond, `out` = actually out of the alarm band. **Views** - Sensor form: split the alerting panel into two groups — "Target (setpoint)" on the left, "Alarm band" on the right. Makes the distinction between "where we want to be" and "where we'd panic" visually obvious. - Reading list: new Δ + band columns, with decoration classes (success/info/warning/danger) so the list reads at a glance. - Tank form Sensors tab: inline setpoint + unit column. Seeded: parameter "Bath Temperature (Hot Process)" now carries target_value=87°C as a realistic ENP shop default. Sensors inherit unless they set their own override. Design decisions kept simple: - Did NOT add a warning band (warn_min/warn_max). Two-tier model (setpoint + alarm band) is enough for the pilot. Can add soft warnings later as a separate commit if ops wants them. - Did NOT auto-control heaters. Setpoint is stored as metadata only; actual heater actuation via IoT is a future phase C project. Verified: setpoint 87°C stored → displays 188.60°F on the live pilot sensor (company pref = F). Each incoming reading correctly computes signed deviation; bands colour the reading list appropriately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
96 lines
2.9 KiB
Python
96 lines
2.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
# Part of the Fusion Plating product family.
|
|
|
|
from odoo import fields, models
|
|
|
|
|
|
class FpBathParameter(models.Model):
|
|
"""Definition of a bath chemistry parameter.
|
|
|
|
Parameters are process-agnostic at the schema level (e.g. "Temperature",
|
|
"pH", "Nickel concentration"). Each process type references a set of
|
|
parameters via fusion.plating.process.type.parameter_ids. Actual target
|
|
ranges per bath are stored on fusion.plating.bath (per-bath overrides)
|
|
or on the bath recipe.
|
|
"""
|
|
_name = 'fusion.plating.bath.parameter'
|
|
_description = 'Fusion Plating — Bath Parameter'
|
|
_order = 'sequence, name'
|
|
|
|
name = fields.Char(
|
|
string='Parameter',
|
|
required=True,
|
|
translate=True,
|
|
help='Display name (e.g. "Nickel Concentration", "pH").',
|
|
)
|
|
code = fields.Char(
|
|
string='Code',
|
|
required=True,
|
|
help='Short code used in logs and exports (e.g. "Ni", "PH", "TEMP").',
|
|
)
|
|
sequence = fields.Integer(
|
|
string='Sequence',
|
|
default=10,
|
|
)
|
|
parameter_type = fields.Selection(
|
|
[
|
|
('concentration', 'Concentration'),
|
|
('temperature', 'Temperature'),
|
|
('ph', 'pH'),
|
|
('conductivity', 'Conductivity'),
|
|
('turbidity', 'Turbidity'),
|
|
('ratio', 'Ratio'),
|
|
('count', 'Count / Age'),
|
|
('other', 'Other'),
|
|
],
|
|
string='Type',
|
|
required=True,
|
|
default='concentration',
|
|
)
|
|
uom = fields.Char(
|
|
string='Unit',
|
|
help='Display unit (e.g. "g/L", "°C", "pH", "MTO").',
|
|
)
|
|
target_min = fields.Float(
|
|
string='Default Target Min',
|
|
help='Default target minimum. Per-bath overrides are allowed.',
|
|
)
|
|
target_max = fields.Float(
|
|
string='Default Target Max',
|
|
help='Default target maximum. Per-bath overrides are allowed.',
|
|
)
|
|
target_value = fields.Float(
|
|
string='Default Setpoint / Optimum',
|
|
help='The IDEAL operating value — what the heater/chiller controls '
|
|
'toward, what dashboards compare against. Sits between '
|
|
'target_min and target_max. Per-sensor override via '
|
|
'fp.tank.sensor.target_value_override.',
|
|
)
|
|
warning_tolerance = fields.Float(
|
|
string='Warning Tolerance %',
|
|
default=10.0,
|
|
help='Distance from target limit at which a reading is flagged as warning.',
|
|
)
|
|
decimals = fields.Integer(
|
|
string='Decimals',
|
|
default=2,
|
|
)
|
|
description = fields.Text(
|
|
string='Description',
|
|
translate=True,
|
|
)
|
|
active = fields.Boolean(
|
|
string='Active',
|
|
default=True,
|
|
)
|
|
|
|
_sql_constraints = [
|
|
(
|
|
'fp_bath_parameter_code_uniq',
|
|
'unique(code)',
|
|
'Bath parameter code must be unique.',
|
|
),
|
|
]
|