diff --git a/backend/scenes/scenes.go b/backend/scenes/scenes.go
index 9dd29c6..6a1daa0 100644
--- a/backend/scenes/scenes.go
+++ b/backend/scenes/scenes.go
@@ -47,10 +47,23 @@ func (sh *ScenesHandler) SaveScene(c *gin.Context) {
}
if _, err := os.Stat(path.Join(sh.dir)); err != nil {
- os.MkdirAll(sh.dir, 666)
+ err := os.MkdirAll(sh.dir, 0755)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
}
- f, err := os.OpenFile(path.Join(sh.dir, scene.Name+".scene"), os.O_CREATE|os.O_TRUNC|os.O_RDWR, 666)
+ f, err := os.OpenFile(path.Join(sh.dir, scene.Name+".scene"), os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
+ defer f.Close()
_, err = f.Write(body)
if err != nil {
@@ -59,7 +72,6 @@ func (sh *ScenesHandler) SaveScene(c *gin.Context) {
})
return
}
- defer f.Close()
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("Scene '%s' saved", scene.Name),
@@ -155,6 +167,7 @@ func (sh *ScenesHandler) LoadScene(c *gin.Context) {
}
var scene models.Scene
+
err = json.Unmarshal(body, &scene)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
@@ -190,6 +203,13 @@ func (sh *ScenesHandler) LoadScene(c *gin.Context) {
})
return
}
+ c.JSON(http.StatusOK, scene)
+ break
+ }
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": fmt.Errorf("scene '%s' not found", scene.Name),
+ })
+ return
}
- c.JSON(http.StatusOK, scene)
}
diff --git a/backend/utils/utils.go b/backend/utils/utils.go
index a9067dc..72e9db5 100644
--- a/backend/utils/utils.go
+++ b/backend/utils/utils.go
@@ -3,6 +3,7 @@ package utils
import (
"fmt"
"io/fs"
+ "os"
"os/exec"
"path/filepath"
"runtime"
@@ -27,6 +28,10 @@ func OpenBrowser(url string, logger *logging.Logger) error {
{"open", url}, // fallback
}
default: // Linux
+ if os.Getenv("DISPLAY") == "" && os.Getenv("WAYLAND_DISPLAY") == "" && os.Getenv("XDG_SESSION_TYPE") != "wayland" {
+
+ return fmt.Errorf("os is running i headless mode do not start browser")
+ }
commands = [][]string{
{"chromium-browser", "--kiosk", url},
{"google-chrome", "--kiosk", url},
@@ -47,14 +52,14 @@ func OpenBrowser(url string, logger *logging.Logger) error {
return fmt.Errorf("could not open browser")
}
-func FindAllFiles(rootDir, fileExtention string) (files []string, err error){
- err = filepath.WalkDir(rootDir, func(path string, d fs.DirEntry, err error) error {
- if d.IsDir() {
+func FindAllFiles(rootDir, fileExtention string) (files []string, err error) {
+ err = filepath.WalkDir(rootDir, func(path string, d fs.DirEntry, err error) error {
+ if d.IsDir() {
return nil
- } else if filepath.Ext(d.Name()) == fileExtention{
+ } else if filepath.Ext(d.Name()) == fileExtention {
files = append(files, path)
}
return err
})
- return
+ return
}
diff --git a/package-lock.json b/package-lock.json
index 5550254..7f56cc4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,16 @@
{
"name": "lightcontrol",
- "version": "0.0.5",
+ "version": "0.0.14",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lightcontrol",
- "version": "0.0.5",
+ "version": "0.0.14",
"hasInstallScript": true,
"dependencies": {
"@quasar/extras": "^1.16.4",
- "axios": "^1.9.0",
+ "axios": "^1.10.0",
"quasar": "^2.16.0",
"vue": "^3.4.18",
"vue-router": "^4.0.12"
@@ -2312,9 +2312,9 @@
}
},
"node_modules/axios": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
- "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
+ "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
diff --git a/package.json b/package.json
index ee952f9..8bf1ebe 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "lightcontrol",
- "version": "0.0.14",
+ "version": "0.0.15",
"description": "A Tecamino App",
"productName": "Light Control",
"author": "A. Zuercher",
@@ -16,7 +16,7 @@
},
"dependencies": {
"@quasar/extras": "^1.16.4",
- "axios": "^1.9.0",
+ "axios": "^1.10.0",
"quasar": "^2.16.0",
"vue": "^3.4.18",
"vue-router": "^4.0.12"
diff --git a/src/components/dbm/UpdateValue.vue b/src/components/dbm/UpdateValue.vue
new file mode 100644
index 0000000..af20b1c
--- /dev/null
+++ b/src/components/dbm/UpdateValue.vue
@@ -0,0 +1,13 @@
+
+ Test
+
+
+
diff --git a/src/components/dbm/dataTable.vue b/src/components/dbm/dataTable.vue
index b25a4df..cda59ad 100644
--- a/src/components/dbm/dataTable.vue
+++ b/src/components/dbm/dataTable.vue
@@ -11,14 +11,24 @@
row-key="path"
virtual-scroll
:rows-per-page-options="[0]"
- />
+ >
+
+
+ {{ props.row.value }}
+
+
+
+
diff --git a/src/components/dialog/UpdateValueDialog.vue b/src/components/dialog/UpdateValueDialog.vue
new file mode 100644
index 0000000..e4506e3
--- /dev/null
+++ b/src/components/dialog/UpdateValueDialog.vue
@@ -0,0 +1,101 @@
+
+
+
+ {{ props.dialogLabel }}
+
+
+
+ {{
+ props.text
+ }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/lights/MovingHead.vue b/src/components/lights/MovingHead.vue
index cb91c94..e1ed573 100644
--- a/src/components/lights/MovingHead.vue
+++ b/src/components/lights/MovingHead.vue
@@ -104,17 +104,17 @@ select
import { useQuasar } from 'quasar';
import LightSlider from './LightSlider.vue';
import { NotifyResponse } from 'src/composables/notify';
-import { computed, onMounted, onUnmounted, ref } from 'vue';
-import { subscribe, unsubscribe, setValues } from 'src/services/websocket';
+import { onBeforeUpdate, computed, onMounted, onUnmounted, ref } from 'vue';
+import { subscribeToPath, unsubscribe, setValues } from 'src/services/websocket';
import { LocalStorage } from 'quasar';
-import { getSubscriptionsByPath, buildTree, dbmData } from 'src/composables/dbm/dbmTree';
+import { getSubscriptionsByPath, updateValue } from 'src/composables/dbm/dbmTree';
import DragPad from 'src/components/lights/DragPad.vue';
import SettingDialog from './SettingMovingHead.vue';
import type { Settings } from 'src/models/MovingHead';
const $q = useQuasar();
const brightness = updateBrightnessValue('MovingHead:Brightness');
-const state = updateValue('MovingHead:State');
+const state = updateValue('MovingHead:State', $q);
const settings = ref({
show: false,
reversePan: false,
@@ -125,24 +125,11 @@ const settings = ref({
onMounted(() => {
settings.value.reversePan = LocalStorage.getItem('reversePan') ?? false;
settings.value.reverseTilt = LocalStorage.getItem('reverseTilt') ?? false;
+ subscribeToPath($q, 'MovingHead:.*');
+});
- subscribe([
- {
- path: 'MovingHead:.*',
- depth: 0,
- },
- ])
- .then((response) => {
- console.log(response);
- if (response?.subscribe) {
- dbmData.splice(0, dbmData.length, ...buildTree(response.subscribe));
- } else {
- NotifyResponse($q, response);
- }
- })
- .catch((err) => {
- NotifyResponse($q, err, 'error');
- });
+onBeforeUpdate(() => {
+ subscribeToPath($q, 'MovingHead:.*');
});
onUnmounted(() => {
@@ -157,45 +144,28 @@ onUnmounted(() => {
});
function changeState() {
+ console.log(55, brightness.value);
+ console.log(56, state.value);
if (brightness.value === 0) {
if (state.value === 0) {
brightness.value = 255;
return;
}
brightness.value = state.value;
+ console.log(57, brightness.value);
return;
}
state.value = brightness.value;
+ console.log(58, state.value);
brightness.value = 0;
}
-function updateValue(path: string, isDouble = false) {
- return computed({
- get() {
- const sub = getSubscriptionsByPath(path);
- const value = sub ? Number(sub.value ?? 0) : 0;
- return isDouble ? value : value;
- },
- set(val) {
- const setPaths = [{ path, value: val }];
-
- if (isDouble) {
- setPaths.push({ path: `${path}Fine`, value: val });
- }
-
- setValues(setPaths)
- .then((response) => NotifyResponse($q, response))
- .catch((err) => console.error(`Failed to update ${path.split(':')[1]}:`, err));
- },
- });
-}
-
function updateBrightnessValue(path: string) {
return computed({
get() {
const sub = getSubscriptionsByPath(path);
- const value = sub ? Number(sub.value ?? 0) : 0;
- return value;
+ if (!sub.value) return 0;
+ return Number(sub.value.value);
},
set(val) {
const setPaths = [{ path, value: val }];
diff --git a/src/components/scenes/ScenesPage.vue b/src/components/scenes/ScenesPage.vue
new file mode 100644
index 0000000..3d6b545
--- /dev/null
+++ b/src/components/scenes/ScenesPage.vue
@@ -0,0 +1,356 @@
+
+
+
+
+
+ {{ dialogLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add New Scene
+
+ Name
+ Description
+
+
+ {{ item.name }}
+ {{ item.description }}
+
+
+
+
+
+
+
+
+
+
+
No scenes available
+
Add First Scene
+
+
+
+
diff --git a/src/components/scenes/ScenesTab.vue b/src/components/scenes/ScenesTab.vue
deleted file mode 100644
index 6f2294c..0000000
--- a/src/components/scenes/ScenesTab.vue
+++ /dev/null
@@ -1,292 +0,0 @@
-
-
-
-
-
- {{ dialogLabel }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Add New Scene
-
- Name
- Description
-
-
- {{ item.name }}
- {{ item.description }}
-
-
-
-
-
-
-
-
-
-
-
No scenes available
-
Add First Scene
-
-
-
-
diff --git a/src/composables/dbm/dbmTree.ts b/src/composables/dbm/dbmTree.ts
index 13871f6..c57785f 100644
--- a/src/composables/dbm/dbmTree.ts
+++ b/src/composables/dbm/dbmTree.ts
@@ -31,7 +31,7 @@ export function buildTree(subs: Subs): TreeNode[] {
for (const item of subs) {
if (item.path) {
- Subscriptions[item.path] = item;
+ addNewSubscription(item);
}
const pathParts = item.path?.split(':') ?? [];
let current = root;
@@ -130,6 +130,11 @@ export function getSubscriptionsByPath(path: string) {
return ref(Subscriptions[path]);
}
+export function addNewSubscription(sub: Subscribe) {
+ if (!sub.path) return;
+ Subscriptions[sub.path] = sub;
+}
+
export function getAllSubscriptions() {
return Object.values(Subscriptions);
}
@@ -145,8 +150,7 @@ export function updateValue(
return computed({
get() {
const sub = getSubscriptionsByPath(toggle?.value && path2 ? path2 : path1);
- const value = sub?.value ? Number(sub.value.value ?? 0) : 0;
- return value;
+ return sub?.value ? Number(sub.value.value ?? 0) : 0;
},
set(val) {
const baseValue = val;
diff --git a/src/models/Publish.ts b/src/models/Publish.ts
index 636bca6..009c07d 100644
--- a/src/models/Publish.ts
+++ b/src/models/Publish.ts
@@ -1,8 +1,8 @@
export type Publish = {
event: string;
- uuid?: string;
- path?: string;
- type?: string;
- value?: undefined;
+ uuid: string;
+ path: string;
+ type: string;
+ value: undefined;
};
export type Pubs = Publish[];
diff --git a/src/router/routes.ts b/src/router/routes.ts
index 3227cbf..5c54edb 100644
--- a/src/router/routes.ts
+++ b/src/router/routes.ts
@@ -7,7 +7,7 @@ const routes: RouteRecordRaw[] = [
children: [
{ path: '', component: () => import('pages/MainPage.vue') },
{ path: '/data', component: () => import('pages/DataPage.vue') },
- { path: '/scenes', component: () => import('components/scenes/ScenesTab.vue') },
+ { path: '/scenes', component: () => import('components/scenes/ScenesPage.vue') },
],
},
diff --git a/src/services/websocket.ts b/src/services/websocket.ts
index c0511fe..6f4af78 100644
--- a/src/services/websocket.ts
+++ b/src/services/websocket.ts
@@ -3,18 +3,19 @@ import type { Publish } from 'src/models/Publish';
import type { Request } from 'src/models/Request';
import type { QVueGlobals } from 'quasar';
import {
- getAllSubscriptions,
buildTree,
dbmData,
- getSubscriptionsByUuid,
+ getSubscriptionsByPath,
+ getAllSubscriptions,
} from 'src/composables/dbm/dbmTree';
-import { ref, reactive } from 'vue';
+import { ref } from 'vue';
import type { Subs } from 'src/models/Subscribe';
import type { Sets } from 'src/models/Set';
import type { PongMessage } from 'src/models/Pong';
+import { NotifyResponse } from 'src/composables/notify';
const pendingResponses = new Map void>();
-const lastKnownValues: Record = reactive({});
+//const lastKnownValues: Record = reactive({});
export let socket: WebSocket | null = null;
const isConnected = ref(false);
@@ -88,29 +89,14 @@ export function initWebSocket(url: string, $q?: QVueGlobals) {
pendingResponses.delete(id);
return;
}
+
if (message.publish) {
(message.publish as Publish[]).forEach((pub) => {
- const uuid = pub.uuid;
- const value = pub.value ?? '';
-
- if (uuid === undefined) {
- return;
- }
-
- const oldValue = lastKnownValues[uuid];
- if (oldValue !== value) {
- lastKnownValues[uuid] = value; // this is now reactive
- if (pub.uuid) {
- const existing = getSubscriptionsByUuid(pub.uuid);
-
- if (existing.value) {
- existing.value.value = value;
- }
- } else {
- getAllSubscriptions().push({ value, uuid: uuid });
- }
- dbmData.splice(0, dbmData.length, ...buildTree(getAllSubscriptions())); // rebuild reactive tree
+ const sub = getSubscriptionsByPath(pub.path);
+ if (sub.value && pub.value) {
+ sub.value.value = pub.value;
}
+ dbmData.splice(0, dbmData.length, ...buildTree(getAllSubscriptions())); // rebuild reactive tree
});
}
}
@@ -157,6 +143,26 @@ export function subscribe(data: Subs): Promise {
return send({ subscribe: data });
}
+export function subscribeToPath(q: QVueGlobals, path: string) {
+ subscribe([
+ {
+ path: path,
+ depth: 0,
+ },
+ ])
+ .then((response) => {
+ console.log(response);
+ if (response?.subscribe) {
+ dbmData.splice(0, dbmData.length, ...buildTree(response.subscribe));
+ } else {
+ NotifyResponse(q, response);
+ }
+ })
+ .catch((err) => {
+ NotifyResponse(q, err, 'error');
+ });
+}
+
export function unsubscribe(data: Subs): Promise {
return send({ unsubscribe: data });
}