Add support for editing individual lock code slots
Some checks failed
/ build-container (push) Has been cancelled

This commit is contained in:
Finn 2024-11-22 22:25:39 -08:00
parent 6ec7434ab6
commit cafbd63f98
7 changed files with 44 additions and 8 deletions

View file

@ -130,7 +130,7 @@ func (q *Queries) GetLockCodesByCode(ctx context.Context, code string) ([]LockCo
}
const upsertCodeSlot = `-- name: UpsertCodeSlot :exec
INSERT INTO lock_code_slots (lock, slot, code, enabled, name) VALUES (?, ?, ?, ?, "") ON CONFLICT (lock, slot) DO UPDATE SET code=excluded.code, enabled=excluded.enabled
INSERT INTO lock_code_slots (lock, slot, code, enabled, name) VALUES (?, ?, ?, ?, ?) ON CONFLICT (lock, slot) DO UPDATE SET code=excluded.code, enabled=excluded.enabled, name=excluded.name
`
type UpsertCodeSlotParams struct {
@ -138,6 +138,7 @@ type UpsertCodeSlotParams struct {
Slot int64
Code string
Enabled bool
Name string
}
func (q *Queries) UpsertCodeSlot(ctx context.Context, arg UpsertCodeSlotParams) error {
@ -146,6 +147,7 @@ func (q *Queries) UpsertCodeSlot(ctx context.Context, arg UpsertCodeSlotParams)
arg.Slot,
arg.Code,
arg.Enabled,
arg.Name,
)
return err
}

View file

@ -1,5 +1,5 @@
-- name: UpsertCodeSlot :exec
INSERT INTO lock_code_slots (lock, slot, code, enabled, name) VALUES (?, ?, ?, ?, "") ON CONFLICT (lock, slot) DO UPDATE SET code=excluded.code, enabled=excluded.enabled;
INSERT INTO lock_code_slots (lock, slot, code, enabled, name) VALUES (?, ?, ?, ?, ?) ON CONFLICT (lock, slot) DO UPDATE SET code=excluded.code, enabled=excluded.enabled, name=excluded.name;
-- name: GetLockCodeBySlot :one
SELECT * FROM lock_code_slots WHERE lock = ? AND slot = ?;

View file

@ -10,4 +10,5 @@
<body>
<div id="wrapper">
<a href="/">Home</a>
<div id="main">

View file

@ -1,7 +1,10 @@
{{ template "header.html" . }}
<header>Rename {{ if eq .Data.Name "" }}Lock #{{ .Data.ID }}{{ else }}{{ .Data.Name }}{{ end }}</header>
<header>{{ if eq .Data.Name "" }}Lock #{{ .Data.ID }}{{ else }}{{ .Data.Name }}{{ end }}</header>
<form method="post">
Code: <input type="text" name="code" value="{{ .Data.Code }}" /><br />
Name: <input type="text" name="name" value="{{ .Data.Name }}" /><br />
Enabled: <input type="checkbox" name="enabled" {{ if .Data.Enabled }}checked{{ end }} /><br />
<br />
<input type="submit" value="save" />
</form>
{{ template "footer.html" }}

View file

@ -1,10 +1,11 @@
{{ template "header.html" . }}
<header>{{ if eq .Data.lock.Name "" }}Lock #{{ .Data.lock.ID }}{{ else }}{{ .Data.lock.Name }}{{ end }}</header>
[ <a href="/locks/{{ .Data.lock.ID }}/edit">rename</a> ]
[ <a href="/locks/{{ .Data.lock.ID }}/edit">rename</a> ]<br />
<br />
<table border="1">
<tr>
<td>Slot</td>
<td>Name</td>
<td>Code</td>
<td>Enabled?</td>
<td>Actions</td>
@ -12,6 +13,7 @@
{{ range $_, $code := .Data.codes }}
<tr class="code-{{ if $code.Enabled }}enabled{{ else }}disabled{{ end }}">
<td>{{ $code.Slot }}</td>
<td>{{ $code.Name }}</td>
<td>{{ $code.Code }}</td>
<td>{{ if $code.Enabled }}enabled{{ else }}disabled{{ end }}</td>
<td>[ <a href="/locks/{{ $.Data.lock.ID }}/codes/{{ $code.Slot }}">edit</a> ]</td>

View file

@ -111,9 +111,27 @@ func lockCodeEditHandler(c echo.Context) error {
return err
}
newCode := c.FormValue("code")
zwaveClient := c.Get(contextKeyZWaveClient).(*zwavejs.Client)
enabled := c.FormValue("enabled") == "on"
enabledInt := 0
if enabled {
enabledInt = 1
}
err = zwaveClient.SetNodeValue(ctx, int(lock.ZwaveDeviceID), zwavejs.NodeValue{
CCVersion: 1,
CommandClassName: zwavejs.CommandClassNameUserCode,
CommandClass: zwavejs.CommandClassUserCode,
Endpoint: 0,
Property: zwavejs.AnyType{Type: zwavejs.AnyTypeString, String: string(zwavejs.PropertyUserIDStatus)},
PropertyName: zwavejs.AnyType{Type: zwavejs.AnyTypeString, String: string(zwavejs.PropertyUserIDStatus)},
PropertyKey: zwavejs.AnyType{Type: zwavejs.AnyTypeInt, Int: int(slot)},
}, zwavejs.AnyType{Type: zwavejs.AnyTypeInt, Int: enabledInt})
if err != nil {
return fmt.Errorf("error pushing enabled state to lock %s (ZWaveDeviceID=%d ID=%d): %v", lock.Name, lock.ZwaveDeviceID, lock.ID, err)
}
newCode := c.FormValue("code")
err = zwaveClient.SetNodeValue(ctx, int(lock.ZwaveDeviceID), zwavejs.NodeValue{
CCVersion: 1,
CommandClassName: zwavejs.CommandClassNameUserCode,
@ -131,7 +149,8 @@ func lockCodeEditHandler(c echo.Context) error {
Lock: lockID,
Slot: slot,
Code: newCode,
Enabled: true,
Name: c.FormValue("name"),
Enabled: enabled,
})
if err != nil {
return err

View file

@ -43,8 +43,10 @@ func (c *Client) DialAndListen(ctx context.Context) {
for {
logrus.WithField("server", c.Server).Info("connecting to zwave-js server")
ctxWithTimeout, cancel := context.WithTimeout(ctx, time.Second*5)
defer cancel()
conn, err := failsafe.Get(func() (*websocket.Conn, error) {
conn, _, err := websocket.DefaultDialer.DialContext(ctx, c.Server, nil)
conn, _, err := websocket.DefaultDialer.DialContext(ctxWithTimeout, c.Server, nil)
return conn, err
}, connectRetryPolicy)
if err != nil {
@ -63,6 +65,7 @@ func (c *Client) DialAndListen(ctx context.Context) {
continue
}
_ = c.conn.Close()
cancel()
}
}
@ -234,6 +237,8 @@ func (c *Client) handleCallback(messageID string, result Result) error {
c.callbacksLock.Lock()
defer c.callbacksLock.Unlock()
logrus.WithField("message_id", messageID).Debug(fmt.Sprintf("%+v", result))
cb, ok := c.callbacks[messageID]
if !ok {
logrus.WithField("message_id", messageID).Warn("got response to a message we didn't send")
@ -255,6 +260,10 @@ func (c *Client) sendMessage(message OutgoingMessageIface) (Result, error) {
c.callbacks[messageID] = ch
c.callbacksLock.Unlock()
// w := logrus.WithField("message_id", messageID).Writer()
// json.NewEncoder(w).Encode(message)
// w.Close()
if err := c.conn.WriteJSON(message); err != nil {
return Result{}, err
}