devagent-ignition 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.
- devagent_hmi.py +471 -0
- devagent_ignition-0.1.0.dist-info/METADATA +204 -0
- devagent_ignition-0.1.0.dist-info/RECORD +133 -0
- devagent_ignition-0.1.0.dist-info/WHEEL +4 -0
- devagent_ignition-0.1.0.dist-info/entry_points.txt +2 -0
- devagent_spatial/__init__.py +1 -0
- devagent_spatial/_resources/README.md +187 -0
- devagent_spatial/_resources/RELEASE_MANIFEST.json +312 -0
- devagent_spatial/_resources/SHA256SUMS.txt +270 -0
- devagent_spatial/_resources/SOURCE_PROVENANCE.json +186 -0
- devagent_spatial/_resources/assets/agent.js +102 -0
- devagent_spatial/_resources/assets/creator.css +247 -0
- devagent_spatial/_resources/assets/creator_2d.mjs +16 -0
- devagent_spatial/_resources/assets/creator_original_r9.mjs +58 -0
- devagent_spatial/_resources/assets/creator_original_v8.mjs +120 -0
- devagent_spatial/_resources/assets/creator_r9_diagnostics.mjs +53 -0
- devagent_spatial/_resources/assets/creator_scene.mjs +128 -0
- devagent_spatial/_resources/assets/creator_ui.mjs +60 -0
- devagent_spatial/_resources/assets/customer_documents.js +110 -0
- devagent_spatial/_resources/assets/equipment_controls.mjs +27 -0
- devagent_spatial/_resources/assets/facility2d.css +24 -0
- devagent_spatial/_resources/assets/facility2d_app.mjs +45 -0
- devagent_spatial/_resources/assets/facility2d_core.mjs +114 -0
- devagent_spatial/_resources/assets/facility2d_simulation.mjs +167 -0
- devagent_spatial/_resources/assets/facility2d_viewer.html +7 -0
- devagent_spatial/_resources/assets/fallback_scene.js +17 -0
- devagent_spatial/_resources/assets/flow_geometry.mjs +218 -0
- devagent_spatial/_resources/assets/harness.js +78 -0
- devagent_spatial/_resources/assets/live_design_review.js +129 -0
- devagent_spatial/_resources/assets/operations_ui.js +305 -0
- devagent_spatial/_resources/assets/operator_viewer.html +64 -0
- devagent_spatial/_resources/assets/project_package.js +52 -0
- devagent_spatial/_resources/assets/r9_transport.mjs +70 -0
- devagent_spatial/_resources/assets/runtime_feed.js +30 -0
- devagent_spatial/_resources/assets/studio.html +139 -0
- devagent_spatial/_resources/assets/style.css +191 -0
- devagent_spatial/_resources/assets/test_workspace.html +195 -0
- devagent_spatial/_resources/assets/three_scene.js +442 -0
- devagent_spatial/_resources/assets/unified_engineer.js +101 -0
- devagent_spatial/_resources/assets/v076_fat_ui.js +40 -0
- devagent_spatial/_resources/assets/v078_command_ui.js +44 -0
- devagent_spatial/_resources/assets/viewer.html +45 -0
- devagent_spatial/_resources/assets/viewer.js +112 -0
- devagent_spatial/_resources/design-system.json +130 -0
- devagent_spatial/_resources/examples/CV101-command-contract-PENDING.json +30 -0
- devagent_spatial/_resources/examples/cv101_guided.json +272 -0
- devagent_spatial/_resources/examples/make_examples.py +36 -0
- devagent_spatial/_resources/examples/single_floor.json +444 -0
- devagent_spatial/_resources/examples/v0771_training_wizard.json +11 -0
- devagent_spatial/_resources/examples/warehouse-3floor-standard-2d.json +708 -0
- devagent_spatial/_resources/examples/warehouse-operations-synthetic.json +1186 -0
- devagent_spatial/_resources/examples/warehouse-v07-lab-bindings-PENDING.json +372 -0
- devagent_spatial/_resources/examples/warehouse.json +708 -0
- devagent_spatial/_resources/examples/water.json +288 -0
- devagent_spatial/_resources/reference/r9-golden/REFERENCE_SHA256.json +13 -0
- devagent_spatial/_resources/reference/r9-golden/web/app.mjs +745 -0
- devagent_spatial/_resources/reference/r9-golden/web/index.html +213 -0
- devagent_spatial/_resources/reference/r9-golden/web/lab_panel.mjs +53 -0
- devagent_spatial/_resources/reference/r9-golden/web/model.mjs +367 -0
- devagent_spatial/_resources/reference/r9-golden/web/state_adapter.mjs +78 -0
- devagent_spatial/_resources/reference/r9-golden/web/styles.css +76 -0
- devagent_spatial/_resources/reference/r9-original/README_R9.md +27 -0
- devagent_spatial/_resources/reference/r9-original/SHA256SUMS.txt +63 -0
- devagent_spatial/_resources/reference/r9-original/SNAPSHOT_SHA256SUMS.txt +16 -0
- devagent_spatial/_resources/reference/r9-original/flow_routes.json +527 -0
- devagent_spatial/_resources/reference/r9-original/flow_sim.py +117 -0
- devagent_spatial/_resources/reference/r9-original/lab_control.py +73 -0
- devagent_spatial/_resources/reference/r9-original/web/app.mjs +745 -0
- devagent_spatial/_resources/reference/r9-original/web/index.html +213 -0
- devagent_spatial/_resources/reference/r9-original/web/lab_panel.mjs +53 -0
- devagent_spatial/_resources/reference/r9-original/web/model.mjs +367 -0
- devagent_spatial/_resources/reference/r9-original/web/state_adapter.mjs +78 -0
- devagent_spatial/_resources/reference/r9-original/web/styles.css +76 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/LICENSE-three.txt +21 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/SHA256SUMS.txt +4 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/addons/controls/OrbitControls.js +1860 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/three.core.js +58773 -0
- devagent_spatial/_resources/reference/r9-original/web/vendor/three.module.js +18251 -0
- devagent_spatial/_resources/reference/v8-original/README.md +36 -0
- devagent_spatial/_resources/reference/v8-original/SHA256SUMS.txt +12 -0
- devagent_spatial/_resources/reference/v8-original/model.py +124 -0
- devagent_spatial/_resources/reference/v8-original/run_demo.sh +4 -0
- devagent_spatial/_resources/reference/v8-original/server.py +100 -0
- devagent_spatial/_resources/reference/v8-original/tests/browser_smoke.py +50 -0
- devagent_spatial/_resources/reference/v8-original/tests/test_v8.py +144 -0
- devagent_spatial/_resources/reference/v8-original/topology.json +24 -0
- devagent_spatial/_resources/reference/v8-original/web/app.js +114 -0
- devagent_spatial/_resources/reference/v8-original/web/index.html +22 -0
- devagent_spatial/_resources/reference/v8-original/web/simulator.html +1 -0
- devagent_spatial/_resources/reference/v8-original/web/simulator.js +6 -0
- devagent_spatial/_resources/reference/v8-original/web/style.css +16 -0
- devagent_spatial/_resources/sample_customer_inputs/Plant_Equipment_Register.csv +4 -0
- devagent_spatial/_resources/sample_customer_inputs/Plant_Flow_Requirements.txt +5 -0
- devagent_spatial/_resources/sample_customer_inputs/Raw_PLC_Tag_Export.csv +4 -0
- devagent_spatial/_resources/templates/warehouse_connections.csv +12 -0
- devagent_spatial/_resources/templates/warehouse_equipment.csv +21 -0
- devagent_spatial/_resources/templates/warehouse_signals.csv +34 -0
- devagent_spatial/_resources/templates/water_connections.csv +7 -0
- devagent_spatial/_resources/templates/water_equipment.csv +10 -0
- devagent_spatial/_resources/templates/water_signals.csv +12 -0
- devagent_spatial/agent_harness.py +299 -0
- devagent_spatial/agent_runtime.py +314 -0
- devagent_spatial/contract_opc_fat.py +216 -0
- devagent_spatial/contract_opc_source.py +265 -0
- devagent_spatial/control_intents.py +38 -0
- devagent_spatial/customer_intake.py +235 -0
- devagent_spatial/engineering_expertise.py +114 -0
- devagent_spatial/generator.py +201 -0
- devagent_spatial/ignition_native.py +234 -0
- devagent_spatial/ignition_project.py +144 -0
- devagent_spatial/live_lab_binding.py +128 -0
- devagent_spatial/model.py +297 -0
- devagent_spatial/native_reference.py +69 -0
- devagent_spatial/opc_snapshot.py +87 -0
- devagent_spatial/operations.py +284 -0
- devagent_spatial/operations_capture.py +47 -0
- devagent_spatial/operations_lab.py +64 -0
- devagent_spatial/original_r9.py +169 -0
- devagent_spatial/original_v8.py +81 -0
- devagent_spatial/preflight.py +140 -0
- devagent_spatial/preview_simulation.py +189 -0
- devagent_spatial/project_package.py +101 -0
- devagent_spatial/qualification.py +152 -0
- devagent_spatial/strict_json.py +29 -0
- devagent_spatial/studio.py +894 -0
- devagent_spatial/studio_workflow.py +277 -0
- devagent_spatial/test_reporting.py +87 -0
- devagent_spatial/v076_opc_fat.py +180 -0
- devagent_spatial/v078_commands.py +277 -0
- devagent_spatial/v078_native_commands.py +161 -0
- devagent_spatial/v07_fat.py +110 -0
- devagent_spatial/v07_native.py +318 -0
- devagent_spatial/v083_native.py +349 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/** Operator-only. This file intentionally has no POST or control endpoint. */
|
|
3
|
+
const NS='http://www.w3.org/2000/svg';
|
|
4
|
+
const $=id=>document.getElementById(id);
|
|
5
|
+
const esc=v=>String(v).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
|
6
|
+
const FULL={x:0,y:0,w:1400,h:700};
|
|
7
|
+
const ZOOMS={INBOUND:{x:50,y:102,w:440,h:530},INDUCTION:{x:340,y:130,w:470,h:510},SORTATION:{x:675,y:125,w:580,h:510},DISPATCH:{x:915,y:120,w:455,h:540}};
|
|
8
|
+
const COLORS={RUNNING:'#32cba5',JAM:'#f17275',FAULT:'#f17275','SENSOR FAULT':'#f17275',CONGESTED:'#f2b45d',BACKPRESSURE:'#f2b45d',SLOW:'#f2b45d',STARVED:'#697e90',STOPPED:'#697e90'};
|
|
9
|
+
let topo=null, state=null, selected=null, region='ALL', current={...FULL}, animFrame=0, lastRevision=-1;
|
|
10
|
+
function svg(tag,attrs={},parent){const n=document.createElementNS(NS,tag);Object.entries(attrs).forEach(([k,v])=>n.setAttribute(k,String(v)));if(parent)parent.appendChild(n);return n;}
|
|
11
|
+
function label(parent,x,y,text,cls,anchor){const n=svg('text',{x,y,class:cls,...(anchor?{'text-anchor':anchor}:{})},parent);n.textContent=text;return n;}
|
|
12
|
+
function prettyStatus(s){return s==='SENSOR FAULT'?'SENSOR':s;}
|
|
13
|
+
function severity(s){return ['JAM','FAULT','SENSOR FAULT'].includes(s)?'fault':['BACKPRESSURE','CONGESTED','SLOW'].includes(s)?'warn':['STOPPED','STARVED'].includes(s)?'off':'';}
|
|
14
|
+
function equipmentMap(){
|
|
15
|
+
const zones=$('zonesLayer');const routes=$('routeLayer');const details=$('equipmentExtras');const labels=$('sectionLayer');
|
|
16
|
+
for(const z of topo.zones){svg('rect',{class:'zonerect',x:z.x,y:z.y,width:z.width,height:z.height,rx:13},zones);
|
|
17
|
+
label(zones,z.x+18,z.y+28,z.name,'zoneheader');label(zones,z.x+18,z.y+48,z.sub,'zonesub');}
|
|
18
|
+
// Inbound dock outlines and terminal boxes: reference geometry only, not separately floating equipment cards.
|
|
19
|
+
for(const d of [{y:225,t:'DOCK A / D01'},{y:462,t:'DOCK B / D02'}]){
|
|
20
|
+
svg('rect',{x:80,y:d.y-36,width:62,height:72,rx:4,class:'dockshape'},details);
|
|
21
|
+
for(let n=0;n<4;n++)svg('line',{x1:88,y1:d.y-25+n*16,x2:119,y2:d.y-25+n*16,stroke:'#527486','stroke-width':2},details);
|
|
22
|
+
label(details,108,d.y-52,d.t,'docktext','middle');}
|
|
23
|
+
for(const d of [{x:1305,y:215,t:'LANE 01'},{x:1305,y:463,t:'LANE 02'},{x:1305,y:565,t:'PRIORITY'},{x:1305,y:340,t:'NO-READ'}]){
|
|
24
|
+
svg('rect',{x:d.x-24,y:d.y-25,width:37,height:50,rx:4,class:'dockshape'},details);
|
|
25
|
+
label(details,d.x-7,d.y-32,d.t,'docktext','middle');}
|
|
26
|
+
// Scan-tunnel gantry is purely a physical symbol; scanner state is surfaced via CV107.
|
|
27
|
+
svg('path',{d:'M775 304V376 M814 304V376 M775 304H814',class:'scannericon'},details);
|
|
28
|
+
label(details,792,395,'SCAN / DWS','directionnote','middle');
|
|
29
|
+
label(details,703,416,'MERGE →','directionnote');
|
|
30
|
+
label(details,914,273,'HIGH SPEED SORTER →','directionnote');
|
|
31
|
+
label(details,1190,614,'OUTBOUND DISPATCH →','directionnote');
|
|
32
|
+
for(const c of topo.sections){
|
|
33
|
+
const g=svg('g',{class:'eq-route running',id:`eq-${c.id}`,tabindex:0,role:'button','aria-label':`Inspect ${c.id}, ${c.name}`},routes);
|
|
34
|
+
for(const [cl,attrs] of [['basetrack',{}],['belt',{}],['slats',{}],['flowline',{}],['edge',{}],['hitpath',{}]]){
|
|
35
|
+
svg('path',{d:c.path,class:cl,...attrs},g);
|
|
36
|
+
}
|
|
37
|
+
const box=svg('g',{class:'cargo'},g);svg('rect',{x:-6,y:-5,width:13,height:10,rx:1.5,class:'dotpack'},box);
|
|
38
|
+
svg('animateMotion',{path:c.path,dur:(2.7+(Number(c.id.slice(2))%4)*.36)+'s',begin:((-Number(c.id.slice(2))%7)*.28)+'s',repeatCount:'indefinite',rotate:'auto'},box);
|
|
39
|
+
const badge=svg('g',{class:'equip-pill',transform:`translate(${c.label[0]-37},${c.label[1]-13})`},labels);
|
|
40
|
+
badge.dataset.equipment=c.id;
|
|
41
|
+
svg('rect',{width:75,height:26,rx:5,class:'pill-plate'},badge);
|
|
42
|
+
svg('rect',{x:7,y:10,width:6,height:6,rx:1,class:'pill-dot'},badge);
|
|
43
|
+
label(badge,18,17,c.id,'pill-id');
|
|
44
|
+
const open=()=>focusEquipment(c.id);
|
|
45
|
+
g.addEventListener('click',open);g.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();open();}});
|
|
46
|
+
badge.addEventListener('click',open);badge.style.setProperty('--eq-color',COLORS.RUNNING);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function limitBox(b){const w=Math.max(235,Math.min(1400,b.w)),h=Math.max(160,Math.min(700,b.h));return{x:Math.min(1400-w,Math.max(0,b.x)),y:Math.min(700-h,Math.max(0,b.y)),w,h};}
|
|
50
|
+
function moveTo(box,animate=true){let target=limitBox(box);cancelAnimationFrame(animFrame);if(!animate){current=target;drawBox();return;}const from={...current};const start=performance.now();const dur=320;
|
|
51
|
+
function tick(t){let p=Math.min(1,(t-start)/dur);p=1-Math.pow(1-p,3);current={x:from.x+(target.x-from.x)*p,y:from.y+(target.y-from.y)*p,w:from.w+(target.w-from.w)*p,h:from.h+(target.h-from.h)*p};drawBox();if(p<1)animFrame=requestAnimationFrame(tick);}
|
|
52
|
+
animFrame=requestAnimationFrame(tick);}
|
|
53
|
+
function drawBox(){$('factoryMap').setAttribute('viewBox',`${current.x.toFixed(1)} ${current.y.toFixed(1)} ${current.w.toFixed(1)} ${current.h.toFixed(1)}`);}
|
|
54
|
+
function focusEquipment(id){if(!topo.sections.some(c=>c.id===id))return;selected=id;region='ALL';document.querySelectorAll('.tab').forEach(b=>b.classList.toggle('active',b.dataset.area==='ALL'));
|
|
55
|
+
const c=topo.sections.find(c=>c.id===id),group=$(`eq-${id}`),path=group.querySelector('path');const bounds=path.getBBox();
|
|
56
|
+
const centerX=bounds.x+bounds.width/2,centerY=bounds.y+bounds.height/2;
|
|
57
|
+
const width=Math.min(730,Math.max(460,bounds.width+340)),height=Math.max(300,width*.68);
|
|
58
|
+
moveTo({x:centerX-width/2,y:centerY-height/2,w:width,h:height});
|
|
59
|
+
document.querySelectorAll('.eq-route').forEach(n=>n.classList.toggle('selected',n.id===`eq-${id}`));
|
|
60
|
+
$('mapTitle').textContent=`Equipment inspection · ${id}`;$('mapSub').textContent=`${c.name} / ${c.area} · faceplate shown at right`;
|
|
61
|
+
renderSide();}
|
|
62
|
+
function setArea(area){selected=null;region=area;document.querySelectorAll('.eq-route').forEach(n=>n.classList.remove('selected'));
|
|
63
|
+
document.querySelectorAll('.tab').forEach(b=>b.classList.toggle('active',b.dataset.area===area));
|
|
64
|
+
$('mapTitle').textContent=area==='ALL'?'Material flow & equipment status':`${topo.zones.find(z=>z.id===area).name} · zone overview`;
|
|
65
|
+
$('mapSub').textContent=area==='ALL'?'Inbound → induction → sortation → outbound · select a conveyor to inspect':'Click a connected conveyor segment to open equipment diagnostics';
|
|
66
|
+
moveTo(area==='ALL'?FULL:ZOOMS[area]);renderSide();}
|
|
67
|
+
function zoomAt(factor,cx=current.x+current.w/2,cy=current.y+current.h/2){const w=current.w*factor,h=current.h*factor;moveTo({x:cx-w/2,y:cy-h/2,w,h},false);}
|
|
68
|
+
function setClock(){const now=new Date();$('clock').textContent=now.toLocaleTimeString([], {hour12:false});}
|
|
69
|
+
function paint(){if(!state)return;const uBy=Object.fromEntries(state.units.map(x=>[x.id,x]));
|
|
70
|
+
for(const c of topo.sections){const u=uBy[c.id],g=$(`eq-${c.id}`);if(!g)continue;g.style.setProperty('--eq-color',COLORS[u.status]||COLORS.RUNNING);
|
|
71
|
+
g.classList.toggle('running',u.status==='RUNNING'||u.status==='SLOW');g.querySelector('.cargo').style.display=u.status==='RUNNING'||u.status==='SLOW'||u.status==='CONGESTED'?'':'none';
|
|
72
|
+
const pill=document.querySelector(`.equip-pill[data-equipment="${c.id}"]`);if(pill)pill.style.setProperty('--eq-color',COLORS[u.status]);
|
|
73
|
+
g.setAttribute('aria-label',`Inspect ${c.id}: ${u.name}. ${u.status}`);
|
|
74
|
+
}
|
|
75
|
+
const o=state.overview;
|
|
76
|
+
$('healthValue').textContent=o.status==='RUNNING'?'OPERATIONAL':o.status;
|
|
77
|
+
$('healthDot').className='healthdot '+(o.status==='RUNNING'?'running':o.status==='ALARM'?'fault':'attention');
|
|
78
|
+
$('healthNote').textContent=o.status==='RUNNING'?'All monitored devices nominal':`${o.affected_units} equipment in non-nominal condition`;
|
|
79
|
+
$('rateValue').textContent=o.throughput_pph.toLocaleString();$('rateMeter').style.width=`${Math.round(o.throughput_pph/o.capacity_pph*100)}%`;
|
|
80
|
+
$('parcelsValue').textContent=o.parcels_in_system;$('availableValue').textContent=o.healthy_units;$('availableSub').textContent=`of ${o.total_units} conveyors`;
|
|
81
|
+
$('alarmValue').textContent=o.active_alarms;$('alarmNote').textContent=o.active_alarms?'Investigate red equipment paths':'No critical equipment alarms';
|
|
82
|
+
$('summaryStatus').textContent=`${o.healthy_units} / ${o.total_units} sections running normally`;
|
|
83
|
+
$('summaryFlow').textContent=o.affected_units?`${o.affected_units} sections affected · status propagated across connected routing`:'2 inbound sources · 3 outbound lanes · 1 exception path';
|
|
84
|
+
renderSide();renderEvents();}
|
|
85
|
+
function renderEvents(){if(!state)return;const ev=state.events?.[0];$('events').innerHTML=ev?`<span class="eventlevel ${esc(ev.level)}">${esc(ev.level.toUpperCase())}</span><span>${esc(ev.asset)} · ${esc(ev.message)}</span>`:'<span>No system events.</span>';}
|
|
86
|
+
function renderSide(){if(!state)return;
|
|
87
|
+
if(!selected){
|
|
88
|
+
const items=state.regions.map((r,i)=>`<div class="arearow" data-area="${esc(r.id)}" role="button" tabindex="0"><span class="areacode">0${i+1}</span><div class="areadetails"><span class="areaname">${esc(topo.zones[i].name.slice(5))}</span><span class="areasmall">${r.total-r.attention} / ${r.total} sections nominal</span></div><strong class="areastatus ${r.alarms?'fault':r.attention?'warn':''}">${r.alarms?'ALARM':r.attention?'ATTENTION':'NORMAL'} →</strong></div>`).join('');
|
|
89
|
+
let faultUnits=state.units.filter(u=>u.status!=='RUNNING').sort((a,b)=>Number(['JAM','FAULT','SENSOR FAULT'].includes(b.status))-Number(['JAM','FAULT','SENSOR FAULT'].includes(a.status)));
|
|
90
|
+
const cards=faultUnits.length?faultUnits.slice(0,3).map(u=>`<div class="attentioncard ${severity(u.status)}" data-id="${esc(u.id)}" role="button" tabindex="0"><strong>${esc(u.id)} · ${esc(prettyStatus(u.status))}</strong><small>${esc(u.name)} · CLICK TO INSPECT →</small></div>`).join(''):'<div class="nominalbox"><i>✓</i>No equipment exceptions detected in the synthetic model.</div>';
|
|
91
|
+
$('insight').innerHTML=`<div class="defaultpanel"><header class="sideheader"><span class="pagenum">02 / NETWORK INSIGHTS</span><h2>Operational status</h2><p>Locate bottlenecks before opening a faceplate.</p></header><div class="sidecontent"><div class="sidesection"><div class="sectionrow"><h3>Area health</h3><span class="supmeta">4 ZONES</span></div>${items}</div><div class="sidesection"><div class="sectionrow"><h3>Attention required</h3><span class="supmeta">${state.overview.affected_units} DEVICES</span></div><div class="attentionItems">${cards}</div></div><div class="sidesection"><div class="sectionrow"><h3>Performance snapshot</h3><span class="supmeta">SYNTHETIC</span></div><div class="performance"><div class="performancebar"><span>Scanner read rate</span><strong>${state.overview.scan_read_pct}%</strong></div><div class="meter"><span style="width:${state.overview.scan_read_pct}%"></span></div><div class="performancebar"><span>Throughput / capacity</span><strong>${Math.round(state.overview.throughput_pph/state.overview.capacity_pph*100)}%</strong></div><div class="meter"><span style="width:${state.overview.throughput_pph/state.overview.capacity_pph*100}%"></span></div></div></div></div></div>`;
|
|
92
|
+
$('insight').querySelectorAll('[data-area]').forEach(e=>{e.onclick=()=>setArea(e.dataset.area);e.onkeydown=ev=>{if(ev.key==='Enter')setArea(e.dataset.area)}});
|
|
93
|
+
$('insight').querySelectorAll('[data-id]').forEach(e=>{e.onclick=()=>focusEquipment(e.dataset.id);e.onkeydown=ev=>{if(ev.key==='Enter')focusEquipment(e.dataset.id)}});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const u=state.units.find(x=>x.id===selected);if(!u)return;const sev=severity(u.status);
|
|
97
|
+
const speedPct=Math.min(100,Math.round(u.speed_mpm/u.nominal_speed_mpm*100));const yn=x=>x?'ON':'OFF';
|
|
98
|
+
const sensor=(s,name)=>`<div class="sensorline"><span class="sensorled ${s.state==='BAD QUALITY'?'bad':s.state!=='CLEAR'?'detected':''}"></span><div><strong>${esc(s.id)}</strong><small>${name} photoeye</small></div><b>${esc(s.state)}</b></div>`;
|
|
99
|
+
$('insight').innerHTML=`<div class="faceheader"><button id="backToMap" class="faceback">← RETURN TO OVERVIEW</button><span class="pagenum">02 / EQUIPMENT FACEPLATE</span><div class="faceheadrow"><h2>${esc(u.id)}</h2><span class="statebadge ${sev}">${esc(u.status)}</span></div><p class="facename">${esc(u.name)} · ${esc(u.area)}</p></div><div class="facebody"><div class="facespeed"><span class="cap">MEASURED BELT SPEED / SIMULATED</span><div class="speednumber">${u.speed_mpm.toFixed(1)} <small>m / min</small></div><div class="meter"><span style="width:${speedPct}%"></span></div><span class="refer">Nominal ${u.nominal_speed_mpm.toFixed(1)} m/min</span></div><div class="facegroup"><div class="grouphead">MOTOR & VFD <span>${esc(u.motor.id)} / ${esc(u.vfd.id)}</span></div><div class="facegrid"><div class="facecell"><small>RUN COMMAND</small><strong>${yn(u.motor.run_command)}</strong></div><div class="facecell"><small>RUN FEEDBACK</small><strong>${yn(u.motor.run_feedback)}</strong></div><div class="facecell"><small>VFD FREQUENCY</small><strong>${u.vfd.frequency_hz.toFixed(1)} Hz</strong></div><div class="facecell"><small>DRIVE FAULT</small><strong>${yn(u.vfd.drive_fault)} · ${esc(u.vfd.fault_code)}</strong></div><div class="facecell"><small>MOTOR CURRENT</small><strong>${u.motor.current_a.toFixed(1)} A</strong></div><div class="facecell"><small>EST. SECTION RATE</small><strong>${u.rate_pph.toLocaleString()} pph</strong></div></div></div><div class="facegroup"><div class="grouphead">FIELD PHOTOEYES <span>SIMULATED I/O</span></div>${sensor(u.sensors.infeed,'Infeed')}${sensor(u.sensors.outfeed,'Outfeed')}</div><div class="facegroup"><div class="grouphead">DIAGNOSTICS <span>QUALITY / ${esc(u.quality)}</span></div><div class="diag ${sev}">${esc(u.diagnostic)}</div></div><div class="connections"><div><span>UPSTREAM</span><strong>${u.upstream.length?u.upstream.map(esc).join(', '):'RECEIVING SOURCE'}</strong></div><div><span>DOWNSTREAM</span><strong>${u.downstream.length?u.downstream.map(esc).join(', '):'OUTBOUND TERMINAL'}</strong></div></div><div class="facebottom">Read-only engineering demonstration. This screen does not reset alarms or command equipment.</div></div>`;
|
|
100
|
+
$('backToMap').onclick=()=>setArea('ALL');
|
|
101
|
+
}
|
|
102
|
+
async function poll(){try{const response=await fetch('/api/state',{cache:'no-store'});if(!response.ok)throw Error(`HTTP ${response.status}`);const payload=await response.json();if(!payload.meta.demo||payload.meta.connected_to_plc!==false)throw Error('Unexpected mode');$('offline').hidden=true;state=payload;if(payload.meta.revision!==lastRevision){lastRevision=payload.meta.revision;paint();}}catch(err){$('offline').hidden=false;$('summaryStatus').textContent='Simulation API unavailable';}}
|
|
103
|
+
function configureMap(){document.querySelectorAll('.tab').forEach(b=>b.addEventListener('click',()=>setArea(b.dataset.area)));
|
|
104
|
+
$('fitBtn').onclick=()=>setArea('ALL');$('zoomPlus').onclick=()=>zoomAt(.72);$('zoomMinus').onclick=()=>zoomAt(1.35);
|
|
105
|
+
$('navConveyors').onclick=()=>setArea('ALL');$('navAlarms').onclick=()=>{document.getElementById('eventbar').scrollIntoView({behavior:'smooth'});};
|
|
106
|
+
window.addEventListener('keydown',e=>{if(e.key==='Escape')setArea('ALL');if(e.key==='+'||e.key==='=')zoomAt(.78);if(e.key==='-')zoomAt(1.28);});
|
|
107
|
+
const map=$('factoryMap');map.addEventListener('wheel',e=>{e.preventDefault();const box=map.getBoundingClientRect(),rx=(e.clientX-box.left)/box.width,ry=(e.clientY-box.top)/box.height;
|
|
108
|
+
const centerX=current.x+current.w*rx,centerY=current.y+current.h*ry;const f=e.deltaY>0?1.18:.84;const w=current.w*f,h=current.h*f;moveTo({x:centerX-w*rx,y:centerY-h*ry,w,h},false);},{passive:false});
|
|
109
|
+
let start=null;map.addEventListener('pointerdown',e=>{if(e.button!==0||e.target.closest('.eq-route')||e.target.closest('.equip-pill'))return;start={x:e.clientX,y:e.clientY,view:{...current}};map.setPointerCapture(e.pointerId);map.classList.add('dragging');});
|
|
110
|
+
map.addEventListener('pointermove',e=>{if(!start)return;const r=map.getBoundingClientRect();moveTo({...start.view,x:start.view.x-(e.clientX-start.x)*start.view.w/r.width,y:start.view.y-(e.clientY-start.y)*start.view.h/r.height},false);});
|
|
111
|
+
map.addEventListener('pointerup',()=>{start=null;map.classList.remove('dragging')});map.addEventListener('pointercancel',()=>{start=null;map.classList.remove('dragging')});
|
|
112
|
+
}
|
|
113
|
+
async function init(){setClock();setInterval(setClock,1000);const r=await fetch('/topology.json');if(!r.ok)throw Error('No topology');topo=await r.json();equipmentMap();configureMap();drawBox();await poll();setInterval(poll,1400);}
|
|
114
|
+
init().catch(err=>{$('offline').hidden=false;$('offline').textContent='Demo initialization failed: '+err.message;});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
3
|
+
<title>DevAgent | Distribution Operations Overview</title><link rel="stylesheet" href="/style.css"><script defer src="/app.js"></script></head>
|
|
4
|
+
<body class="operator"><div class="shell">
|
|
5
|
+
<aside class="navrail" aria-label="Operator navigation"><div class="mark">D<span>●</span></div><div class="navicons"><button class="navico selected" title="Facility overview" aria-label="Facility overview">▦</button><button class="navico" title="Conveyor network" id="navConveyors" aria-label="Fit conveyor network">⌁</button><button class="navico" title="Alarms" id="navAlarms" aria-label="View alarms">♧</button></div><div class="navfoot">OP<br>01</div></aside>
|
|
6
|
+
<div class="maincol"><header class="topbar"><div class="heading-brand"><span class="eyebrow">DEVAGENT / INDUSTRIAL OPERATIONS</span><strong>Fulfillment Control Center <span class="tinychev">⌄</span></strong></div><div class="toplinks"><span class="headtag">SITE ND-01</span><span class="headtag">SORTATION · AREA A</span><span class="demo"><i></i>LOCAL SIMULATION <small>NO PLC CONNECTION</small></span><span class="clock" id="clock">--:--:--</span><span class="avatar">OP</span></div></header>
|
|
7
|
+
<main class="workspace"><div class="pageintro"><div><span class="eyebrow">OPERATIONS <span class="dotsep">/</span> FACILITY VISIBILITY</span><h1>Warehouse overview</h1><p>Live-style system awareness across receiving, induction, sortation, and outbound.</p></div><div class="intro-actions"><span class="mode"><span class="pulsedot"></span> SIMULATED LIVE DATA</span></div></div>
|
|
8
|
+
<section class="metrics" aria-label="Facility KPIs"><article class="metric feature"><div class="key">SYSTEM HEALTH <span class="metricicon">◈</span></div><div class="bigrow"><span id="healthDot" class="healthdot"></span><strong id="healthValue">CONNECTING</strong></div><span class="smallmetric" id="healthNote">Connecting to local demo</span></article><article class="metric"><div class="key">CURRENT THROUGHPUT <span>↗</span></div><div class="bigrow"><strong id="rateValue">—</strong><em>parcels / hr</em></div><div class="meter"><span id="rateMeter"></span></div><span class="smallmetric">Capacity 9,200 pph · illustrative</span></article><article class="metric"><div class="key">PARCELS ON SYSTEM <span>▣</span></div><div class="bigrow"><strong id="parcelsValue">—</strong><em>tracked</em></div><span class="smallmetric">Synthetic WCS tracking volume</span></article><article class="metric"><div class="key">EQUIPMENT AVAILABLE <span>◉</span></div><div class="bigrow"><strong id="availableValue">—</strong><em id="availableSub">of 13 conveyors</em></div><span class="smallmetric">Based on simulated device state</span></article><article class="metric"><div class="key">ACTIVE ALARMS <span class="warnicon">!</span></div><div class="bigrow"><strong id="alarmValue">—</strong><em>critical</em></div><span class="smallmetric" id="alarmNote">No active faults</span></article></section>
|
|
9
|
+
<div class="contentgrid"><section class="network box" aria-label="Facility conveyor layout"><header class="panehead"><div><span class="pagenum">01 / FACILITY MAP</span><h2 id="mapTitle">Material flow & equipment status</h2><p id="mapSub">Inbound → induction → sortation → outbound · select a conveyor to inspect</p></div><div class="maptools"><button type="button" id="zoomMinus" aria-label="Zoom out">−</button><button type="button" id="zoomPlus" aria-label="Zoom in">+</button><button type="button" class="fit" id="fitBtn">⤢ FIT VIEW</button></div></header>
|
|
10
|
+
<div class="zonenav" id="zoneTabs"><button class="tab active" data-area="ALL">All areas</button><button class="tab" data-area="INBOUND">Receiving</button><button class="tab" data-area="INDUCTION">Induction</button><button class="tab" data-area="SORTATION">Sortation</button><button class="tab" data-area="DISPATCH">Outbound</button></div>
|
|
11
|
+
<div class="mapwrap" id="mapWrap"><div class="maptopleft"><span class="mapid">DC-01 <span class="sep">/</span> SORTATION FLOOR</span><span class="mapscale">SCHEMATIC · NOT TO SCALE</span></div>
|
|
12
|
+
<svg id="factoryMap" viewBox="0 0 1400 700" role="img" aria-label="Connected receiving induction sortation outbound conveyor network. Click conveyor for equipment faceplate.">
|
|
13
|
+
<defs><pattern id="floorgrid" width="25" height="25" patternUnits="userSpaceOnUse"><path d="M25 0H0V25" fill="none" stroke="#2b4053" stroke-width=".65" opacity=".65"/></pattern><filter id="trackShadow" x="-35%" y="-35%" width="170%" height="170%"><feDropShadow dx="0" dy="3" stdDeviation="4" flood-color="#030b12" flood-opacity=".6"/></filter></defs>
|
|
14
|
+
<rect x="0" y="0" width="1400" height="700" fill="url(#floorgrid)"/>
|
|
15
|
+
<g id="zonesLayer"></g><g id="routeLayer"></g><g id="equipmentExtras"></g><g id="sectionLayer"></g>
|
|
16
|
+
</svg>
|
|
17
|
+
<div class="maplegend"><span><i class="ld green"></i>Running</span><span><i class="ld amber"></i>Attention / blocked</span><span><i class="ld red"></i>Fault / jam</span><span><i class="ld slate"></i>Stopped / starved</span></div><span class="maphint" id="mapHint">CLICK A CONVEYOR · SCROLL TO ZOOM · DRAG TO PAN</span><div class="offline" id="offline" hidden>Local demo server offline · values unavailable</div></div>
|
|
18
|
+
<div class="networkfoot"><div><span class="pointrunning"></span><span id="summaryStatus">13 devices in model</span><span class="divider">│</span><span id="summaryFlow">Two inbound sources · three outbound destinations · one exception transfer</span></div><span>OPERATOR OVERVIEW • READ ONLY</span></div></section>
|
|
19
|
+
<aside class="insight box" id="insight" aria-live="polite"><div class="defaultpanel"><header class="sideheader"><span class="pagenum">02 / NETWORK INSIGHTS</span><h2>Operational status</h2><p>Locate bottlenecks before opening a faceplate.</p></header><div class="sidecontent"><div class="sidesection"><div class="sectionrow"><h3>Area health</h3><span class="supmeta">4 ZONES</span></div><div id="areaHealth"></div></div><div class="sidesection"><div class="sectionrow"><h3>Attention required</h3><span class="supmeta" id="alertCountSmall">0 EVENTS</span></div><div id="attentionItems" class="attentionItems"></div></div><div class="sidesection"><div class="sectionrow"><h3>Performance snapshot</h3><span class="supmeta">SIMULATED</span></div><div class="performance"><div class="performancebar"><span>Scanner read rate</span><strong id="scanRead">99.3%</strong></div><div class="meter"><span id="scanMeter" style="width:99%"></span></div><div class="performancebar"><span>Line utilization</span><strong id="lineUtil">79%</strong></div><div class="meter"><span id="utilMeter" style="width:79%"></span></div></div></div></div></div></aside></div>
|
|
20
|
+
<section class="eventbar box" id="eventbar"><div class="eventtitle"><span class="pagenum">03 / EVENT STREAM</span><strong>Recent activity</strong></div><div id="events" class="eventline"><span>Awaiting simulation data…</span></div><span class="eventsource">DEMO EVENTS · LOCAL</span></section>
|
|
21
|
+
<div class="footnote"><span>DEVAGENT HMI CONCEPT V8</span><span>SIMULATED DATA ONLY · NOT A SAFETY SYSTEM · NO EQUIPMENT CONTROL</span></div>
|
|
22
|
+
</main></div></div></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>DevAgent | Engineering Scenario Console</title><link rel="stylesheet" href="/style.css"><script defer src="/simulator.js"></script></head><body class="simbody"><main class="simlayout"><header class="simheader"><div><span class="eyebrow">DEVAGENT / ENGINEERING TEST ENVIRONMENT</span><h1>Scenario controller</h1><p>This separate page changes synthetic state only. It cannot control a PLC, motor or VFD.</p></div><a class="outline-link" href="/index.html" target="_blank" rel="noopener">OPEN OPERATOR OVERVIEW ↗</a></header><div class="simguard"><span>ⓘ DEMO / SANDBOX</span><strong>All changes affect only the local browser simulation. No physical commands are issued.</strong></div><section class="simbox"><div><span class="pagenum">TEST INPUTS / 01</span><h2>Inject an operating condition</h2><p>Keep the operator HMI open in another tab. Observe connected conveyor statuses, flow, KPIs and diagnostics update.</p></div><label class="fieldlabel" for="target">TARGET CONVEYOR</label><select id="target"></select><label class="fieldlabel" for="scenario">SIMULATED SCENARIO</label><select id="scenario"><option value="jam">Conveyor jam</option><option value="vfd_fault">VFD fault F003</option><option value="photoeye_fault">Photoeye bad quality</option><option value="congestion">Downstream congestion</option><option value="slow">Low belt speed</option><option value="line_stop">Facility line stop</option></select><div class="simactions"><button id="inject" class="primarybtn">APPLY TEST SCENARIO</button><button id="restore" class="secondarybtn">RESTORE NOMINAL</button></div><div class="response" id="response">Ready for local testing.</div></section><section class="simbox slim"><span class="pagenum">CURRENT SYNTHETIC STATE / 02</span><div class="simstatus"><div><small>Active scenario</small><strong id="currentScenario">—</strong></div><div><small>Selected equipment</small><strong id="currentTarget">—</strong></div><div><small>Revision</small><strong id="currentRevision">—</strong></div></div></section><footer>READ-ONLY OPERATOR HMI • SYNTHETIC ENGINEERING CONSOLE • NOT FOR COMMISSIONING</footer></main></body></html>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const $ = id => document.getElementById(id);
|
|
3
|
+
async function updateState(){ const r=await fetch('/api/state',{cache:'no-store'}); if(!r.ok)throw Error('State unavailable'); const s=await r.json(); $('currentScenario').textContent=s.overview.scenario.replaceAll('_',' ').toUpperCase();$('currentTarget').textContent=s.overview.target;$('currentRevision').textContent=s.meta.revision; }
|
|
4
|
+
async function send(scenario){$('response').textContent='Submitting to local demo server…';try{const r=await fetch('/api/scenario',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({scenario,target:$('target').value})});const s=await r.json();if(!r.ok)throw Error(s.error||'Request failed');$('response').textContent=`✓ Applied ${scenario} to ${$('target').value} · revision ${s.meta.revision}`;await updateState();}catch(e){$('response').textContent='⚠ '+e.message;}}
|
|
5
|
+
async function init(){const t=await(await fetch('/topology.json')).json();for(const c of t.sections){const opt=document.createElement('option');opt.value=c.id;opt.textContent=`${c.id} · ${c.name}`;$('target').append(opt);}$('target').value='CV108';$('inject').onclick=()=>send($('scenario').value);$('restore').onclick=()=>send('normal');await updateState();setInterval(()=>updateState().catch(()=>{}),1500);}
|
|
6
|
+
init().catch(e=>{$('response').textContent='⚠ Cannot load: '+e.message;});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
:root{--bg:#0b141e;--panel:#13212d;--panel2:#172837;--line:#294052;--muted:#87a0af;--text:#e8f1f5;--green:#32cba5;--amber:#f2b45d;--red:#f17275;--blue:#66bcf6;--slate:#697e90;--mono:'IBM Plex Mono','Liberation Mono',monospace;--sans:'Inter','Segoe UI',Arial,sans-serif}
|
|
2
|
+
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;color:var(--text);background:var(--bg);font-family:var(--sans);font-size:14px}button,a,select{font:inherit}button{cursor:pointer}a{text-decoration:none;color:inherit}button:focus-visible,a:focus-visible,select:focus-visible{outline:2px solid var(--blue);outline-offset:3px}[hidden]{display:none!important}
|
|
3
|
+
.shell{display:flex;min-height:100vh}.navrail{width:67px;flex:0 0 67px;background:#0b1822;border-right:1px solid #273c4b;display:flex;align-items:center;flex-direction:column;position:sticky;top:0;height:100vh;z-index:5}.mark{font-family:var(--mono);font-size:20px;font-weight:600;letter-spacing:-3px;margin:24px 0 47px}.mark span{color:var(--green);font-size:9px;position:relative;left:2px;top:-6px}.navicons{display:grid;gap:14px;width:100%;justify-content:center}.navico{width:46px;height:47px;border:0;border-radius:8px;color:#7795a4;background:none;font-size:25px}.navico.selected{background:#173a43;color:#5cdbb8;border-left:2px solid #37d6af}.navico:hover{background:#1b3544;color:#ebffff}.navfoot{margin-top:auto;margin-bottom:24px;font:600 11px/1.8 var(--mono);color:#587788;text-align:center}.maincol{flex:1;min-width:0}.topbar{height:76px;border-bottom:1px solid #274054;padding:0 35px;display:flex;align-items:center;justify-content:space-between;background:#101d29;gap:18px}.heading-brand{display:grid;gap:7px}.eyebrow,.pagenum,.key,.headtag,.smallmetric,.supmeta,.fieldlabel{font-family:var(--mono);letter-spacing:1px;font-size:10px}.eyebrow,.pagenum{color:#7fb0b9}.heading-brand strong{font-size:17px;font-weight:600}.tinychev{color:#5d8998;font-size:13px}.toplinks{display:flex;align-items:center;gap:22px}.headtag{color:#8fa4b3;white-space:nowrap}.demo{font:600 10px var(--mono);letter-spacing:.4px;color:#91d8c8;padding:9px 11px;border:1px solid #296251;background:#14332f;border-radius:5px;white-space:nowrap}.demo i{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--green);box-shadow:0 0 12px #35d7b9;margin-right:7px}.demo small{color:#83a7a4;font-size:9px;margin-left:8px}.clock{font:500 13px var(--mono);white-space:nowrap}.avatar{border:1px solid #426278;color:#b8d4dd;padding:10px;border-radius:50%;font:600 11px var(--mono)}.workspace{max-width:1940px;margin:auto;padding:30px 30px 20px}.pageintro{display:flex;align-items:flex-end;justify-content:space-between;gap:20px;margin-bottom:23px}.dotsep{padding:0 6px;color:#4b6375}.pageintro h1{font-size:31px;letter-spacing:-.8px;font-weight:600;margin:11px 0 6px}.pageintro p{color:#9cb0bb;margin:0;font-size:13px}.intro-actions{display:flex;align-items:center;gap:14px}.mode{font:600 10px var(--mono);letter-spacing:.55px;color:#9fd4c1;white-space:nowrap}.pulsedot{display:inline-block;height:7px;width:7px;background:var(--green);border-radius:50%;margin-right:6px;box-shadow:0 0 9px #39d8ae}.outline-link{border:1px solid #39586e;background:#162b39;padding:11px 15px;border-radius:5px;font:600 11px var(--mono);color:#bcd2de;white-space:nowrap}.outline-link:hover{border-color:#5dbda6;color:#fff}
|
|
4
|
+
.metrics{display:grid;grid-template-columns:1.12fr 1.22fr 1fr 1.15fr .85fr;gap:12px;margin-bottom:17px}.metric{min-width:0;background:#142430;border:1px solid #2c4353;border-radius:7px;padding:18px 19px 16px;height:132px}.metric.feature{border-top:2px solid var(--green);background:linear-gradient(110deg,#14332f,#142430 70%)}.key{display:flex;justify-content:space-between;gap:8px;color:#93aabb;font-weight:500;white-space:nowrap}.key span{font-size:15px;color:#648ba1}.key .warnicon{font-size:13px;color:var(--amber)}.bigrow{margin-top:14px;display:flex;align-items:baseline;gap:9px;white-space:nowrap}.bigrow strong{font-size:31px;line-height:1.14;letter-spacing:-1.3px;font-weight:600}.feature .bigrow strong{font-size:24px;letter-spacing:-.5px}.bigrow em{font:400 10px var(--mono);color:#829aaa;font-style:normal}.healthdot{height:12px;width:12px;background:var(--slate);display:inline-block;border-radius:50%;box-shadow:0 0 14px #52708077;align-self:center}.healthdot.running{background:var(--green);box-shadow:0 0 10px #31c9a877}.healthdot.fault{background:var(--red);box-shadow:0 0 9px #e5666677}.healthdot.attention{background:var(--amber)}.smallmetric{display:block;color:#849bab;margin-top:9px;letter-spacing:0;font-size:10px}.meter{height:4px;background:#263c4a;border-radius:9px;overflow:hidden}.meter span{height:100%;display:block;background:var(--green);width:0;transition:width .4s}.metric .meter{margin-top:8px}.metric:has(.meter) .smallmetric{margin-top:6px}
|
|
5
|
+
.contentgrid{display:grid;grid-template-columns:minmax(0,1fr) 337px;gap:16px}.box{border:1px solid #2c4354;border-radius:7px;background:var(--panel);overflow:hidden}.panehead{height:93px;padding:19px 21px 16px;display:flex;justify-content:space-between;align-items:center;gap:12px}.pagenum{color:#59bfae;font-weight:600;font-size:9px}.panehead h2,.sideheader h2{font-weight:600;font-size:18px;margin:5px 0}.panehead p,.sideheader p{color:#8ba4b3;font-size:12px;margin:3px 0 0}.maptools{display:flex;align-items:center;gap:6px}.maptools button{border:1px solid #375163;border-radius:4px;background:#1c3242;color:#d5e8ef;height:34px;min-width:35px;font:500 16px var(--mono)}.maptools button.fit{font:600 10px var(--mono);padding:0 11px}.maptools button:hover{background:#294758}.zonenav{height:43px;background:#122330;display:flex;align-items:stretch;gap:0;border-top:1px solid #293f4f;border-bottom:1px solid #293f4f;padding:0 10px}.tab{border:0;background:none;color:#92a8b7;padding:0 17px;font-size:12px;white-space:nowrap;border-bottom:2px solid transparent}.tab.active{color:#c8f4e9;border-bottom-color:var(--green);background:#1b3840}.tab:hover{color:white}
|
|
6
|
+
.mapwrap{position:relative;height:575px;background:#101e2b;overflow:hidden;user-select:none}.mapwrap svg{height:100%;width:100%;display:block;touch-action:none;cursor:grab}.mapwrap svg.dragging{cursor:grabbing}.maptopleft{position:absolute;top:15px;left:18px;right:18px;z-index:1;display:flex;justify-content:space-between;pointer-events:none}.mapid,.mapscale{font:600 10px var(--mono);letter-spacing:.6px;color:#7f9aaa}.mapid .sep{color:#4d7383;padding:0 6px}.maplegend{position:absolute;bottom:14px;left:16px;background:#102331e8;border:1px solid #2c4957;border-radius:5px;padding:9px 11px;display:flex;gap:15px;z-index:2}.maplegend span{display:flex;align-items:center;gap:7px;font:10px var(--mono);color:#b0c4ca;white-space:nowrap}.ld{width:9px;height:9px;border-radius:2px;background:var(--slate)}.ld.green{background:var(--green)}.ld.amber{background:var(--amber)}.ld.red{background:var(--red)}.maphint{position:absolute;bottom:21px;right:17px;font:600 9px var(--mono);letter-spacing:.6px;color:#779bab;pointer-events:none}.offline{position:absolute;left:25%;right:25%;top:44%;background:#58312c;color:#ffe9dc;border:1px solid #f17275;padding:16px;text-align:center;z-index:9}.networkfoot{min-height:56px;padding:0 18px;display:flex;align-items:center;justify-content:space-between;gap:10px;border-top:1px solid #293f4e;background:#152733;color:#a0b2bd;font-size:10px}.networkfoot>span{font:600 9px var(--mono);color:#64899a;white-space:nowrap}.networkfoot .divider{padding:0 12px;color:#456073}.pointrunning{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--green);margin-right:8px}.networkfoot b{font-weight:500;color:#e7eeee}
|
|
7
|
+
.zonerect{stroke:#30495a;stroke-dasharray:5 7;stroke-width:1.5;fill:#172d3b;fill-opacity:.4}.zoneheader{font:600 15px var(--mono);letter-spacing:1.1px;fill:#83a7b7}.zonesub{font:12px var(--sans);fill:#71909e}.eq-route{cursor:pointer;outline:none}.eq-route .basetrack{fill:none;stroke:#2f4554;stroke-width:43;stroke-linecap:butt;stroke-linejoin:round;filter:url(#trackShadow)}.eq-route .belt{fill:none;stroke:#203442;stroke-width:32;stroke-linejoin:round}.eq-route .slats{fill:none;stroke:#ffffff30;stroke-width:26;stroke-dasharray:2 11;stroke-linejoin:round}.eq-route .flowline{fill:none;stroke:var(--eq-color,#32cba5);stroke-width:4.5;stroke-dasharray:12 15;stroke-linejoin:round;animation:beltmove .7s linear infinite}.eq-route .edge{fill:none;stroke:var(--eq-color,#32cba5);stroke-width:2;stroke-linejoin:round;opacity:.55}.eq-route:not(.running) .flowline{animation-play-state:paused;stroke-dasharray:none;opacity:.9}.eq-route.selected .basetrack{stroke:#4e7891;stroke-width:48}.eq-route.selected .edge{stroke:#a5eaf8;opacity:1;stroke-width:4}.eq-route:focus .edge,.eq-route:hover .edge{stroke:#e3f7ff;stroke-width:4;opacity:1}.hitpath{fill:none;stroke:transparent;stroke-width:50;pointer-events:stroke}.equip-pill{cursor:pointer;pointer-events:all}.pill-plate{fill:#142938;stroke:#466173;stroke-width:1.5}.pill-id{font:600 13px var(--mono);fill:#eaf4fa;pointer-events:none}.pill-dot{fill:var(--eq-color);pointer-events:none}.selected .pill-plate{stroke:#abedff;stroke-width:2}.equip-pill:hover .pill-plate{stroke:#bfe1ec}.areaicon{fill:#243d4c;stroke:#597384;stroke-width:1.2}.buildingnote{font:600 12px var(--mono);letter-spacing:.5px;fill:#547c8d}.directionnote{font:11px var(--mono);fill:#73b6bf}.dotpack{fill:#e3b77e;stroke:#fff5d5;stroke-width:.8}.cargo{pointer-events:none;opacity:.85}.scannericon{stroke:#6cd7c0;stroke-width:2;fill:none}.dockshape{fill:#1a3340;stroke:#577485;stroke-width:1.5}.docktext{font:600 10px var(--mono);fill:#83a7b7}@keyframes beltmove{to{stroke-dashoffset:-27}}
|
|
8
|
+
.insight{min-height:767px}.sideheader{padding:20px 19px 17px;border-bottom:1px solid #2a4253}.sideheader h2{margin-top:9px}.sidecontent{padding:0 18px 17px}.sidesection{padding:19px 0;border-bottom:1px solid #294052}.sidesection:last-child{border-bottom:0}.sectionrow{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.sectionrow h3{font-size:12px;font-weight:600;margin:0}.supmeta{color:#7693a4;font-size:9px}.arearow{display:flex;align-items:center;gap:10px;padding:9px 0;cursor:pointer}.arearow:hover .areaname{color:white}.areacode{background:#1c3541;border:1px solid #365061;color:#9ac1cb;border-radius:4px;font:600 10px var(--mono);width:26px;height:25px;display:grid;place-items:center}.areadetails{flex:1;min-width:0}.areaname{font-size:12px;color:#d4e2e6}.areasmall{display:block;margin-top:3px;font:10px var(--mono);color:#7794a4}.areastatus{font:600 10px var(--mono);color:var(--green)}.areastatus.warn{color:var(--amber)}.areastatus.fault{color:var(--red)}.attentionItems{display:grid;gap:8px}.attentioncard{padding:12px;border:1px solid #315063;background:#1b3140;border-left:3px solid var(--amber);border-radius:3px;cursor:pointer}.attentioncard.fault{border-left-color:var(--red)}.attentioncard small{font:9px var(--mono);color:#a1bccb;display:block;margin-top:5px}.attentioncard strong{font-size:12px}.nominalbox{color:#9ab0b7;font-size:12px;line-height:1.5;padding:13px;background:#1b3540;border:1px solid #2e514c;border-radius:4px}.nominalbox i{color:var(--green);font-size:17px;font-style:normal;margin-right:7px}.performance{display:grid;gap:7px}.performancebar{display:flex;align-items:center;justify-content:space-between;margin:8px 0 1px;color:#97adbb;font-size:11px}.performancebar strong{color:#e6f2f5;font:600 11px var(--mono)}.performance .meter{height:5px}
|
|
9
|
+
/* The equipment faceplate reuses the right insight column, preserving map visibility. */
|
|
10
|
+
.faceheader{padding:18px 18px;border-bottom:1px solid #294354}.faceback{background:none;border:none;color:#84d7c7;font:600 11px var(--mono);padding:0;margin-bottom:17px}.faceheadrow{display:flex;align-items:center;justify-content:space-between;gap:8px}.faceheadrow h2{font:600 26px var(--mono);margin:4px 0}.facename{color:#91aaba;font-size:12px;margin:3px 0}.statebadge{padding:7px 9px;background:#1a3b34;border:1px solid #317d67;color:var(--green);font:600 10px var(--mono);white-space:nowrap;border-radius:3px}.statebadge.warn{color:var(--amber);background:#453727;border-color:#997343}.statebadge.fault{color:var(--red);background:#432e32;border-color:#9f4b50}.statebadge.off{color:#a4b3bb;background:#263442;border-color:#435466}.facebody{padding:17px 18px}.facespeed{background:#162e3b;border:1px solid #2d5260;padding:15px;border-radius:5px}.facespeed .cap{font:600 10px var(--mono);color:#8eaabb}.facespeed .speednumber{font-size:34px;letter-spacing:-1px;margin-top:6px}.speednumber small{font:12px var(--mono);color:#91adba}.facespeed .meter{margin:8px 0}.facespeed .refer{color:#7498a6;font:10px var(--mono)}.facegroup{margin-top:19px}.grouphead{display:flex;align-items:center;justify-content:space-between;font:600 10px var(--mono);letter-spacing:.3px;color:#9dc3cc;border-bottom:1px solid #2b4553;padding-bottom:9px}.grouphead span{color:#718c9c;font-size:9px}.facegrid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}.facecell{background:#1a303e;border:1px solid #2c4758;border-radius:3px;padding:11px 10px}.facecell small{color:#84a4b5;font:9px var(--mono);display:block;min-height:24px}.facecell strong{display:block;font:600 13px var(--mono);color:#ddebeb}.sensorline{display:flex;align-items:center;gap:9px;padding:11px 0;border-bottom:1px solid #293f4d}.sensorled{width:9px;height:9px;background:var(--green);border-radius:2px;flex:0 0 9px}.sensorled.bad{background:var(--red)}.sensorled.detected{background:var(--amber)}.sensorline div{flex:1}.sensorline strong{display:block;font:500 11px var(--mono)}.sensorline small{color:#7593a3;font-size:10px}.sensorline b{font:600 10px var(--mono);color:#b4c8d0}.diag{background:#183b34;border-left:3px solid var(--green);padding:12px;color:#bfe8dc;line-height:1.45;font-size:11px;margin-top:12px}.diag.warn{background:#3a3227;border-left-color:var(--amber);color:#f5d5a6}.diag.fault{background:#412a2f;border-left-color:var(--red);color:#ffd4cf}.connections{margin-top:18px;display:grid;grid-template-columns:1fr 1fr;gap:8px}.connections>div{padding:10px;background:#1a303c}.connections span{display:block;font:9px var(--mono);color:#7797a4;margin-bottom:6px}.connections strong{font:500 10px var(--mono);color:#bde2eb}.facebottom{font:10px var(--mono);color:#7796a6;margin-top:16px;line-height:1.5}
|
|
11
|
+
.eventbar{display:flex;align-items:center;margin-top:16px;padding:13px 19px;gap:21px;min-height:61px}.eventtitle{min-width:155px;display:grid;gap:5px;border-right:1px solid #344b5a;padding-right:15px}.eventtitle strong{font-size:13px}.eventline{min-width:0;display:flex;flex:1;gap:15px;overflow:hidden;color:#b1c7d0;white-space:nowrap}.eventline span{font:11px var(--mono);overflow:hidden;text-overflow:ellipsis}.eventline .eventlevel{color:var(--green)}.eventline .eventlevel.warning{color:var(--amber)}.eventline .eventlevel.alarm{color:var(--red)}.eventsource{font:9px var(--mono);color:#6b8a9c;white-space:nowrap}.footnote{display:flex;justify-content:space-between;font:9px var(--mono);letter-spacing:1px;color:#58798c;margin-top:19px}
|
|
12
|
+
/* Engineering sandbox */
|
|
13
|
+
.simbody{background:radial-gradient(ellipse at 15% 0,#173544,#0c1520 55%)}.simlayout{max-width:850px;margin:50px auto;padding:0 25px}.simheader{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-bottom:27px}.simheader h1{font-size:32px;font-weight:600;margin:12px 0}.simheader p{color:#a7b7c2;font-size:13px;max-width:460px;line-height:1.6}.simguard{padding:14px 18px;background:#183b33;border:1px solid #39745f;border-radius:5px;display:flex;gap:16px;font-size:12px;color:#acdacb;margin-bottom:16px}.simguard span{font:600 10px var(--mono);white-space:nowrap}.simguard strong{font-weight:500}.simbox{background:#142534;border:1px solid #345166;border-radius:6px;padding:28px 30px;margin-bottom:16px}.simbox h2{font-size:20px;margin:8px 0}.simbox p{max-width:640px;color:#99b0bd;line-height:1.65;font-size:13px;margin:0 0 25px}.fieldlabel{display:block;color:#8bb4c0;margin:22px 0 8px}.simbox select{display:block;width:100%;background:#10212d;color:#edf4f8;border:1px solid #45687b;padding:12px;border-radius:4px}.simactions{display:flex;gap:10px;margin-top:25px}.primarybtn,.secondarybtn{border-radius:4px;border:1px solid #3ba98e;padding:13px 20px;font:600 11px var(--mono);letter-spacing:.6px}.primarybtn{background:#25b99a;color:#081b20}.secondarybtn{background:#263844;color:#d8e8ee;border-color:#4a6675}.response{margin-top:16px;padding:14px;background:#1c3341;color:#a6c6cf;font:11px var(--mono)}.simbox.slim{padding:22px 30px}.simstatus{display:flex;justify-content:space-between;margin-top:17px}.simstatus>div{flex:1}.simstatus small{display:block;color:#8aa8b7;font:10px var(--mono);margin-bottom:11px}.simstatus strong{font:600 13px var(--mono)}.simlayout footer{color:#7295a3;font:10px var(--mono);margin:24px 0;text-align:center}
|
|
14
|
+
@media(max-width:1430px){.metrics{grid-template-columns:repeat(5,minmax(0,1fr))}.metric{padding:16px 13px}.key{font-size:9px}.bigrow strong{font-size:26px}.contentgrid{grid-template-columns:minmax(0,1fr) 300px}.mapwrap{height:535px}.insight{min-height:725px}.toplinks{gap:12px}.headtag:first-child{display:none}.networkfoot>span{display:none}}
|
|
15
|
+
@media(max-width:1080px){.metrics{grid-template-columns:repeat(3,minmax(0,1fr))}.contentgrid{grid-template-columns:1fr}.insight{min-height:auto}.sidecontent{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}.sidesection{border:0}.toplinks .headtag{display:none}.mapwrap{height:560px}}
|
|
16
|
+
@media(max-width:730px){.navrail{display:none}.topbar{padding:0 16px}.workspace{padding:20px 13px}.toplinks .demo small,.toplinks .clock{display:none}.heading-brand strong{font-size:13px}.pageintro{align-items:flex-start}.pageintro h1{font-size:25px}.intro-actions .mode{display:none}.metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.metric{height:119px}.metric.feature{grid-column:span 2}.panehead{height:auto;min-height:96px;padding:16px}.panehead h2{font-size:15px}.panehead p{font-size:10px}.maptools{flex:0 0 auto}.zonenav{overflow-x:auto}.tab{padding:0 11px;font-size:11px}.mapwrap{height:455px}.maplegend{gap:8px;left:7px;bottom:9px;padding:7px}.maplegend span{font-size:8px}.maphint{display:none}.sidecontent{display:block}.networkfoot{font-size:9px}.eventsource{display:none}.footnote{gap:20px;font-size:8px}.simheader{display:block}.simguard{display:block}.simguard strong{display:block;margin-top:8px}}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
id,name,kind,floor,zone,x,y,z
|
|
2
|
+
INFEED01,Receiving infeed,conveyor,1,ZONE-F1,-18,0,0
|
|
3
|
+
CV101,Line conveyor 101,conveyor,1,ZONE-F1,-11,0,0
|
|
4
|
+
DWS01,Dimension-weight-scan,scanner,1,ZONE-F1,-7,0,-2
|
|
5
|
+
PE101,Infeed photoeye,photoeye,1,ZONE-F1,-10,0,2
|
|
6
|
+
CV102,Main feed conveyor,conveyor,1,ZONE-F1,-4,0,0
|
|
7
|
+
SPIRAL01,Spiral ascent 1,spiral,1,ZONE-F1,2,0,2
|
|
8
|
+
CV201,Sorter infeed,conveyor,2,ZONE-F2,6,8,0
|
|
9
|
+
SORT201,Crossbelt sorter,sorter,2,ZONE-F2,13,8,1
|
|
10
|
+
CV202,Exit chute left,conveyor,2,ZONE-F2,20,8,-5
|
|
11
|
+
CV203,Exit chute right,conveyor,2,ZONE-F2,20,8,6
|
|
12
|
+
PE201,Sorter entry photoeye,photoeye,2,ZONE-F2,10,8,-2
|
|
13
|
+
SCN201,Destination scanner,scanner,2,ZONE-F2,16,8,-2
|
|
14
|
+
SPIRAL02,Spiral ascent 2,spiral,2,ZONE-F2,24,8,2
|
|
15
|
+
CV301,Upper receiving conveyor,conveyor,3,ZONE-F3,22,16,0
|
|
16
|
+
CV302,Upper distribution,conveyor,3,ZONE-F3,15,16,-2
|
|
17
|
+
CV303,Outbound line,conveyor,3,ZONE-F3,8,16,-6
|
|
18
|
+
PE301,Outbound photoeye,photoeye,3,ZONE-F3,5,16,-5
|
|
19
|
+
VFD101,Conveyor motor drive,vfd,1,ZONE-F1,-13,0,4
|
|
20
|
+
VFD201,Sorter motor drive,vfd,2,ZONE-F2,11,8,5
|
|
21
|
+
VFD301,Outbound drive,vfd,3,ZONE-F3,12,16,3
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
id,asset_id,role,datatype,namespace_uri,node_id,unit,polarity
|
|
2
|
+
S_INFEED01_RUN_FEEDBACK,INFEED01,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/INFEED01/RunFeedback,,active_high
|
|
3
|
+
S_INFEED01_FAULT,INFEED01,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/INFEED01/MotorFault,,active_high
|
|
4
|
+
S_CV101_RUN_FEEDBACK,CV101,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/CV101/RunFeedback,,active_high
|
|
5
|
+
S_CV101_FAULT,CV101,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/CV101/MotorFault,,active_high
|
|
6
|
+
S_CV102_RUN_FEEDBACK,CV102,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/CV102/RunFeedback,,active_high
|
|
7
|
+
S_CV102_FAULT,CV102,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/CV102/MotorFault,,active_high
|
|
8
|
+
S_CV201_RUN_FEEDBACK,CV201,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/CV201/RunFeedback,,active_high
|
|
9
|
+
S_CV201_FAULT,CV201,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/CV201/MotorFault,,active_high
|
|
10
|
+
S_SORT201_RUN_FEEDBACK,SORT201,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/SORT201/RunFeedback,,active_high
|
|
11
|
+
S_SORT201_FAULT,SORT201,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/SORT201/MotorFault,,active_high
|
|
12
|
+
S_CV202_RUN_FEEDBACK,CV202,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/CV202/RunFeedback,,active_high
|
|
13
|
+
S_CV202_FAULT,CV202,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/CV202/MotorFault,,active_high
|
|
14
|
+
S_CV203_RUN_FEEDBACK,CV203,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/CV203/RunFeedback,,active_high
|
|
15
|
+
S_CV203_FAULT,CV203,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/CV203/MotorFault,,active_high
|
|
16
|
+
S_CV301_RUN_FEEDBACK,CV301,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/CV301/RunFeedback,,active_high
|
|
17
|
+
S_CV301_FAULT,CV301,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/CV301/MotorFault,,active_high
|
|
18
|
+
S_CV302_RUN_FEEDBACK,CV302,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/CV302/RunFeedback,,active_high
|
|
19
|
+
S_CV302_FAULT,CV302,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/CV302/MotorFault,,active_high
|
|
20
|
+
S_CV303_RUN_FEEDBACK,CV303,run_feedback,Boolean,urn:customer:warehouse:opc:preview,Line01/CV303/RunFeedback,,active_high
|
|
21
|
+
S_CV303_FAULT,CV303,fault,Boolean,urn:customer:warehouse:opc:preview,Line01/CV303/MotorFault,,active_high
|
|
22
|
+
S_PE101_PHOTOEYE_BLOCKED,PE101,photoeye_blocked,Boolean,urn:customer:warehouse:opc:preview,Line01/PE101/Blocked,,active_high
|
|
23
|
+
S_PE101_PHOTOEYE_COUNT,PE101,photoeye_count,Int32,urn:customer:warehouse:opc:preview,Line01/PE101/EdgeCount,count,
|
|
24
|
+
S_PE201_PHOTOEYE_BLOCKED,PE201,photoeye_blocked,Boolean,urn:customer:warehouse:opc:preview,Line01/PE201/Blocked,,active_high
|
|
25
|
+
S_PE201_PHOTOEYE_COUNT,PE201,photoeye_count,Int32,urn:customer:warehouse:opc:preview,Line01/PE201/EdgeCount,count,
|
|
26
|
+
S_PE301_PHOTOEYE_BLOCKED,PE301,photoeye_blocked,Boolean,urn:customer:warehouse:opc:preview,Line01/PE301/Blocked,,active_high
|
|
27
|
+
S_PE301_PHOTOEYE_COUNT,PE301,photoeye_count,Int32,urn:customer:warehouse:opc:preview,Line01/PE301/EdgeCount,count,
|
|
28
|
+
S_DWS01_SCANNER_RESULT,DWS01,scanner_result,String,urn:customer:warehouse:opc:preview,Line01/DWS01/LastResult,,
|
|
29
|
+
S_DWS01_NO_READ_COUNT,DWS01,no_read_count,Int32,urn:customer:warehouse:opc:preview,Line01/DWS01/NoReadCount,count,
|
|
30
|
+
S_SCN201_SCANNER_RESULT,SCN201,scanner_result,String,urn:customer:warehouse:opc:preview,Line01/SCN201/LastResult,,
|
|
31
|
+
S_SCN201_NO_READ_COUNT,SCN201,no_read_count,Int32,urn:customer:warehouse:opc:preview,Line01/SCN201/NoReadCount,count,
|
|
32
|
+
S_VFD101_VFD_FREQUENCY,VFD101,vfd_frequency,Double,urn:customer:warehouse:opc:preview,Line01/VFD101/ActualHz,Hz,
|
|
33
|
+
S_VFD201_VFD_FREQUENCY,VFD201,vfd_frequency,Double,urn:customer:warehouse:opc:preview,Line01/VFD201/ActualHz,Hz,
|
|
34
|
+
S_VFD301_VFD_FREQUENCY,VFD301,vfd_frequency,Double,urn:customer:warehouse:opc:preview,Line01/VFD301/ActualHz,Hz,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
id,name,kind,floor,zone,x,y,z
|
|
2
|
+
TANK01,Raw-water holding tank,tank,1,WATER-PROCESS,-15,0,-3
|
|
3
|
+
PUMP01,Lift pump 1,pump,1,WATER-PROCESS,-9,0,-3
|
|
4
|
+
VALVE01,Isolation valve,valve,1,WATER-PROCESS,-5,0,-3
|
|
5
|
+
FILTER01,Primary filter vessel,tank,1,WATER-PROCESS,0,0,-3
|
|
6
|
+
PUMP02,Treatment feed pump,pump,1,WATER-PROCESS,5,0,-3
|
|
7
|
+
TANK02,Clear-water storage tank,tank,1,WATER-PROCESS,12,0,-3
|
|
8
|
+
VFD01,Lift pump frequency drive,vfd,1,WATER-PROCESS,-9,0,2
|
|
9
|
+
VFD02,Treatment pump drive,vfd,1,WATER-PROCESS,5,0,2
|
|
10
|
+
VALVE02,Outlet valve,valve,1,WATER-PROCESS,16,0,-3
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
id,asset_id,role,datatype,namespace_uri,node_id,unit,polarity
|
|
2
|
+
S_PUMP01_RUN_FEEDBACK,PUMP01,run_feedback,Boolean,urn:customer:waterplant:opc:preview,WaterProcess/PUMP01/run_feedback,,active_high
|
|
3
|
+
S_PUMP01_FAULT,PUMP01,fault,Boolean,urn:customer:waterplant:opc:preview,WaterProcess/PUMP01/fault,,active_high
|
|
4
|
+
S_PUMP02_RUN_FEEDBACK,PUMP02,run_feedback,Boolean,urn:customer:waterplant:opc:preview,WaterProcess/PUMP02/run_feedback,,active_high
|
|
5
|
+
S_PUMP02_FAULT,PUMP02,fault,Boolean,urn:customer:waterplant:opc:preview,WaterProcess/PUMP02/fault,,active_high
|
|
6
|
+
S_TANK01_TANK_LEVEL,TANK01,tank_level,Double,urn:customer:waterplant:opc:preview,WaterProcess/TANK01/tank_level,%,
|
|
7
|
+
S_TANK02_TANK_LEVEL,TANK02,tank_level,Double,urn:customer:waterplant:opc:preview,WaterProcess/TANK02/tank_level,%,
|
|
8
|
+
S_FILTER01_TANK_LEVEL,FILTER01,tank_level,Double,urn:customer:waterplant:opc:preview,WaterProcess/FILTER01/tank_level,%,
|
|
9
|
+
S_VFD01_VFD_FREQUENCY,VFD01,vfd_frequency,Double,urn:customer:waterplant:opc:preview,WaterProcess/VFD01/vfd_frequency,Hz,
|
|
10
|
+
S_VFD02_VFD_FREQUENCY,VFD02,vfd_frequency,Double,urn:customer:waterplant:opc:preview,WaterProcess/VFD02/vfd_frequency,Hz,
|
|
11
|
+
S_VALVE01_VALVE_OPEN,VALVE01,valve_open,Boolean,urn:customer:waterplant:opc:preview,WaterProcess/VALVE01/valve_open,,
|
|
12
|
+
S_VALVE02_VALVE_OPEN,VALVE02,valve_open,Boolean,urn:customer:waterplant:opc:preview,WaterProcess/VALVE02/valve_open,,
|