手机主板温度:代理 0.8.0 上报,rack 拓扑图显示
- 机架代理 0.8.0(Thermal.java):读 /sys/class/thermal 的 quiet_therm(主板热敏)和最热的 CPU 核, 每次长轮询拼在 URL 后面(&tb=&tc=,m°C),不为它多醒一次。电池那一路不报(电池拆了)。 - rack 后端 prrack/fleet.py:每 5 秒读 AppTask 后端的 /api/fleet/phones,按机架位 B-n 对到第 n 路, 放进快照 phones[].live(在线 / 在跑活 / 代理版本 / 温度);变了才推 phones_live。只显示,不参与自动恢复。 读不到就清空,不留旧值。服务单元加 --apptask-env。 - 前端拓扑图每台手机多一行「主板 / CPU」温度(50 °C 橙、60 °C 红,只改颜色)。 - agent_upgrade_safe.sh:升级后 4 分钟没开机就 power_cycle 救一次并补收尾。 五台已升到 0.8.0(两路并行推);第 2、1、5 路 staged 重启后卡死 / 僵住,断电重启后版本都已是新的。 后端测试 58 项全过;已部署。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -76,6 +76,10 @@
|
||||
<span class="readout pw">{{ W(x.r.mv, x.r.ua) }}<small>W</small></span></div>
|
||||
<div class="ps" :style="{ color: loud(x.h.level) ? LEVEL_COLOR[x.h.level] : 'var(--muted)' }">
|
||||
{{ x.h.text }}<span class="muted readout"> {{ V(x.r.mv) }} V</span></div>
|
||||
<div class="pt" v-if="x.temp" :title="x.temp.tip">
|
||||
<span :style="{ color: x.temp.color }">主板 <b class="readout">{{ x.temp.board }}</b> °C</span>
|
||||
<span class="muted">CPU <span class="readout">{{ x.temp.cpu }}</span> °C</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="ps muted" v-else>空槽</div>
|
||||
</div>
|
||||
@@ -128,11 +132,14 @@ import { computed, reactive, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import RailOps from './RailOps.vue'
|
||||
import { api } from '../api'
|
||||
import { mA, V, W, railHealth, LEVEL_COLOR } from '../util'
|
||||
import { mA, V, W, C, railHealth, LEVEL_COLOR } from '../util'
|
||||
|
||||
const props = defineProps({ board: Object, sel: Number, recStates: Object })
|
||||
defineEmits(['select'])
|
||||
|
||||
// 手机主板 / CPU 温度的提示线(只改颜色,不参与任何动作):50 °C 橙、60 °C 红
|
||||
const TEMP_WARN_MC = 50000
|
||||
const TEMP_BAD_MC = 60000
|
||||
const LIVE_UA = 5000
|
||||
const s = computed(() => props.board?.status)
|
||||
const online = computed(() => !!props.board?.online && !props.board?.stale && !!s.value)
|
||||
@@ -160,11 +167,19 @@ const rails = computed(() => [1, 2, 3, 4, 5].map(i => {
|
||||
const live = online.value && pr && r.en && Math.abs(r.ua ?? 0) > LIVE_UA
|
||||
const fault = pr && r.flt && !(r.chg > 0)
|
||||
const phone = props.board?.phones?.find(x => x.rail === i)
|
||||
// 手机主板温度:机架代理(≥0.8.0)每次轮询报的 quiet_therm 和最热的 CPU 核;手机不在线 / 老代理 ⇒ 这一行不出现
|
||||
const lv = phone?.live
|
||||
const tmax = Math.max(lv?.temp_board_mc ?? -1e9, lv?.temp_cpu_mc ?? -1e9)
|
||||
const temp = lv?.online && tmax > -1e9 ? {
|
||||
board: C(lv.temp_board_mc), cpu: C(lv.temp_cpu_mc),
|
||||
color: tmax >= TEMP_BAD_MC ? LEVEL_COLOR.bad : tmax >= TEMP_WARN_MC ? LEVEL_COLOR.warn : 'var(--ink-2)',
|
||||
tip: `手机自己报的(机架代理 ${lv.agent},机架位 ${lv.fleet_rail}):主板热敏 quiet_therm 和最热的 CPU 核,约 25 秒更新一次`,
|
||||
} : null
|
||||
const w1 = !online.value || !pr ? 'off' : live ? 'live' : 'idle' // 母线 → 降压(12 V 侧)
|
||||
const w2 = !online.value || !pr ? 'off' : live ? 'live' : 'idle' // 降压 → eFuse
|
||||
const w3 = !online.value || !pr || !r.en ? 'off' : fault ? 'bad' : live ? 'live' : 'idle' // eFuse → 手机
|
||||
return {
|
||||
i, r, h, pr, fault, w1, w2, w3, label: phone?.label || '',
|
||||
i, r, h, pr, fault, w1, w2, w3, temp, label: phone?.label || '',
|
||||
ctl: online.value && pr, // 图上元件可点(调压 / 上下电 / USB);序列类动作另看执行器空闲,在 RailOps 里
|
||||
rev: live && (r.ua ?? 0) < -LIVE_UA,
|
||||
f: flow(r?.ua, p),
|
||||
@@ -282,6 +297,8 @@ const vbN = computed(() => rails.value.filter(x => x.pr && x.r.vb).length)
|
||||
.pv .pw { margin-left: auto; font-size: 14px; color: var(--ink-2); }
|
||||
.ps { font-size: 12px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.ps .muted { font-weight: 400; font-size: 11px; }
|
||||
.pt { display: flex; gap: 10px; font-size: 11px; white-space: nowrap; overflow: hidden; margin-top: 1px; }
|
||||
.pt b { font-weight: 600; }
|
||||
.phone.bad { border-color: var(--st-bad); }
|
||||
.phone.busy { border-color: var(--st-busy); }
|
||||
.phone.warn { border-color: var(--st-warn); }
|
||||
|
||||
@@ -51,6 +51,12 @@ function handle(m) {
|
||||
case 'board':
|
||||
state.boards[m.board.id] = m.board
|
||||
break
|
||||
case 'phones_live': {
|
||||
// 手机自己报的那一半(在线 / 温度,后端 fleet.py);live 里没有的路 = 读不到,清掉
|
||||
const b = state.boards[m.board]
|
||||
if (b) for (const p of b.phones || []) p.live = m.live[p.rail] ?? null
|
||||
break
|
||||
}
|
||||
case 'tele': {
|
||||
const b = state.boards[m.board]
|
||||
if (b) { b.status = m.status; b.last_tele = m.ts; b.stale = false; b.online = true }
|
||||
|
||||
在新工单中引用
屏蔽一个用户