Compare commits

...

6 commits
v0.4.0 ... main

Author SHA1 Message Date
f90a7cd66d Frontend: put version number in static URL to cache-bust on updates
All checks were successful
/ build-container (push) Successful in 8m40s
2025-02-23 14:48:35 -08:00
426ab872dd somewhat improve style
All checks were successful
/ build-container (push) Successful in 9m0s
2025-02-23 14:30:56 -08:00
6920f9ee24 drop max code length to 4
All checks were successful
/ build-container (push) Successful in 9m15s
2024-11-26 13:48:19 -08:00
1340b3167f Add a button to generate codes
All checks were successful
/ build-container (push) Successful in 9m6s
2024-11-25 14:38:51 -08:00
7a0420bb46 Update CSS
All checks were successful
/ build-container (push) Successful in 8m50s
2024-11-24 19:49:27 -08:00
4627ae91b3 add readme and limit log entry counts displayed
All checks were successful
/ build-container (push) Successful in 8m0s
2024-11-24 16:36:18 -08:00
13 changed files with 76 additions and 51 deletions

View file

@ -7,7 +7,7 @@ jobs:
steps:
- run: apk add --no-cache nodejs git
- name: login to container registry
run: echo "${{ secrets.PACKAGE_PUBLISH_TOKEN }}" | docker login --username finn --password-stdin git.janky.solutions
run: echo "${{ secrets.PACKAGE_PUBLISH_TOKEN }}" | docker login --username ${{ secrets.PACKAGE_PUBLISH_USER }} --password-stdin git.janky.solutions
- name: gather metadata for container image tags
uses: https://github.com/docker/metadata-action@v5
id: meta
@ -20,7 +20,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
push: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') }}
build-args: |
VERSION_STRING=${{ env.GITHUB_REF_NAME }}
- name: update hassio-addons

View file

@ -19,7 +19,7 @@ RUN apk add --no-cache go
ADD . /go/lockserver
WORKDIR /go/lockserver
ARG VERSION_STRING
RUN CGO_ENABLED=0 go build -ldflags "-X git.devhack.net/devhack/member-services/config.Version=${VERSION_STRING}" ./cmd/lockserver
RUN CGO_ENABLED=0 go build -ldflags "-X git.janky.solutions/finn/lockserver/config.Version=${VERSION_STRING}" ./cmd/lockserver
FROM scratch
COPY --from=build /go/lockserver/lockserver /lockserver

18
README.md Normal file
View file

@ -0,0 +1,18 @@
# lockserver
_better Z-Wave Lock management for Home Assistant_
## Status
This is a work in progress. I have some ideas of where I want it to go, but I'm mostly experimenting with my own needs.
## Install
To add to Home Assistant, add my hassio-addons repo by clicking the button below, then search for and install the "LockServer" addon.
[![Add to Home Assistant.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgit.janky.solutions%2Ffinn%2Fhassio-addons)
## Usage
When you open the addon's web UI, it will show a list of Z-Wave locks. Clicking a lock shows all codes slots for that lock. Clicking edit on each slot allows changing the code, changing the name, enabling or disabling the slot, and seeing a log of recent uses of that code.

View file

@ -26,5 +26,9 @@ func init() {
break
}
}
if Version == "" {
Version = "development"
}
}
}

View file

@ -97,7 +97,7 @@ func (q *Queries) GetLogForLock(ctx context.Context, lock int64) ([]LockLog, err
}
const getLogForSlot = `-- name: GetLogForSlot :many
SELECT lock, timestamp, state, code, issued_code FROM lock_log WHERE lock = ? AND code = ? ORDER BY timestamp DESC
SELECT lock, timestamp, state, code, issued_code FROM lock_log WHERE lock = ? AND code = ? ORDER BY timestamp DESC LIMIT 100
`
type GetLogForSlotParams struct {

View file

@ -5,7 +5,7 @@ INSERT INTO lock_log (lock, state, code) VALUES (?, ?, ?);
SELECT * FROM lock_log WHERE lock = ? ORDER BY timestamp DESC;
-- name: GetLogForSlot :many
SELECT * FROM lock_log WHERE lock = ? AND code = ? ORDER BY timestamp DESC;
SELECT * FROM lock_log WHERE lock = ? AND code = ? ORDER BY timestamp DESC LIMIT 100;
-- name: GetLastLogForSlot :many
SELECT * FROM lock_log WHERE lock = ? AND code = ? ORDER BY timestamp DESC LIMIT 1;

View file

@ -2,7 +2,6 @@ package frontend
import (
"embed"
"fmt"
"html/template"
"io/fs"
"time"
@ -20,7 +19,7 @@ var (
Templates *template.Template
funcs = template.FuncMap{
"version": func() string { return fmt.Sprintf("better-zwave-locks %s", config.Version) },
"version": func() string { return config.Version },
"time_since": func(t time.Time) string { return time.Since(t).Round(time.Second).String() },
}
)

View file

@ -5,7 +5,7 @@
<title>Better Z-Wave Locks for Home Assistant</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="{{ .BaseURL }}/static/main.css" />
<link rel="stylesheet" href="{{ .BaseURL }}/static-{{ version }}/main.css" />
</head>
<body>

View file

@ -1,28 +1,11 @@
{{ template "header.html" . }}
<h1>Better Z-Wave Locks</h1>
<!-- <header>Active Codes</header>
[ <a href="{{ .BaseURL }}/add-code">add</a> ]
<table border="1">
<tr>
<th>Name</th>
<th>Code</th>
<th>Last used</th>
<th>Expires</th>
<th>Actions</th>
</tr>
{{ range .ActiveCodes }}
<tr>
<td>{{ .Name.Value }}</td>
<td>{{ .Code }}</td>
<td>0.005ms ago on <a href="{{ $.BaseURL }}/locks/1">Back Door</a></td>
<td>{{ .End.Value }}</td>
<td><a href="#">details</a> | <a href="#">delete</a></td>
</tr>
{{ end }}
</table> -->
<br /><br />
<header>locks</header>
<ul>
{{ range .Locks }}<li><a href="{{ $.BaseURL }}/locks/{{ .ID }}">{{ .Name }} ({{ .ZwaveDeviceID }})</a></li>{{ end }}
</ul>
<span class="table">
{{ range .Locks }}
<a class="table-row" href="{{ $.BaseURL }}/locks/{{ .ID }}">
<p class="table-cell">{{ if eq .Name "" }}Lock #{{ .ZwaveDeviceID }}{{ else }}{{ .Name }}{{ end }}</p>
</a>
{{ end }}
</span>
{{ template "footer.html" }}

View file

@ -2,7 +2,7 @@
<header>{{ if eq .Data.lock.Name "" }}Lock #{{ .Data.lock.ID }}{{ else }}{{ .Data.lock.Name }}{{ end }} Slot #{{ .Data.code.Slot }}</header>
<br />
<form method="post">
Code: <input type="text" name="code" value="{{ .Data.code.Code }}" /><br />
Code: <input type="text" name="code" value="{{ .Data.code.Code }}" id="code" /> <a href="#" onclick="generateCode()">🔄</a><br />
Name: <input type="text" name="name" value="{{ .Data.code.Name }}" /><br />
Enabled: <input type="checkbox" name="enabled" {{ if .Data.code.Enabled }}checked{{ end }} /><br />
<br />
@ -15,4 +15,14 @@
<li>{{ $entry.State }} (<i>{{ $entry.Timestamp | time_since }} ago</i>)</li>
{{ end }}
</ul>
<script type="text/javascript">
function generateCode() {
let code = "";
while(code.length < 4) {
code += Math.round(Math.random()*10);
}
document.querySelector('#code').value = code;
}
</script>
{{ template "footer.html" }}

View file

@ -2,24 +2,18 @@
<header>{{ if eq .Data.lock.Name "" }}Lock #{{ .Data.lock.ID }}{{ else }}{{ .Data.lock.Name }}{{ end }}</header>
[ <a href="{{ $.BaseURL }}/locks/{{ .Data.lock.ID }}/edit">rename</a> ]<br />
<br />
<table class="table">
<tr>
<td>Slot</td>
<td>Name</td>
<td>Code</td>
<td>Enabled?</td>
<td>Actions</td>
</tr>
<span class="table">
<span class="table-row">
<span class="table-cell">Name</span>
<span class="table-cell">Code</span>
</span>
{{ 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="{{ $.BaseURL }}/locks/{{ $.Data.lock.ID }}/codes/{{ $code.Slot }}">edit</a> ]</td>
</tr>
<a href="{{ $.BaseURL }}/locks/{{ $.Data.lock.ID }}/codes/{{ $code.Slot }}" class="table-row code-{{ if $code.Enabled }}enabled{{ else }}disabled{{ end }}">
<span class="table-cell">{{ $code.Name }}</span>
<span class="table-cell">{{ $code.Code }}</span>
</a>
{{ end }}
</table>
</span>
<br /><br />

View file

@ -16,6 +16,8 @@ a {
flex-direction: column;
row-gap: 1em;
padding: 1em;
margin: auto;
max-width: 1000px;
}
#main {
@ -28,9 +30,24 @@ header {
}
.code-enabled {
background-color: #0a0;
background-color: #050;
}
.table {
width: 100%;
display: flex;
flex-direction: column;
}
.table-row {
border-bottom: solid #999 1px;
/* background-color: #333; */
height: 3em;
display: flex;
flex-direction: row;
justify-content: space-around;
}
.table-row:first {
border-top: solid #999 1px;
}

View file

@ -28,7 +28,7 @@ func ListenAndServe(zwaveClient *zwavejs.Client) {
server.Use(accessLogMiddleware)
server.RouteNotFound("/*", tmpl("404.html"))
server.StaticFS("/static", frontend.Static)
server.StaticFS("/static-"+config.Version, frontend.Static)
server.GET("/", indexHandler)
server.GET("/locks/:lock", lockHandler)
server.GET("/locks/:lock/edit", lockEditHandler)