@samlab-corp/usb-relay-hid
v1.0.0
Published
Advanced USB HID Relay controller for Node.js with auto-reconnect, handshake validation, and event-based monitoring
Readme
USB Relay HID Controller
고급 USB HID 릴레이 제어 라이브러리로, 자동 재연결, 핸드셰이크 검증, 이벤트 기반 모니터링 기능을 제공합니다.
✨ 주요 기능
- 🔌 자동 장치 검색 및 연결: USB 릴레이 장치 자동 탐지
- 🔄 자동 재연결: 연결 끊김 시 자동으로 재연결 시도
- 🤝 핸드셰이크 검증: 장치 연결 시 통신 검증
- 📊 실시간 상태 모니터링: 릴레이 상태 폴링 및 이벤트 알림
- ⚡ 이벤트 기반 아키텍처: EventEmitter 기반 비동기 처리
- 🛡️ 에러 복구: 자동 재시도 및 에러 핸들링
- 📝 상세한 로깅: 디버깅을 위한 로그 시스템
- 🎯 TypeScript 지원: 타입 정의 포함
📦 설치
npm install usb-relay-hid시스템 요구사항
- Node.js >= 14.0.0
- USB HID 릴레이 장치 (VID: 0x16c0, PID: 0x05df)
Windows
추가 설정 불필요
Linux
# USB 접근 권한 설정
sudo usermod -a -G plugdev $USERmacOS
# Xcode Command Line Tools 필요
xcode-select --install🚀 빠른 시작
기본 사용법
const USBRelayController = require('usb-relay-hid');
// 컨트롤러 인스턴스 생성
const relay = new USBRelayController({
autoReconnect: true,
reconnectInterval: 1000, // 1초마다 재연결 시도
enableLogging: true
});
// 장치 연결
async function main() {
// 1. 장치 검색
const devices = relay.enumerate();
console.log(`발견된 장치: ${devices.length}개`);
// 2. 첫 번째 장치 연결
const success = await relay.open();
if (success) {
console.log('연결 성공!');
// 3. 릴레이 제어
await relay.openRelay(1); // 릴레이 1번 열기
await relay.closeRelay(1); // 릴레이 1번 닫기
// 4. 모든 릴레이 제어
await relay.openAllRelays();
await relay.closeAllRelays();
// 5. 상태 확인
const status = relay.getAllRelayStates();
console.log('릴레이 상태:', status);
}
}
main();이벤트 기반 사용
const relay = new USBRelayController();
// 연결 이벤트
relay.on('connected', (data) => {
console.log('장치 연결됨:', data.deviceInfo);
console.log('초기 상태:', data.status);
});
// 연결 끊김 이벤트
relay.on('disconnected', () => {
console.log('장치 연결 끊김');
});
// 재연결 이벤트
relay.on('reconnecting', () => {
console.log('재연결 시도 중...');
});
relay.on('reconnected', () => {
console.log('재연결 성공!');
});
// 릴레이 상태 변경 이벤트
relay.on('relay-changed', (data) => {
console.log(`릴레이 ${data.channel}: ${data.state ? '열림' : '닫힘'}`);
});
// 상태 폴링 이벤트
relay.on('status-changed', (data) => {
console.log('상태 변경 감지:', {
이전: data.oldStatus,
현재: data.newStatus
});
});
// 에러 이벤트
relay.on('error', (data) => {
console.error('에러 발생:', data.error);
});
// 장치 연결
await relay.open();📖 API 문서
생성자 옵션
new USBRelayController(options)| 옵션 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| autoReconnect | boolean | true | 자동 재연결 활성화 |
| reconnectInterval | number | 1000 | 재연결 시도 간격 (ms) |
| maxRetries | number | 3 | 명령 재시도 최대 횟수 |
| commandTimeout | number | 1000 | 명령 타임아웃 (ms) |
| statusPollingInterval | number | 0 | 상태 폴링 간격 (0=비활성화) |
| enableLogging | boolean | true | 로깅 활성화 |
메서드
장치 관리
// 장치 검색
relay.enumerate() // => Array<DeviceInfo>
// 장치 연결
await relay.open(serialNumber?) // => Promise<boolean>
// 장치 연결 해제
relay.close() // => void
// 연결 상태 확인
relay.isDeviceConnected() // => boolean
// 장치 정보 가져오기
relay.getDeviceInfo() // => DeviceInfo | null릴레이 제어
// 특정 릴레이 열기 (켜기)
await relay.openRelay(channel) // channel: 1-8
// 특정 릴레이 닫기 (끄기)
await relay.closeRelay(channel) // channel: 1-8
// 모든 릴레이 열기
await relay.openAllRelays()
// 모든 릴레이 닫기
await relay.closeAllRelays()
// 릴레이 토글
await relay.toggleRelay(channel)상태 확인
// 전체 상태 확인 (비트마스크)
relay.getStatus() // => number
// 특정 릴레이 상태
relay.getRelayStatus(channel) // => boolean | null
// 모든 릴레이 상태 배열
relay.getAllRelayStates() // => Array<boolean>이벤트
| 이벤트 | 인자 | 설명 |
|--------|------|------|
| connected | { deviceInfo, status } | 장치 연결 성공 |
| disconnected | - | 장치 연결 해제 |
| reconnecting | - | 재연결 시도 중 |
| reconnected | - | 재연결 성공 |
| handshake-failed | { error } | 핸드셰이크 실패 |
| connection-failed | { error } | 연결 실패 |
| relay-changed | { channel, state } | 릴레이 상태 변경 |
| all-relays-changed | { state } | 모든 릴레이 상태 변경 |
| status-changed | { oldStatus, newStatus } | 상태 변경 감지 |
| command-failed | { command, error } | 명령 실행 실패 |
| device-error | { error } | 장치 에러 |
| error | { type, error } | 일반 에러 |
💡 예제
1. 간단한 릴레이 제어
const USBRelayController = require('usb-relay-hid');
async function simpleControl() {
const relay = new USBRelayController();
await relay.open();
// 릴레이 1번 1초 동안 켜기
await relay.openRelay(1);
await new Promise(resolve => setTimeout(resolve, 1000));
await relay.closeRelay(1);
relay.close();
}
simpleControl();2. 순차 제어
async function sequentialControl() {
const relay = new USBRelayController({ enableLogging: false });
await relay.open();
// 릴레이 1-8 순차 제어
for (let i = 1; i <= 8; i++) {
console.log(`릴레이 ${i} 켜기`);
await relay.openRelay(i);
await new Promise(resolve => setTimeout(resolve, 500));
console.log(`릴레이 ${i} 끄기`);
await relay.closeRelay(i);
await new Promise(resolve => setTimeout(resolve, 500));
}
relay.close();
}3. 상태 모니터링
const relay = new USBRelayController({
statusPollingInterval: 1000 // 1초마다 상태 폴링
});
relay.on('status-changed', (data) => {
const oldBinary = data.oldStatus.toString(2).padStart(8, '0');
const newBinary = data.newStatus.toString(2).padStart(8, '0');
console.log(`상태 변경: 0b${oldBinary} → 0b${newBinary}`);
});
await relay.open();4. 자동 재연결
const relay = new USBRelayController({
autoReconnect: true,
reconnectInterval: 1000 // 1초마다 재연결 시도
});
relay.on('disconnected', () => {
console.log('⚠️ USB 연결이 끊어졌습니다');
});
relay.on('reconnecting', () => {
console.log('🔄 재연결 시도 중...');
});
relay.on('reconnected', () => {
console.log('✅ 재연결 성공!');
});
await relay.open();
// USB를 뽑았다 다시 꽂으면 자동으로 재연결됩니다5. 에러 처리
const relay = new USBRelayController();
relay.on('error', (data) => {
console.error(`에러 발생 [${data.type}]:`, data.error.message);
});
relay.on('command-failed', (data) => {
console.error(`명령 실패 [${data.command}]:`, data.error);
});
try {
await relay.open();
await relay.openRelay(1);
} catch (error) {
console.error('치명적 에러:', error);
}🔧 고급 사용
TypeScript 사용
import USBRelayController from 'usb-relay-hid';
const relay = new USBRelayController({
autoReconnect: true,
reconnectInterval: 1000, // 1초마다 재연결 시도
maxRetries: 5,
enableLogging: true
});
relay.on('connected', (data) => {
console.log('Device:', data.deviceInfo.product);
});
await relay.open();Express.js와 함께 사용
const express = require('express');
const USBRelayController = require('usb-relay-hid');
const app = express();
const relay = new USBRelayController();
app.use(express.json());
// 릴레이 제어 API
app.post('/relay/:channel/open', async (req, res) => {
const channel = parseInt(req.params.channel);
const success = await relay.openRelay(channel);
res.json({ success, channel, state: 'open' });
});
app.post('/relay/:channel/close', async (req, res) => {
const channel = parseInt(req.params.channel);
const success = await relay.closeRelay(channel);
res.json({ success, channel, state: 'closed' });
});
app.get('/status', (req, res) => {
const states = relay.getAllRelayStates();
res.json({ states });
});
// 서버 시작
relay.open().then(() => {
app.listen(3000, () => {
console.log('릴레이 제어 서버 실행 중: http://localhost:3000');
});
});🖥️ GUI 애플리케이션
이 패키지는 Electron 기반 GUI 애플리케이션도 포함하고 있습니다.
npm start # GUI 앱 실행
npm run dev # 개발 모드 (로그 활성화)
npm run build # 실행 파일 빌드🛠️ 문제 해결
USB 장치를 찾을 수 없음
const devices = relay.enumerate();
if (devices.length === 0) {
console.log('USB 릴레이 장치가 연결되지 않았습니다');
console.log('- USB 케이블 확인');
console.log('- 드라이버 설치 확인');
console.log('- VID/PID 확인: 0x16c0/0x05df');
}연결은 되지만 제어가 안됨
relay.on('handshake-failed', (data) => {
console.error('핸드셰이크 실패:', data.error);
console.log('장치가 올바른 USB 릴레이인지 확인하세요');
});Linux 권한 문제
# udev 규칙 추가
sudo nano /etc/udev/rules.d/99-usb-relay.rules
# 다음 내용 추가:
# SUBSYSTEM=="usb", ATTR{idVendor}=="16c0", ATTR{idProduct}=="05df", MODE="0666"
# udev 재시작
sudo udevadm control --reload-rules
sudo udevadm trigger📄 라이선스
MIT License - 자유롭게 사용하세요!
🤝 기여
이슈와 풀 리퀘스트를 환영합니다!
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📞 지원
- Issues: GitHub Issues
- Email: [email protected]
- Website: https://samlab.co.kr
🙏 감사의 말
- node-hid - USB HID 통신 라이브러리
- USB 릴레이 커뮤니티의 모든 기여자분들
Made with ❤️ by Samlab Corp
