diff --git a/lockserver/assalockserver.go b/lockserver/assalockserver.go index dbd7615..5fad505 100644 --- a/lockserver/assalockserver.go +++ b/lockserver/assalockserver.go @@ -10,11 +10,11 @@ import ( ) // Build key encoding request command for the Assa Abloy lock server. -func (lock *AssaLockServer) BuildCommand(lockId string, checkIn, checkOut time.Time) error { +func (lock *AssaLockServer) BuildCommand(doorReq DoorCardRequest, checkIn, checkOut time.Time) error { ci := checkIn.Format("200601021504") co := checkOut.Format("200601021504") - lock.command = fmt.Sprintf("CCA;EA%s;GR%s;CO%s;CI%s;AM1;\r\n", lock.encoderAddr, lockId, co, ci) + lock.command = fmt.Sprintf("CCA;EA%s;GR%s;CO%s;CI%s;AM1;\r\n", lock.encoderAddr, doorReq.RoomField, co, ci) return nil } diff --git a/lockserver/lockservercommon.go b/lockserver/lockservercommon.go index c81ff08..9ee83c5 100644 --- a/lockserver/lockservercommon.go +++ b/lockserver/lockservercommon.go @@ -12,6 +12,14 @@ import ( log "github.com/sirupsen/logrus" ) +// DoorCardRequest is the JSON payload for /issue-door-card. +type DoorCardRequest struct { + RoomField string `json:"roomField"` + CheckinTime string `json:"checkinTime"` + CheckoutTime string `json:"checkoutTime"` + FollowStr string `json:"followStr"` +} + const ( AssaAbloy = "assaabloy" Omnitec = "omnitec" @@ -20,7 +28,7 @@ const ( type ( LockServer interface { - BuildCommand(lockId string, checkIn, checkOut time.Time) error + BuildCommand(doorReq DoorCardRequest, checkIn, checkOut time.Time) error LockSequence(conn net.Conn) error } diff --git a/lockserver/omnilockserver.go b/lockserver/omnilockserver.go index 2d8f541..396462a 100644 --- a/lockserver/omnilockserver.go +++ b/lockserver/omnilockserver.go @@ -13,7 +13,7 @@ import ( ) // Build key encoding request command for the Omnitec lock server. -func (lock *OmniLockServer) BuildCommand(lockId string, checkIn, checkOut time.Time) error { +func (lock *OmniLockServer) BuildCommand(doorReq DoorCardRequest, checkIn, checkOut time.Time) error { const funcName = "OmniLockServer.BuildCommand" hostname, err := os.Hostname() if err != nil { @@ -21,7 +21,7 @@ func (lock *OmniLockServer) BuildCommand(lockId string, checkIn, checkOut time.T } // Format lockId as 4-digit zero-padded string - idInt, err := strconv.Atoi(lockId) + idInt, err := strconv.Atoi(doorReq.RoomField) if err != nil { return fmt.Errorf("[%s] failed to convert lockId to integer: %v", funcName, err) } diff --git a/lockserver/saltolockserver.go b/lockserver/saltolockserver.go index 5348365..6fcfe28 100644 --- a/lockserver/saltolockserver.go +++ b/lockserver/saltolockserver.go @@ -41,8 +41,9 @@ func stringJoin(parts []string, sep string) string { // BuildCommand builds a Salto card‑issuance command in the form: // STX|CN||E|| | | | | |||ETX| // where and are hhmmDDMMYY, and LRC is the XOR of all bytes -func (lock *SaltoLockServer) BuildCommand(lockId string, checkIn, checkOut time.Time) error { +func (lock *SaltoLockServer) BuildCommand(doorReq DoorCardRequest, checkIn, checkOut time.Time) error { // format helper: hhmmDDMMYY + var command string fmtStamp := func(t time.Time) string { return fmt.Sprintf("%02d%02d%02d%02d%02d", t.Hour(), t.Minute(), t.Day(), int(t.Month()), t.Year()%100) @@ -51,9 +52,18 @@ func (lock *SaltoLockServer) BuildCommand(lockId string, checkIn, checkOut time. start := fmtStamp(checkIn) expiry := fmtStamp(checkOut) + switch doorReq.FollowStr { + case "0": + command = "CN" // encode keycard + case "1": + command = "CC" // encode keycard copy + default: + command = "CN" + } + // the 12 fields between STX and ETX fields := []string{ - "CN", lock.encoderAddr, "E", lockId, "", "", "", "", "", "", start, expiry, + command, lock.encoderAddr, "E", doorReq.RoomField, "", "", "", "", "", "", start, expiry, } body := "|" + stringJoin(fields, "|") + "|" // leading/trailing pipes, so the ETX ends the last field diff --git a/main.go b/main.go index 7ae2cfa..f79e355 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ import ( ) const ( - buildVersion = "1.0.4" + buildVersion = "1.0.5" serviceName = "hardlink" customLayout = "2006-01-02 15:04:05 -0700" transactionUrl = "http://127.0.0.1:18181/start-transaction/" @@ -49,13 +49,6 @@ type configRec struct { isPayment bool `yaml:"isPayment"` } -// DoorCardRequest is the JSON payload for /issue-door-card. -type DoorCardRequest struct { - RoomField string `json:"roomField"` - CheckinTime string `json:"checkinTime"` - CheckoutTime string `json:"checkoutTime"` - FollowStr string `json:"followStr"` -} // App holds shared resources. type App struct { @@ -179,6 +172,7 @@ func main() { } // Create App and wire routes + // dispHandle := &serial.Port{} // Placeholder, replace with actual dispenser handle app := newApp(dispHandle, lockConn, config) mux := http.NewServeMux() @@ -323,7 +317,7 @@ func (app *App) startTransaction(w http.ResponseWriter, r *http.Request) { func (app *App) issueDoorCard(w http.ResponseWriter, r *http.Request) { const op = logging.Op("issueDoorCard") var ( - doorReq DoorCardRequest + doorReq lockserver.DoorCardRequest theResponse cmstypes.StatusRec ) @@ -384,7 +378,7 @@ func (app *App) issueDoorCard(w http.ResponseWriter, r *http.Request) { } // build lock server command - app.lockserver.BuildCommand(doorReq.RoomField, checkIn, checkOut) + app.lockserver.BuildCommand(doorReq, checkIn, checkOut) // lock server sequence err = app.lockserver.LockSequence(app.lockConn) diff --git a/release notes.md b/release notes.md index 107cfad..df41db9 100644 --- a/release notes.md +++ b/release notes.md @@ -2,9 +2,11 @@ builtVersion is a const in main.go -#### 1.0.1 - 22 July 2024 -added salto lock server and implemented workflow for Salto - +#### 1.0.5 - 24 July 2024 +added encoding keycard copy for Salto locks + +#### 1.0.4 - 22 July 2024 +added salto lock server and implemented workflow for Salto #### 1.0.0 - 30 June 2024 added creditcall payment method