Compare commits
7 Commits
4aad657c9d
...
v1.2.2
Author | SHA1 | Date | |
---|---|---|---|
aac191521f | |||
96fe2d04cb | |||
d858b9e7c8 | |||
4b2248a6d7 | |||
![]() |
53722bdf18 | ||
![]() |
cf35326bf2 | ||
![]() |
cb397b7cd3 |
@@ -27,7 +27,7 @@ type ChangeLockReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ChangeAlertReq struct {
|
type ChangeAlertReq struct {
|
||||||
Alert bool `json:"alert"`
|
Alert bool `json:"alerts"`
|
||||||
For int `json:"for"`
|
For int `json:"for"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ func makeGetReq(url string) ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() { res.Body.Close() }()
|
defer func() { _ = res.Body.Close() }()
|
||||||
|
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
fmt.Printf("<-- %d\n", res.StatusCode)
|
fmt.Printf("<-- %d\n", res.StatusCode)
|
||||||
@@ -120,7 +120,7 @@ func main() {
|
|||||||
Action: test,
|
Action: test,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "open",
|
Name: "opened",
|
||||||
Usage: "get door state (opened or closed)",
|
Usage: "get door state (opened or closed)",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
@@ -131,34 +131,38 @@ func main() {
|
|||||||
Action: getOpened,
|
Action: getOpened,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "lock",
|
Name: "locked",
|
||||||
Usage: "change lock status",
|
Usage: "change lock status",
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "on",
|
Name: "yes",
|
||||||
Usage: "lock the door",
|
Usage: "lock the door",
|
||||||
Action: createManageLock(true),
|
Aliases: []string{"y", "on", "1", "do"},
|
||||||
|
Action: createManageLock(true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "off",
|
Name: "no",
|
||||||
Usage: "unlock the door",
|
Usage: "unlock the door",
|
||||||
Action: createManageLock(false),
|
Aliases: []string{"n", "off", "0", "undo"},
|
||||||
|
Action: createManageLock(false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: getLocked,
|
Action: getLocked,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "alert",
|
Name: "alerts",
|
||||||
Usage: "change alert status",
|
Usage: "change alert status",
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "on",
|
Name: "yes",
|
||||||
Usage: "resume alerts",
|
Usage: "resume alerts",
|
||||||
Action: createManageAlert(true),
|
Aliases: []string{"y", "on", "1", "do"},
|
||||||
|
Action: createManageAlert(true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "off",
|
Name: "no",
|
||||||
Usage: "pause alerts",
|
Usage: "pause alerts",
|
||||||
|
Aliases: []string{"n", "off", "0", "undo"},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "for",
|
Name: "for",
|
||||||
@@ -195,13 +199,13 @@ func test(context.Context, *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOpened(ctx context.Context, cmd *cli.Command) error {
|
func getOpened(_ context.Context, cmd *cli.Command) error {
|
||||||
err := load()
|
err := load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
opened, err := makeGetReq(fmt.Sprintf("%s/open", server))
|
opened, err := makeGetReq(fmt.Sprintf("%s/opened", server))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -225,7 +229,7 @@ func getLocked(context.Context, *cli.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
locked, err := makeGetReq(fmt.Sprintf("%s/lock", server))
|
locked, err := makeGetReq(fmt.Sprintf("%s/locked", server))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -245,7 +249,7 @@ func getAlert(context.Context, *cli.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
alert, err := makeGetReq(fmt.Sprintf("%s/alert", server))
|
alert, err := makeGetReq(fmt.Sprintf("%s/alerts", server))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -269,7 +273,7 @@ func createManageLock(locked bool) func(context.Context, *cli.Command) error {
|
|||||||
var data ChangeLockReq
|
var data ChangeLockReq
|
||||||
data.Locked = locked
|
data.Locked = locked
|
||||||
|
|
||||||
_, err = makePostReq(fmt.Sprintf("%s/lock", server), data)
|
_, err = makePostReq(fmt.Sprintf("%s/locked", server), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -306,7 +310,7 @@ func createManageAlert(alert bool) func(context.Context, *cli.Command) error {
|
|||||||
data.For = secs
|
data.For = secs
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = makePostReq(fmt.Sprintf("%s/alert", server), data)
|
_, err = makePostReq(fmt.Sprintf("%s/alerts", server), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -322,7 +326,7 @@ func createManageAlert(alert bool) func(context.Context, *cli.Command) error {
|
|||||||
action = "paused"
|
action = "paused"
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("alerts were %sd%s\n", action, rest)
|
fmt.Printf("alerts were %s%s\n", action, rest)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -97,8 +97,8 @@ class App:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
r = urequests.post(
|
r = urequests.post(
|
||||||
f"{self.server}/open",
|
f"{self.server}/opened",
|
||||||
headers={"Authorization": self.token, "Content-Type": "application/json"},
|
headers={"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"},
|
||||||
data=raw
|
data=raw
|
||||||
)
|
)
|
||||||
print(f"State updated [{r.status_code}] {r.content.decode()}")
|
print(f"State updated [{r.status_code}] {r.content.decode()}")
|
||||||
|
@@ -23,14 +23,13 @@ const TimeFormat = "2006-01-02 15:04:05"
|
|||||||
var token string
|
var token string
|
||||||
|
|
||||||
// the condition is: distance >= threshold (is door open)
|
// the condition is: distance >= threshold (is door open)
|
||||||
var opened bool
|
var opened = false
|
||||||
var openedChange = make(chan any)
|
|
||||||
|
|
||||||
// is door locked
|
// is door locked
|
||||||
var locked bool = false
|
var locked = false
|
||||||
|
|
||||||
// alerts the user when door locked and but open?
|
// alerts the user when door locked and but open?
|
||||||
var alerts bool = false
|
var alerts = false
|
||||||
var gotifyToken string
|
var gotifyToken string
|
||||||
var gotifyURL string
|
var gotifyURL string
|
||||||
|
|
||||||
@@ -118,7 +117,6 @@ func main() {
|
|||||||
app.GET("/", helloWorld)
|
app.GET("/", helloWorld)
|
||||||
|
|
||||||
app.GET("/opened", authed(getOpened))
|
app.GET("/opened", authed(getOpened))
|
||||||
app.GET("/opened/ws", authed(getOpenedWs))
|
|
||||||
app.POST("/opened", authed(setOpened))
|
app.POST("/opened", authed(setOpened))
|
||||||
|
|
||||||
app.GET("/locked", authed(getLocked))
|
app.GET("/locked", authed(getLocked))
|
||||||
|
@@ -1,14 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/labstack/gommon/log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{}
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/labstack/gommon/log"
|
||||||
|
)
|
||||||
|
|
||||||
func helloWorld(c echo.Context) error {
|
func helloWorld(c echo.Context) error {
|
||||||
return c.JSON(http.StatusOK, "Hello world!")
|
return c.JSON(http.StatusOK, "Hello world!")
|
||||||
@@ -22,39 +20,6 @@ func getOpened(c echo.Context) error {
|
|||||||
return c.JSON(http.StatusOK, o)
|
return c.JSON(http.StatusOK, o)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOpenedWs(c echo.Context) error {
|
|
||||||
ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() { _ = ws.Close() }()
|
|
||||||
|
|
||||||
// empty the channel
|
|
||||||
emptied := false
|
|
||||||
for !emptied {
|
|
||||||
select {
|
|
||||||
case <-openedChange:
|
|
||||||
default:
|
|
||||||
emptied = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
<-openedChange
|
|
||||||
mut.Lock()
|
|
||||||
|
|
||||||
err = ws.WriteJSON(opened)
|
|
||||||
mut.Unlock()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func setOpened(c echo.Context) error {
|
func setOpened(c echo.Context) error {
|
||||||
var data ChangeOpenReq
|
var data ChangeOpenReq
|
||||||
err := c.Bind(&data)
|
err := c.Bind(&data)
|
||||||
@@ -79,7 +44,6 @@ func setOpened(c echo.Context) error {
|
|||||||
go sendAlert(action)
|
go sendAlert(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
openedChange <- 0
|
|
||||||
mut.Unlock()
|
mut.Unlock()
|
||||||
return c.NoContent(http.StatusOK)
|
return c.NoContent(http.StatusOK)
|
||||||
}
|
}
|
||||||
@@ -126,6 +90,7 @@ func setAlerts(c echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if data.For > 0 {
|
if data.For > 0 {
|
||||||
|
log.Infof("pausing alerts for %d seconds", data.For)
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Duration(data.For) * time.Second)
|
time.Sleep(time.Duration(data.For) * time.Second)
|
||||||
|
|
||||||
|
@@ -7,3 +7,10 @@
|
|||||||
<style>
|
<style>
|
||||||
@import "assets/css/main.css";
|
@import "assets/css/main.css";
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
useHead({
|
||||||
|
title: "Door alarm",
|
||||||
|
link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" }],
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import type { FetchResponse } from "ofetch"
|
import { type AxiosResponse } from "axios"
|
||||||
import { AxiosError, type AxiosResponse } from "axios"
|
|
||||||
|
|
||||||
export function useAPI(route: string = "/") {
|
export function useAPI(route: string = "/") {
|
||||||
return `https://api.door.svitan.dev${route}`
|
return `https://api.door.svitan.dev${route}`
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<main
|
<main
|
||||||
class="flex items-center justify-center min-w-screen min-h-screen gap-4 flex-wrap"
|
class="flex items-center justify-center min-w-screen min-h-screen gap-4 flex-wrap flex-col md:flex-row"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-center flex-col gap-y-2 w-32">
|
<div class="flex items-center justify-center flex-col gap-y-2 w-32">
|
||||||
<div
|
<div
|
||||||
:class="`flex items-center justify-center border-solid border-2 border-${open ? (locked ? 'error' : 'secondary') : 'primary'} rounded-lg w-full h-32`"
|
:class="`flex items-center justify-center border-solid border-2 border-${opened ? (locked ? 'error' : 'secondary') : 'primary'} rounded-lg w-full h-32`"
|
||||||
>
|
>
|
||||||
<UIcon
|
<UIcon
|
||||||
:name="
|
:name="
|
||||||
open
|
opened
|
||||||
? 'material-symbols:door-open'
|
? 'material-symbols:door-open'
|
||||||
: 'material-symbols:door-front'
|
: 'material-symbols:door-front'
|
||||||
"
|
"
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p
|
<p
|
||||||
:class="`flex items-center justify-center text-${open ? (locked ? 'error' : 'secondary') : 'primary'} text-xl w-full h-10`"
|
:class="`flex items-center justify-center text-${opened ? (locked ? 'error' : 'secondary') : 'primary'} text-xl w-full h-10 border-${opened ? (locked ? 'error' : 'secondary') : 'primary'} border-solid border-2 rounded-md`"
|
||||||
>
|
>
|
||||||
{{ open ? "Opened" : "Closed" }}
|
{{ opened ? "Opened" : "Closed" }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -55,11 +55,11 @@
|
|||||||
|
|
||||||
<div class="flex items-center justify-center flex-col gap-y-2 w-32">
|
<div class="flex items-center justify-center flex-col gap-y-2 w-32">
|
||||||
<div
|
<div
|
||||||
:class="`flex items-center justify-center border-solid border-2 border-${alert ? 'primary' : 'secondary'} rounded-lg w-full h-32`"
|
:class="`flex items-center justify-center border-solid border-2 border-${alerts ? 'primary' : 'secondary'} rounded-lg w-full h-32`"
|
||||||
>
|
>
|
||||||
<UIcon
|
<UIcon
|
||||||
:name="
|
:name="
|
||||||
alert
|
alerts
|
||||||
? 'material-symbols:volume-up'
|
? 'material-symbols:volume-up'
|
||||||
: 'material-symbols:volume-off'
|
: 'material-symbols:volume-off'
|
||||||
"
|
"
|
||||||
@@ -69,17 +69,17 @@
|
|||||||
|
|
||||||
<UButton
|
<UButton
|
||||||
:icon="
|
:icon="
|
||||||
alert
|
alerts
|
||||||
? 'material-symbols:volume-off'
|
? 'material-symbols:volume-off'
|
||||||
: 'material-symbols:volume-up'
|
: 'material-symbols:volume-up'
|
||||||
"
|
"
|
||||||
size="xl"
|
size="xl"
|
||||||
:color="alert ? 'primary' : 'secondary'"
|
:color="alerts ? 'primary' : 'secondary'"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
class="flex items-center justify-center w-full h-10"
|
class="flex items-center justify-center w-full h-10"
|
||||||
@click="toggleAlert"
|
@click="toggleAlert"
|
||||||
>
|
>
|
||||||
{{ alert ? "Turn off" : "Turn on" }}
|
{{ alerts ? "Turn off" : "Turn on" }}
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@@ -90,9 +90,9 @@ import axios from "axios"
|
|||||||
|
|
||||||
const token = useToken()
|
const token = useToken()
|
||||||
|
|
||||||
const open = ref(true)
|
const opened = ref(false)
|
||||||
const locked = ref(true)
|
const locked = ref(false)
|
||||||
const alert = ref(false)
|
const alerts = ref(false)
|
||||||
|
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ async function toggleLock() {
|
|||||||
const desired = !locked.value
|
const desired = !locked.value
|
||||||
axios
|
axios
|
||||||
.post(
|
.post(
|
||||||
useAPI("/lock"),
|
useAPI("/locked"),
|
||||||
{
|
{
|
||||||
locked: desired,
|
locked: desired,
|
||||||
},
|
},
|
||||||
@@ -120,15 +120,15 @@ async function toggleLock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function toggleAlert() {
|
async function toggleAlert() {
|
||||||
const desired = !alert.value
|
const desired = !alerts.value
|
||||||
axios
|
axios
|
||||||
.post(useAPI("/alert"), { alert: desired }, { headers: useHeaders() })
|
.post(useAPI("/alerts"), { alert: desired }, { headers: useHeaders() })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
handleResponse(res, () => {
|
handleResponse(res, () => {
|
||||||
toast.add({
|
toast.add({
|
||||||
title: `Alerts were turned ${desired ? "on" : "off"}`,
|
title: `Alerts were turned ${desired ? "on" : "off"}`,
|
||||||
})
|
})
|
||||||
alert.value = desired
|
alerts.value = desired
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(handleRequestError)
|
.catch(handleRequestError)
|
||||||
@@ -139,26 +139,43 @@ onMounted(() => {
|
|||||||
return navigateTo("/token")
|
return navigateTo("/token")
|
||||||
}
|
}
|
||||||
|
|
||||||
axios
|
setInterval(() => {
|
||||||
.get<boolean>(useAPI("/lock"), {
|
axios
|
||||||
headers: useHeaders(),
|
.get<boolean>(useAPI("/opened"), {
|
||||||
})
|
headers: useHeaders(),
|
||||||
.then((res) => {
|
|
||||||
handleResponse(res, (response) => {
|
|
||||||
locked.value = response.data
|
|
||||||
})
|
})
|
||||||
})
|
.then((res) => {
|
||||||
.catch(handleRequestError)
|
handleResponse(res, (res) => {
|
||||||
|
opened.value = res.data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(handleRequestError)
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
axios
|
setInterval(() => {
|
||||||
.get<boolean>(useAPI("/alert"), {
|
axios
|
||||||
headers: useHeaders(),
|
.get<boolean>(useAPI("/locked"), {
|
||||||
})
|
headers: useHeaders(),
|
||||||
.then((res) => {
|
|
||||||
handleResponse(res, (response) => {
|
|
||||||
alert.value = response.data
|
|
||||||
})
|
})
|
||||||
})
|
.then((res) => {
|
||||||
.catch(handleRequestError)
|
handleResponse(res, (res) => {
|
||||||
|
locked.value = res.data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(handleRequestError)
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
axios
|
||||||
|
.get<boolean>(useAPI("/alerts"), {
|
||||||
|
headers: useHeaders(),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
handleResponse(res, (res) => {
|
||||||
|
alerts.value = res.data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(handleRequestError)
|
||||||
|
}, 1000)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@@ -39,7 +39,7 @@ const toast = useToast()
|
|||||||
function onSubmit(event: FormSubmitEvent<Schema>) {
|
function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||||
const received = event.data.token
|
const received = event.data.token
|
||||||
axios
|
axios
|
||||||
.get<boolean>(useAPI("/open"), {
|
.get<boolean>(useAPI("/opened"), {
|
||||||
headers: useHeaders(received),
|
headers: useHeaders(received),
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
Reference in New Issue
Block a user