import { pgTable, timestamp, varchar, integer, text, index, } from 'drizzle-orm/pg-core' /** * 充电桩表 * 对应OCPP 1.6-J BootNotification.req中的基本信息 */ export const chargePoint = pgTable('charge_point', { id: varchar('id').primaryKey(), chargePointIdentifier: varchar('charge_point_identifier', { length: 100, }) .unique() .notNull(), chargePointSerialNumber: varchar('charge_point_serial_number', { length: 25, }), chargePointModel: varchar('charge_point_model', { length: 20 }).notNull(), chargePointVendor: varchar('charge_point_vendor', { length: 20 }).notNull(), firmwareVersion: varchar('firmware_version', { length: 50 }), iccid: varchar('iccid', { length: 20 }), imsi: varchar('imsi', { length: 20 }), meterSerialNumber: varchar('meter_serial_number', { length: 25 }), meterType: varchar('meter_type', { length: 25 }), createdAt: timestamp('created_at').notNull().defaultNow(), updatedAt: timestamp('updated_at') .notNull() .defaultNow() .$onUpdate(() => new Date()), }) /** * 连接器表 * OCPP 1.6-J 2.2术语定义: * "Connector" 指充电桩上可独立操作和管理的电气插座。通常对应单个物理连接器, * 但某些情况下一个插座可能有多个物理插座类型和/或拴住的电缆/连接器安排 * 以适应不同的车辆类型(如四轮电动汽车和电动滑板车)。 * * 连接器ID规范: * - 第一个连接器的ID必须是1 * - 额外的连接器必须按顺序编号(不能跳过) * - 连接器ID不能超过充电桩的总连接器数 * - ID为0保留用于主控制器(在报告时)或整个充电桩(在中央系统的操作时) */ export const connector = pgTable( 'connector', { id: varchar('id').primaryKey(), chargePointId: varchar('charge_point_id') .notNull() .references(() => chargePoint.id, { onDelete: 'cascade' }), /** * 连接器编号(connectorId) * OCPP 1.6-J 6.47 StatusNotification.req: * "The id of the connector for which the status is reported. * Id '0' (zero) is used if the status is for the Charge Point main controller." * connectorId > 0 对实际连接器, connectorId = 0 表示主控制器 */ connectorId: integer('connector_id').notNull(), /** * 当前状态(status字段) * OCPP 1.6-J 7.7 ChargePointStatus: * - Available: 连接器可用于新用户 * - Preparing: 用户提示卡、插入电缆或车辆占用停泊位时 * - Charging: 接触器闭合,允许车辆充电 * - SuspendedEVSE: EV连接但EVSE不提供能量 * - SuspendedEV: EVSE提供能量但EV不取用 * - Finishing: 交易已停止但连接器未准备好新用户 * - Reserved: 连接器因ReserveNow命令被保留 * - Unavailable: 因ChangeAvailability命令不可用(非运行态) * - Faulted: 充电桩或连接器报告错误且不可用(非运行态) */ status: varchar('status', { enum: [ 'Available', 'Preparing', 'Charging', 'SuspendedEVSE', 'SuspendedEV', 'Finishing', 'Reserved', 'Unavailable', 'Faulted', ], }).notNull(), /** * 错误代码(errorCode字段) * OCPP 1.6-J 7.6 ChargePointErrorCode */ errorCode: varchar('error_code', { enum: [ 'NoError', 'ConnectorLockFailure', 'EVCommunicationError', 'GroundFailure', 'HighTemperature', 'InternalError', 'LocalListConflict', 'OtherError', 'OverCurrentFailure', 'OverVoltage', 'PowerMeterFailure', 'PowerSwitchFailure', 'ReaderFailure', 'ResetFailure', 'UnderVoltage', 'WeakSignal', ], }) .notNull() .default('NoError'), /** * 供应商标识(vendorId字段) * OCPP 1.6-J 6.47: "This identifies the vendor-specific implementation." * CiString255Type - 不超过255个字符 */ vendorId: varchar('vendor_id', { length: 255 }), /** * 供应商特定错误代码(vendorErrorCode字段) * OCPP 1.6-J 6.47: "This contains the vendor-specific error code." * CiString50Type - 不超过50个字符 */ vendorErrorCode: varchar('vendor_error_code', { length: 50 }), /** * 附加信息(info字段) * OCPP 1.6-J 6.47: "Additional free format information related to the error." * CiString50Type - 不超过50个字符 */ info: varchar('info', { length: 50 }), /** * 最后一次状态更新时间 * OCPP 1.6-J 6.47: "The time for which the status is reported. * If absent time of receipt of the message will be assumed." */ lastStatusUpdate: timestamp('last_status_update').notNull().defaultNow(), createdAt: timestamp('created_at').notNull().defaultNow(), updatedAt: timestamp('updated_at') .notNull() .defaultNow() .$onUpdate(() => new Date()), }, (table) => ({ chargePointIdIdx: index('idx_connector_charge_point_id').on( table.chargePointId ), connectorIdIdx: index('idx_connector_connector_id').on( table.chargePointId, table.connectorId ), }) ) /** * 连接器状态历史表 * 记录StatusNotification.req的完整消息内容,用于审计和历史查询 * 对应 OCPP 1.6-J 6.47 StatusNotification.req 消息 */ export const connectorStatusHistory = pgTable( 'connector_status_history', { id: varchar('id').primaryKey(), connectorId: varchar('connector_id') .notNull() .references(() => connector.id, { onDelete: 'cascade' }), /** * 连接器编号(connectorId) * OCPP 1.6-J 6.47: connectorId >= 0 */ connectorNumber: integer('connector_number').notNull(), /** * 状态值 * OCPP 1.6-J 7.7 ChargePointStatus */ status: varchar('status', { enum: [ 'Available', 'Preparing', 'Charging', 'SuspendedEVSE', 'SuspendedEV', 'Finishing', 'Reserved', 'Unavailable', 'Faulted', ], }).notNull(), /** * 错误代码 * OCPP 1.6-J 7.6 ChargePointErrorCode */ errorCode: varchar('error_code', { enum: [ 'NoError', 'ConnectorLockFailure', 'EVCommunicationError', 'GroundFailure', 'HighTemperature', 'InternalError', 'LocalListConflict', 'OtherError', 'OverCurrentFailure', 'OverVoltage', 'PowerMeterFailure', 'PowerSwitchFailure', 'ReaderFailure', 'ResetFailure', 'UnderVoltage', 'WeakSignal', ], }).notNull(), /** * 附加信息 * OCPP 1.6-J 6.47: "Additional free format information related to the error." */ info: varchar('info', { length: 50 }), /** * 供应商标识 * OCPP 1.6-J 6.47: "This identifies the vendor-specific implementation." */ vendorId: varchar('vendor_id', { length: 255 }), /** * 供应商错误代码 * OCPP 1.6-J 6.47: "This contains the vendor-specific error code." */ vendorErrorCode: varchar('vendor_error_code', { length: 50 }), /** * 状态报告时间戳 * OCPP 1.6-J 6.47: "The time for which the status is reported. * If absent time of receipt of the message will be assumed." */ statusTimestamp: timestamp('status_timestamp'), /** * 消息接收时间 */ receivedAt: timestamp('received_at').notNull().defaultNow(), }, (table) => ({ connectorIdIdx: index('idx_status_history_connector_id').on( table.connectorId ), statusTimestampIdx: index('idx_status_history_timestamp').on( table.statusTimestamp ), receivedAtIdx: index('idx_status_history_received_at').on( table.receivedAt ), }) )