feat(hal): add EBDS bill validator driver for BATM3 support
Port MEI CashFlow SC / BNR Advance EBDS protocol from lamassu-machine to TypeScript HAL. Adds 'batm3' machine model preset (EBDS validator + F56 dispenser). Fixes hardcoded 'id003' validator type in device config overrides so model presets correctly propagate their validator type. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2cc0acfdef
commit
71eff33f1e
11 changed files with 814 additions and 13 deletions
|
|
@ -15,7 +15,7 @@ import type { HalConfig, CassetteConfig } from '@/services/hal'
|
|||
/**
|
||||
* Supported machine models
|
||||
*/
|
||||
export type MachineModel = 'sintra' | 'tejo' | 'douro' | 'gaia' | 'custom'
|
||||
export type MachineModel = 'sintra' | 'tejo' | 'douro' | 'gaia' | 'batm3' | 'custom'
|
||||
|
||||
/**
|
||||
* Full device configuration
|
||||
|
|
@ -28,7 +28,7 @@ export interface DeviceConfig {
|
|||
/** Bill validator configuration */
|
||||
validator: {
|
||||
/** Validator protocol type */
|
||||
type: 'id003'
|
||||
type: 'id003' | 'ebds'
|
||||
/** Serial device path(s) */
|
||||
device: string | string[]
|
||||
}
|
||||
|
|
@ -130,6 +130,27 @@ export const MACHINE_PRESETS: Record<MachineModel, Omit<DeviceConfig, 'fiatCode'
|
|||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* General Bytes BATM3 (XL variant)
|
||||
* - Validator: MEI BNR Advance or CashFlow SC (EBDS protocol, USB CDC ACM)
|
||||
* - Dispenser: Fujitsu F56 (RS232)
|
||||
*/
|
||||
batm3: {
|
||||
model: 'batm3',
|
||||
validator: {
|
||||
type: 'ebds',
|
||||
device: '/dev/ttyACM0',
|
||||
},
|
||||
dispenser: {
|
||||
type: 'f56',
|
||||
device: '/dev/ttyUSB0',
|
||||
cassettes: [
|
||||
{ denomination: 20, count: 500 },
|
||||
{ denomination: 50, count: 500 },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Custom configuration - all values must be provided via env/runtime
|
||||
*/
|
||||
|
|
@ -200,10 +221,10 @@ export function loadDeviceConfigFromEnv(): DeviceConfig {
|
|||
|
||||
const overrides: Partial<DeviceConfig> = {}
|
||||
|
||||
// Validator device override
|
||||
// Validator device override (preserve validator type from preset)
|
||||
const validatorDevice = import.meta.env.VITE_LAMASSU_VALIDATOR_DEVICE
|
||||
if (validatorDevice) {
|
||||
overrides.validator = { type: 'id003', device: validatorDevice }
|
||||
overrides.validator = { type: MACHINE_PRESETS[model].validator.type, device: validatorDevice }
|
||||
}
|
||||
|
||||
// Dispenser device override
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export interface CassetteConfig {
|
|||
|
||||
export interface HalConfig {
|
||||
validator: {
|
||||
type: 'id003'
|
||||
type: 'id003' | 'ebds'
|
||||
device: string | string[]
|
||||
fiatCode: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -767,13 +767,18 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
fiatCode.value = runtimeFiatCode
|
||||
|
||||
// Build device config from runtime values
|
||||
const { getDeviceConfig, toHalConfig } = await import('@/config')
|
||||
const { getDeviceConfig, toHalConfig, MACHINE_PRESETS } = await import('@/config')
|
||||
const preset = MACHINE_PRESETS[model] ?? MACHINE_PRESETS.sintra
|
||||
const overrides: any = {}
|
||||
if (runtimeConfig.validatorDevice) {
|
||||
overrides.validator = { type: 'id003', device: runtimeConfig.validatorDevice }
|
||||
overrides.validator = { type: preset.validator.type, device: runtimeConfig.validatorDevice }
|
||||
}
|
||||
if (runtimeConfig.dispenserDevice) {
|
||||
overrides.dispenser = { type: 'f56', device: runtimeConfig.dispenserDevice, cassettes: [] }
|
||||
overrides.dispenser = {
|
||||
type: preset.dispenser.type,
|
||||
device: runtimeConfig.dispenserDevice,
|
||||
cassettes: [],
|
||||
}
|
||||
}
|
||||
if (runtimeConfig.cassettes) {
|
||||
try {
|
||||
|
|
@ -781,7 +786,7 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
if (overrides.dispenser) {
|
||||
overrides.dispenser.cassettes = cassettes
|
||||
} else {
|
||||
overrides.dispenser = { type: 'f56', device: '', cassettes }
|
||||
overrides.dispenser = { type: preset.dispenser.type, device: '', cassettes }
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[ATM] Failed to parse cassettes:', e)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue