"Add_AdSense_and_Settings_Delay"

This commit is contained in:
2025-12-21 18:37:31 +09:00
parent 56f2c0825a
commit 78343d2b9a

View File

@@ -20,8 +20,20 @@ const Settings: React.FC = () => {
try { try {
await serialService.enterFactoryModeRead(); await serialService.enterFactoryModeRead();
const p = serialService.readRegister.bind(serialService); // Helper with delay
const pBytes = serialService.readRegisterBytes.bind(serialService); const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
const p = async (reg: number) => {
const val = await serialService.readRegister(reg);
await delay(250);
return val;
};
const pBytes = async (reg: number) => {
const val = await serialService.readRegisterBytes(reg);
await delay(250);
return val;
};
// 병렬 처리는 시리얼 통신에서 꼬일 수 있으므로 순차 처리 권장 (await 사용) // 병렬 처리는 시리얼 통신에서 꼬일 수 있으므로 순차 처리 권장 (await 사용)
// 주요 레지스터 읽기 // 주요 레지스터 읽기
@@ -69,13 +81,13 @@ const Settings: React.FC = () => {
newConfig.cellCnt = await p(JBD.REG_CELL_CNT); newConfig.cellCnt = await p(JBD.REG_CELL_CNT);
newConfig.cycleCnt = await p(JBD.REG_CYCLE_CNT); newConfig.cycleCnt = await p(JBD.REG_CYCLE_CNT);
newConfig.serialNum = await p(JBD.REG_SERIAL_NUM); newConfig.serialNum = await p(JBD.REG_SERIAL_NUM);
newConfig.mfgDate = await p(JBD.REG_MFG_DATE); newConfig.mfgDate = await p(JBD.REG_MFG_DATE);
const mfgNameRaw = await pBytes(JBD.REG_MFG_NAME); const mfgNameRaw = await pBytes(JBD.REG_MFG_NAME);
const deviceNameRaw = await pBytes(JBD.REG_DEVICE_NAME); const deviceNameRaw = await pBytes(JBD.REG_DEVICE_NAME);
const barcodeRaw = await pBytes(JBD.REG_BARCODE); const barcodeRaw = await pBytes(JBD.REG_BARCODE);
newConfig.mfgName = JBD.JBDProtocol.parseString(mfgNameRaw); newConfig.mfgName = JBD.JBDProtocol.parseString(mfgNameRaw);
newConfig.deviceName = JBD.JBDProtocol.parseString(deviceNameRaw); newConfig.deviceName = JBD.JBDProtocol.parseString(deviceNameRaw);
newConfig.barcode = JBD.JBDProtocol.parseString(barcodeRaw); newConfig.barcode = JBD.JBDProtocol.parseString(barcodeRaw);
@@ -98,16 +110,16 @@ const Settings: React.FC = () => {
setSuccessMsg(null); setSuccessMsg(null);
try { try {
await serialService.enterFactoryModeRead(); await serialService.enterFactoryModeRead();
let val: any; let val: any;
if (type === 'int' || type === 'date') { // date reads as int raw if (type === 'int' || type === 'date') { // date reads as int raw
val = await serialService.readRegister(reg); val = await serialService.readRegister(reg);
} else if (type === 'string' || type === 'bytes') { } else if (type === 'string' || type === 'bytes') {
const bytes = await serialService.readRegisterBytes(reg); const bytes = await serialService.readRegisterBytes(reg);
if (type === 'string') { if (type === 'string') {
val = JBD.JBDProtocol.parseString(bytes); val = JBD.JBDProtocol.parseString(bytes);
} else { } else {
val = bytes; // bytes not fully supported in single row yet unless custom val = bytes; // bytes not fully supported in single row yet unless custom
} }
} }
@@ -150,11 +162,11 @@ const Settings: React.FC = () => {
}; };
// 그룹 컴포넌트 // 그룹 컴포넌트
const Group: React.FC<{title: string, children: React.ReactNode}> = ({title, children}) => ( const Group: React.FC<{ title: string, children: React.ReactNode }> = ({ title, children }) => (
<div className="bg-gray-900 rounded-xl border border-gray-800 shadow-xl overflow-hidden mb-6"> <div className="bg-gray-900 rounded-xl border border-gray-800 shadow-xl overflow-hidden mb-6">
<div className="bg-gray-800/50 px-5 py-3 border-b border-gray-700"> <div className="bg-gray-800/50 px-5 py-3 border-b border-gray-700">
<h3 className="text-lg font-bold text-gray-200 flex items-center gap-2"> <h3 className="text-lg font-bold text-gray-200 flex items-center gap-2">
{title} {title}
</h3> </h3>
</div> </div>
<div className="p-1 space-y-1">{children}</div> <div className="p-1 space-y-1">{children}</div>
@@ -162,11 +174,11 @@ const Settings: React.FC = () => {
); );
// 개별 설정 행 컴포넌트 // 개별 설정 행 컴포넌트
const SettingRow: React.FC<{ const SettingRow: React.FC<{
label: string; label: string;
val: number | string | undefined; val: number | string | undefined;
unit?: string; unit?: string;
reg: number; reg: number;
field: keyof BMSConfig; field: keyof BMSConfig;
scale?: number; scale?: number;
type?: 'int' | 'string' | 'bytes' | 'date'; type?: 'int' | 'string' | 'bytes' | 'date';
@@ -177,40 +189,40 @@ const Settings: React.FC = () => {
// config 값이 업데이트되면 로컬 상태 동기화 // config 값이 업데이트되면 로컬 상태 동기화
useEffect(() => { useEffect(() => {
if (val === undefined || val === null) { if (val === undefined || val === null) {
setLocalVal(''); setLocalVal('');
setIsDirty(false); setIsDirty(false);
} else {
if (type === 'date') {
setLocalVal(JBD.JBDProtocol.parseDate(val as number));
} else if (type === 'int') {
setLocalVal(Number(val) * scale);
} else { } else {
if (type === 'date') { setLocalVal(val as string);
setLocalVal(JBD.JBDProtocol.parseDate(val as number));
} else if (type === 'int') {
setLocalVal(Number(val) * scale);
} else {
setLocalVal(val as string);
}
setIsDirty(false);
} }
setIsDirty(false);
}
}, [val, scale, type]); }, [val, scale, type]);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setLocalVal(e.target.value); setLocalVal(e.target.value);
setIsDirty(true); setIsDirty(true);
}; };
const onRead = () => { const onRead = () => {
handleReadSingle(reg, field, type as 'int' | 'string' | 'bytes' | 'date'); handleReadSingle(reg, field, type as 'int' | 'string' | 'bytes' | 'date');
}; };
const onSave = () => { const onSave = () => {
let payload: any = localVal; let payload: any = localVal;
if (type === 'int') { if (type === 'int') {
payload = Number(localVal) / scale; payload = Number(localVal) / scale;
} else if (type === 'date') { } else if (type === 'date') {
payload = JBD.JBDProtocol.encodeDate(localVal as string); payload = JBD.JBDProtocol.encodeDate(localVal as string);
} }
handleSaveSingle(reg, payload, type as 'int' | 'string' | 'bytes' | 'date'); handleSaveSingle(reg, payload, type as 'int' | 'string' | 'bytes' | 'date');
setIsDirty(false); setIsDirty(false);
}; };
return ( return (
@@ -219,10 +231,10 @@ const Settings: React.FC = () => {
<div className="text-sm text-gray-300 font-medium">{label}</div> <div className="text-sm text-gray-300 font-medium">{label}</div>
<div className="text-xs text-gray-600 font-mono">ADDR: 0x{reg.toString(16).toUpperCase().padStart(2, '0')}</div> <div className="text-xs text-gray-600 font-mono">ADDR: 0x{reg.toString(16).toUpperCase().padStart(2, '0')}</div>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="relative"> <div className="relative">
<input <input
type={type === 'date' ? 'date' : 'text'} type={type === 'date' ? 'date' : 'text'}
value={localVal} value={localVal}
onChange={handleChange} onChange={handleChange}
@@ -233,7 +245,7 @@ const Settings: React.FC = () => {
{unit && <span className="absolute right-2 top-2 text-gray-500 text-xs pointer-events-none opacity-50">{type !== 'date' ? unit : ''}</span>} {unit && <span className="absolute right-2 top-2 text-gray-500 text-xs pointer-events-none opacity-50">{type !== 'date' ? unit : ''}</span>}
</div> </div>
<button <button
onClick={onRead} onClick={onRead}
disabled={isBusy || globalLoading} disabled={isBusy || globalLoading}
title="개별 읽기" title="개별 읽기"
@@ -242,7 +254,7 @@ const Settings: React.FC = () => {
<RotateCw size={16} className={isBusy ? 'animate-spin text-blue-500' : ''} /> <RotateCw size={16} className={isBusy ? 'animate-spin text-blue-500' : ''} />
</button> </button>
<button <button
onClick={onSave} onClick={onSave}
disabled={isBusy || globalLoading} disabled={isBusy || globalLoading}
title="개별 저장" title="개별 저장"
@@ -264,8 +276,8 @@ const Settings: React.FC = () => {
<p className="text-gray-400 text-sm">BMS .</p> <p className="text-gray-400 text-sm">BMS .</p>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<button <button
onClick={readAllSettings} onClick={readAllSettings}
disabled={globalLoading} disabled={globalLoading}
className="flex items-center px-5 py-2.5 bg-blue-600 hover:bg-blue-500 text-white rounded-xl transition-colors shadow-lg shadow-blue-900/20 text-sm font-bold" className="flex items-center px-5 py-2.5 bg-blue-600 hover:bg-blue-500 text-white rounded-xl transition-colors shadow-lg shadow-blue-900/20 text-sm font-bold"
> >
@@ -293,62 +305,62 @@ const Settings: React.FC = () => {
{/* 설정 그리드 */} {/* 설정 그리드 */}
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6"> <div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
<div className="space-y-6"> <div className="space-y-6">
<Group title="전압 보호 (Voltage Protection)"> <Group title="전압 보호 (Voltage Protection)">
<SettingRow label="셀 과전압 (Cell OVP)" unit="mV" val={config.cellOvp} reg={JBD.REG_COVP} field="cellOvp" /> <SettingRow label="셀 과전압 (Cell OVP)" unit="mV" val={config.cellOvp} reg={JBD.REG_COVP} field="cellOvp" />
<SettingRow label="셀 과전압 해제 (Release)" unit="mV" val={config.cellOvpRel} reg={JBD.REG_COVP_REL} field="cellOvpRel" /> <SettingRow label="셀 과전압 해제 (Release)" unit="mV" val={config.cellOvpRel} reg={JBD.REG_COVP_REL} field="cellOvpRel" />
<SettingRow label="셀 저전압 (Cell UVP)" unit="mV" val={config.cellUvp} reg={JBD.REG_CUVP} field="cellUvp" /> <SettingRow label="셀 저전압 (Cell UVP)" unit="mV" val={config.cellUvp} reg={JBD.REG_CUVP} field="cellUvp" />
<SettingRow label="셀 저전압 해제 (Release)" unit="mV" val={config.cellUvpRel} reg={JBD.REG_CUVP_REL} field="cellUvpRel" /> <SettingRow label="셀 저전압 해제 (Release)" unit="mV" val={config.cellUvpRel} reg={JBD.REG_CUVP_REL} field="cellUvpRel" />
<SettingRow label="팩 과전압 (Pack OVP)" unit="V" val={config.packOvp} reg={JBD.REG_POVP} field="packOvp" scale={0.01} /> <SettingRow label="팩 과전압 (Pack OVP)" unit="V" val={config.packOvp} reg={JBD.REG_POVP} field="packOvp" scale={0.01} />
<SettingRow label="팩 과전압 해제 (Release)" unit="V" val={config.packOvpRel} reg={JBD.REG_POVP_REL} field="packOvpRel" scale={0.01} /> <SettingRow label="팩 과전압 해제 (Release)" unit="V" val={config.packOvpRel} reg={JBD.REG_POVP_REL} field="packOvpRel" scale={0.01} />
<SettingRow label="팩 저전압 (Pack UVP)" unit="V" val={config.packUvp} reg={JBD.REG_PUVP} field="packUvp" scale={0.01} /> <SettingRow label="팩 저전압 (Pack UVP)" unit="V" val={config.packUvp} reg={JBD.REG_PUVP} field="packUvp" scale={0.01} />
<SettingRow label="팩 저전압 해제 (Release)" unit="V" val={config.packUvpRel} reg={JBD.REG_PUVP_REL} field="packUvpRel" scale={0.01} /> <SettingRow label="팩 저전압 해제 (Release)" unit="V" val={config.packUvpRel} reg={JBD.REG_PUVP_REL} field="packUvpRel" scale={0.01} />
</Group> </Group>
<Group title="온도 보호 (Temperature)"> <Group title="온도 보호 (Temperature)">
<SettingRow label="충전 과온 (Chg OT)" unit="°C" val={config.chgOt} reg={JBD.REG_CHG_OT} field="chgOt" type="int" /> <SettingRow label="충전 과온 (Chg OT)" unit="°C" val={config.chgOt} reg={JBD.REG_CHG_OT} field="chgOt" type="int" />
<SettingRow label="충전 과온 해제 (Release)" unit="°C" val={config.chgOtRel} reg={JBD.REG_CHG_OT_REL} field="chgOtRel" /> <SettingRow label="충전 과온 해제 (Release)" unit="°C" val={config.chgOtRel} reg={JBD.REG_CHG_OT_REL} field="chgOtRel" />
<SettingRow label="충전 저온 (Chg UT)" unit="°C" val={config.chgUt} reg={JBD.REG_CHG_UT} field="chgUt" /> <SettingRow label="충전 저온 (Chg UT)" unit="°C" val={config.chgUt} reg={JBD.REG_CHG_UT} field="chgUt" />
<SettingRow label="충전 저온 해제 (Release)" unit="°C" val={config.chgUtRel} reg={JBD.REG_CHG_UT_REL} field="chgUtRel" /> <SettingRow label="충전 저온 해제 (Release)" unit="°C" val={config.chgUtRel} reg={JBD.REG_CHG_UT_REL} field="chgUtRel" />
<SettingRow label="방전 과온 (Dsg OT)" unit="°C" val={config.dsgOt} reg={JBD.REG_DSG_OT} field="dsgOt" /> <SettingRow label="방전 과온 (Dsg OT)" unit="°C" val={config.dsgOt} reg={JBD.REG_DSG_OT} field="dsgOt" />
<SettingRow label="방전 과온 해제 (Release)" unit="°C" val={config.dsgOtRel} reg={JBD.REG_DSG_OT_REL} field="dsgOtRel" /> <SettingRow label="방전 과온 해제 (Release)" unit="°C" val={config.dsgOtRel} reg={JBD.REG_DSG_OT_REL} field="dsgOtRel" />
</Group> </Group>
<Group title="하드웨어 정보 (Hardware Info)">
<SettingRow label="제조일자 (Mfg Date)" unit="" val={config.mfgDate} reg={JBD.REG_MFG_DATE} field="mfgDate" type="date" />
<SettingRow label="제조사명 (Mfg Name)" unit="" val={config.mfgName} reg={JBD.REG_MFG_NAME} field="mfgName" type="string" />
<SettingRow label="장치명 (Device Name)" unit="" val={config.deviceName} reg={JBD.REG_DEVICE_NAME} field="deviceName" type="string" />
<SettingRow label="바코드 (Barcode)" unit="" val={config.barcode} reg={JBD.REG_BARCODE} field="barcode" type="string" />
<SettingRow label="션트 저항 (Shunt)" unit="mΩ" val={config.shuntRes} reg={JBD.REG_SHUNT_RES} field="shuntRes" scale={0.1} />
<SettingRow label="셀 개수 (Cell Count)" unit="S" val={config.cellCnt} reg={JBD.REG_CELL_CNT} field="cellCnt" />
</Group>
</div>
<div className="space-y-6"> <Group title="하드웨어 정보 (Hardware Info)">
<Group title="용량 설정 (Capacity Settings)"> <SettingRow label="제조일자 (Mfg Date)" unit="" val={config.mfgDate} reg={JBD.REG_MFG_DATE} field="mfgDate" type="date" />
<SettingRow label="설계 용량 (Design Cap)" unit="Ah" val={config.designCapacity} reg={JBD.REG_DESIGN_CAP} field="designCapacity" scale={0.01} /> <SettingRow label="제조사명 (Mfg Name)" unit="" val={config.mfgName} reg={JBD.REG_MFG_NAME} field="mfgName" type="string" />
<SettingRow label="사이클 용량 (Cycle Cap)" unit="Ah" val={config.cycleCapacity} reg={JBD.REG_CYCLE_CAP} field="cycleCapacity" scale={0.01} /> <SettingRow label="장치명 (Device Name)" unit="" val={config.deviceName} reg={JBD.REG_DEVICE_NAME} field="deviceName" type="string" />
<SettingRow label="방전율 (Dsg Rate)" unit="%" val={config.dsgRate} reg={JBD.REG_DSG_RATE} field="dsgRate" scale={0.1} /> <SettingRow label="바코드 (Barcode)" unit="" val={config.barcode} reg={JBD.REG_BARCODE} field="barcode" type="string" />
<SettingRow label="100% 전압 (Vol at 100%)" unit="mV" val={config.cap100} reg={JBD.REG_CAP_100} field="cap100" /> <SettingRow label="션트 저항 (Shunt)" unit="mΩ" val={config.shuntRes} reg={JBD.REG_SHUNT_RES} field="shuntRes" scale={0.1} />
<SettingRow label="80% 전압 (Vol at 80%)" unit="mV" val={config.cap80} reg={JBD.REG_CAP_80} field="cap80" /> <SettingRow label="셀 개수 (Cell Count)" unit="S" val={config.cellCnt} reg={JBD.REG_CELL_CNT} field="cellCnt" />
<SettingRow label="60% 전압 (Vol at 60%)" unit="mV" val={config.cap60} reg={JBD.REG_CAP_60} field="cap60" /> </Group>
<SettingRow label="40% 전압 (Vol at 40%)" unit="mV" val={config.cap40} reg={JBD.REG_CAP_40} field="cap40" /> </div>
<SettingRow label="20% 전압 (Vol at 20%)" unit="mV" val={config.cap20} reg={JBD.REG_CAP_20} field="cap20" />
<SettingRow label="0% 전압 (Vol at 0%)" unit="mV" val={config.cap0} reg={JBD.REG_CAP_0} field="cap0" />
</Group>
<Group title="밸런스 설정 (Balancer)"> <div className="space-y-6">
<SettingRow label="시작 전압 (Start Volt)" unit="mV" val={config.balStart} reg={JBD.REG_BAL_START} field="balStart" /> <Group title="용량 설정 (Capacity Settings)">
<SettingRow label="정밀도 (Precision)" unit="mV" val={config.balWindow} reg={JBD.REG_BAL_WINDOW} field="balWindow" /> <SettingRow label="설계 용량 (Design Cap)" unit="Ah" val={config.designCapacity} reg={JBD.REG_DESIGN_CAP} field="designCapacity" scale={0.01} />
</Group> <SettingRow label="사이클 용량 (Cycle Cap)" unit="Ah" val={config.cycleCapacity} reg={JBD.REG_CYCLE_CAP} field="cycleCapacity" scale={0.01} />
<SettingRow label="방전율 (Dsg Rate)" unit="%" val={config.dsgRate} reg={JBD.REG_DSG_RATE} field="dsgRate" scale={0.1} />
<SettingRow label="100% 전압 (Vol at 100%)" unit="mV" val={config.cap100} reg={JBD.REG_CAP_100} field="cap100" />
<SettingRow label="80% 전압 (Vol at 80%)" unit="mV" val={config.cap80} reg={JBD.REG_CAP_80} field="cap80" />
<SettingRow label="60% 전압 (Vol at 60%)" unit="mV" val={config.cap60} reg={JBD.REG_CAP_60} field="cap60" />
<SettingRow label="40% 전압 (Vol at 40%)" unit="mV" val={config.cap40} reg={JBD.REG_CAP_40} field="cap40" />
<SettingRow label="20% 전압 (Vol at 20%)" unit="mV" val={config.cap20} reg={JBD.REG_CAP_20} field="cap20" />
<SettingRow label="0% 전압 (Vol at 0%)" unit="mV" val={config.cap0} reg={JBD.REG_CAP_0} field="cap0" />
</Group>
<Group title="기타 설정 (Misc)"> <Group title="밸런스 설정 (Balancer)">
<SettingRow label="기능 설정 (Func Config)" unit="HEX" val={config.funcConfig} reg={JBD.REG_FUNC_CONFIG} field="funcConfig" /> <SettingRow label="시작 전압 (Start Volt)" unit="mV" val={config.balStart} reg={JBD.REG_BAL_START} field="balStart" />
<SettingRow label="NTC 설정 (NTC Config)" unit="HEX" val={config.ntcConfig} reg={JBD.REG_NTC_CONFIG} field="ntcConfig" /> <SettingRow label="정밀도 (Precision)" unit="mV" val={config.balWindow} reg={JBD.REG_BAL_WINDOW} field="balWindow" />
<SettingRow label="FET 제어 시간" unit="s" val={config.fetCtrl} reg={JBD.REG_FET_CTRL} field="fetCtrl" /> </Group>
<SettingRow label="LED 타이머" unit="s" val={config.ledTimer} reg={JBD.REG_LED_TIMER} field="ledTimer" />
</Group> <Group title="기타 설정 (Misc)">
</div> <SettingRow label="기능 설정 (Func Config)" unit="HEX" val={config.funcConfig} reg={JBD.REG_FUNC_CONFIG} field="funcConfig" />
<SettingRow label="NTC 설정 (NTC Config)" unit="HEX" val={config.ntcConfig} reg={JBD.REG_NTC_CONFIG} field="ntcConfig" />
<SettingRow label="FET 제어 시간" unit="s" val={config.fetCtrl} reg={JBD.REG_FET_CTRL} field="fetCtrl" />
<SettingRow label="LED 타이머" unit="s" val={config.ledTimer} reg={JBD.REG_LED_TIMER} field="ledTimer" />
</Group>
</div>
</div> </div>
</div> </div>
); );