import {useEffect,useRef,useState} from 'react'; import {Button,LoadingRegion,ResourceList,ResourceRow,SettingsCard,StatusBadge} from '@nodedc/ui-react'; import type {SensorDetailProps} from '../../../../packages/sensor-ui/src/extensions'; import {perform} from '../../../../packages/sensor-ui/src/contracts'; import {vescLabel,vescStatus,type VescTelemetry} from './model'; import {VescBackups} from './VescBackups'; import {VescMotor} from './VescMotor'; import {VescHall} from './VescHall'; import {VescCalibration} from './VescCalibration'; import {VescLink} from './VescLink'; const fields=[['input_voltage_v','Напряжение питания','В'],['input_current_a','Ток питания','А'], ['motor_current_a','Ток мотора','А'],['erpm','Электрические обороты','ERPM'],['duty','Заполнение PWM',''], ['mos_temperature_c','Температура контроллера','°C'],['motor_temperature_c','Температура мотора','°C'], ['fault_code','Код ошибки',''],['can_id','CAN ID',''],['timeout','Тайм-аут управления',''], ['kill_switch','Вход аварийного останова','']] as const; export function VescDetail(props:SensorDetailProps){ const {device,transport,enabled,back,refresh,failure}=props; const status=vescStatus(device);const label=vescLabel(device,enabled); const [telemetry,setTelemetry]=useState(status.telemetry); const [pending,setPending]=useState(null); const [saved,setSaved]=useState(null); const [motorBusy,setMotorBusy]=useState(false); const [hallBusy,setHallBusy]=useState(false); const [calibrationBusy,setCalibrationBusy]=useState(false); const [linkBusy,setLinkBusy]=useState(false); const poweredBusy=motorBusy||hallBusy||calibrationBusy||linkBusy; const running=useRef(false);const mounted=useRef(true); const available=enabled&&device.online&&device.verified&&status.readable; useEffect(()=>{mounted.current=true;return()=>{mounted.current=false;};},[]); async function read(action:'vesc.telemetry.read'|'vesc.config.backup'){ if(running.current||poweredBusy||!available)return; running.current=true;setPending(action);failure(null); try{ const result=await perform>(transport,device,action); if(!mounted.current)return; if(action==='vesc.telemetry.read')setTelemetry(result as unknown as VescTelemetry); else { setSaved(String(result.observed_at)); } await refresh(); }catch(error){if(mounted.current)failure(error);} finally{running.current=false;if(mounted.current)setPending(null);} } const backupAt=saved??status.backup?.observed_at; return
{label.label}}> {!enabled||!device.online?

Нет свежей связи с контроллером.

:status.message?

{status.message}

:null} {status.identity?
  • {status.identity.test_firmware!==null&&status.identity.test_firmware>0&&
  • }
    :

    Аппаратный идентификатор ещё не подтверждён.

    }
    void read('vesc.telemetry.read')}>Обновить показания}> {telemetry?{fields.map(([key,title,unit])=>{ const value=telemetry.values[key];if(value===undefined)return null; return
  • ; })}
    :

    Показания ещё не прочитаны.

    }

    ERPM — электрические обороты. Обороты вала зависят от числа пар полюсов мотора.

    void read('vesc.config.backup')}>Сохранить версию}> {backupAt&&

    Последняя копия: {new Date(backupAt).toLocaleString()}

    }

    Копия привязана к UUID и прошивке. Версии до и после калибровки остаются в истории.

    ; }