commit 5ff83ecaeb167b800850299a7ca1bbe94b9a168e Author: Kevin Midboe Date: Sat Apr 19 17:09:13 2025 +0200 init commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..7650ad1 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# PATLITE light tower controller + +## frontend + +setup + +``` +cp .env.exmaple .env +``` + +build + +``` +cd frontend +yarn +yarn build + +# docker build +build -t patlite-light-tower-controller . +``` + +## server + +``` +cd server +virtualenv env +source env/bin/activate + +pip3 install -r requirements.txt +python3 main.py + +or + +python3 --server main.py +``` diff --git a/assets/screenshot.png b/assets/screenshot.png new file mode 100644 index 0000000..c4d3e01 Binary files /dev/null and b/assets/screenshot.png differ diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 0000000..c1f51d8 --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1,4 @@ +VITE_APP_TITLE=Patlite Status Light Controller +VITE_DEVICE_URL=http://localhost:5000 +VITE_DEVICE_PATH=/api/ +VITE_GITHUB_SOURCE=https://github.com/kevinmidboe/patlite-controller diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 0000000..6b78363 --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,4 @@ +{ + "plugins": ["prettier-plugin-svelte"], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..37870e0 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,28 @@ +# Stage 1: Build the frontend +FROM node:18 AS builder + +# Set working directory +WORKDIR /app + +# Copy required config and lock files +COPY package.json yarn.lock svelte.config.js vite.config.js ./ + +# Install dependencies +RUN yarn install + +# Copy the rest of the source files +COPY . . + +# Build the frontend +RUN yarn build + +# Stage 2: Serve with Caddy +FROM caddy:2-alpine + +# Set working directory +WORKDIR /usr/share/caddy + +# Copy the build output from the previous stage +COPY --from=builder /app/dist /usr/share/caddy + +CMD ["caddy", "file-server", "--root", "/usr/share/caddy", "--listen", ":80"] diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..8f6d6ca --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,14 @@ + + + + + + Svelte App + + + + +
+ + + diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..85b09ef --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,19 @@ +{ + "name": "my-svelte-app", + "type": "module", + "version": "1.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^2.0.0", + "prettier": "^3.5.3", + "prettier-plugin-svelte": "^3.3.3", + "sass": "^1.86.3", + "svelte": "5.28.1", + "svelte-preprocess": "^6.0.3", + "vite": "^5.0.0" + } +} diff --git a/frontend/public/fonts/IBMPlexSerif-SemiBoldItalic.ttf b/frontend/public/fonts/IBMPlexSerif-SemiBoldItalic.ttf new file mode 100644 index 0000000..4e37556 Binary files /dev/null and b/frontend/public/fonts/IBMPlexSerif-SemiBoldItalic.ttf differ diff --git a/frontend/public/style.scss b/frontend/public/style.scss new file mode 100644 index 0000000..f1dd8c3 --- /dev/null +++ b/frontend/public/style.scss @@ -0,0 +1,66 @@ +@font-face { + font-family: 'ibm-plex'; + src: url('./fonts/IBMPlexSerif-SemiBoldItalic.ttf') format('truetype'); + font-weight: 500; + font-style: italic; + font-display: swap; +} + +body { + font-family: Arial, sans-serif; + background-color: #f0f0f0; + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + height: 100%; + position: relative; +} + +.container { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + text-align: center; + background-color: #fff; + padding: 2rem; + border-radius: 10px; + touch-action: manipulation; + margin: 2rem; + + @media screen and (max-width: 750px) { + min-height: 100vh; + margin: 0; + } +} + +hr { + border-color: lightgrey; +} + +h1 { + color: #333; + margin-top: 0; + font-size: 4rem; + font-family: 'ibm-plex'; + text-transform: uppercase; +} + +footer { + position: absolute; + bottom: 0; + left: 0; + height: 3rem; + width: 100%; + display: grid; + place-items: center; + + a { + display: inline-block; + vertical-align: middle; + height: 1.5rem; + } +} diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte new file mode 100644 index 0000000..f1d26cb --- /dev/null +++ b/frontend/src/App.svelte @@ -0,0 +1,129 @@ + + +{#if error} + +{/if} + +
+

{title}

+ +
+ {#each Object.entries(state || {}) as [color, value] (color)} + toggleLight(color, value)} /> + {/each} +
+
+ +
+ (state = _state)} /> + +
+ {#each Object.entries(state || {}) as [color, value] (color)} + toggleLight(color, value)} + /> + {/each} +
+
+
+ +
+   with svelte ❤️ +
+ + diff --git a/frontend/src/components/ControlButton.svelte b/frontend/src/components/ControlButton.svelte new file mode 100644 index 0000000..987bf04 --- /dev/null +++ b/frontend/src/components/ControlButton.svelte @@ -0,0 +1,76 @@ + + + + + diff --git a/frontend/src/components/ErrorPage.svelte b/frontend/src/components/ErrorPage.svelte new file mode 100644 index 0000000..a540bc6 --- /dev/null +++ b/frontend/src/components/ErrorPage.svelte @@ -0,0 +1,84 @@ + + +
+

{title}

+

+ it is sad when the application does not work, but below is a stack trace and + current environment variables for deugging. +

+ +
+ + +

Error occured and returned message: "{error}"

+ +

{error?.stack}

+
+ + + + {#each Object.entries(env) as [key, value] (key)} + {key}: {value}
+ {/each} +
+
+
+ + diff --git a/frontend/src/components/Light.svelte b/frontend/src/components/Light.svelte new file mode 100644 index 0000000..6f64556 --- /dev/null +++ b/frontend/src/components/Light.svelte @@ -0,0 +1,59 @@ + + + + {/each} + + +
+ {#if seqRunning} +

+ Currently running: {active}, {1 + iteratorSelector - iterator} of {iteratorSelector} +

+ {/if} +
+ + + diff --git a/frontend/src/icons/bell.svelte b/frontend/src/icons/bell.svelte new file mode 100644 index 0000000..38a1328 --- /dev/null +++ b/frontend/src/icons/bell.svelte @@ -0,0 +1,15 @@ + + + + + + diff --git a/frontend/src/icons/cactus.svelte b/frontend/src/icons/cactus.svelte new file mode 100644 index 0000000..561e298 --- /dev/null +++ b/frontend/src/icons/cactus.svelte @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/frontend/src/icons/fire-hazard-active.svelte b/frontend/src/icons/fire-hazard-active.svelte new file mode 100644 index 0000000..203dcad --- /dev/null +++ b/frontend/src/icons/fire-hazard-active.svelte @@ -0,0 +1,21 @@ + + + + + + diff --git a/frontend/src/icons/fire-hazard.svelte b/frontend/src/icons/fire-hazard.svelte new file mode 100644 index 0000000..a065a85 --- /dev/null +++ b/frontend/src/icons/fire-hazard.svelte @@ -0,0 +1,19 @@ + + + + + + + diff --git a/frontend/src/icons/flower.svelte b/frontend/src/icons/flower.svelte new file mode 100644 index 0000000..d0d5ad1 --- /dev/null +++ b/frontend/src/icons/flower.svelte @@ -0,0 +1,13 @@ + + + + + diff --git a/frontend/src/icons/github.svelte b/frontend/src/icons/github.svelte new file mode 100644 index 0000000..e3458f5 --- /dev/null +++ b/frontend/src/icons/github.svelte @@ -0,0 +1 @@ + diff --git a/frontend/src/icons/lamp-bright.svelte b/frontend/src/icons/lamp-bright.svelte new file mode 100644 index 0000000..1f64daf --- /dev/null +++ b/frontend/src/icons/lamp-bright.svelte @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/frontend/src/icons/lamp.svelte b/frontend/src/icons/lamp.svelte new file mode 100644 index 0000000..a885465 --- /dev/null +++ b/frontend/src/icons/lamp.svelte @@ -0,0 +1,15 @@ + + + + + + + diff --git a/frontend/src/icons/no-connection.svelte b/frontend/src/icons/no-connection.svelte new file mode 100644 index 0000000..f5fcbf8 --- /dev/null +++ b/frontend/src/icons/no-connection.svelte @@ -0,0 +1,14 @@ + + + + + + diff --git a/frontend/src/icons/rubber-duck.svelte b/frontend/src/icons/rubber-duck.svelte new file mode 100644 index 0000000..3ca52d0 --- /dev/null +++ b/frontend/src/icons/rubber-duck.svelte @@ -0,0 +1,16 @@ + + + + + + diff --git a/frontend/src/icons/siren-bright.svelte b/frontend/src/icons/siren-bright.svelte new file mode 100644 index 0000000..ca93c17 --- /dev/null +++ b/frontend/src/icons/siren-bright.svelte @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/frontend/src/icons/siren.svelte b/frontend/src/icons/siren.svelte new file mode 100644 index 0000000..b247b37 --- /dev/null +++ b/frontend/src/icons/siren.svelte @@ -0,0 +1,16 @@ + + + + + + diff --git a/frontend/src/icons/traffic-lights.svelte b/frontend/src/icons/traffic-lights.svelte new file mode 100644 index 0000000..aafd59e --- /dev/null +++ b/frontend/src/icons/traffic-lights.svelte @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/frontend/src/icons/warning.svelte b/frontend/src/icons/warning.svelte new file mode 100644 index 0000000..02bc93b --- /dev/null +++ b/frontend/src/icons/warning.svelte @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/frontend/src/icons/weight-1kg.svelte b/frontend/src/icons/weight-1kg.svelte new file mode 100644 index 0000000..c179db4 --- /dev/null +++ b/frontend/src/icons/weight-1kg.svelte @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/frontend/src/main.js b/frontend/src/main.js new file mode 100644 index 0000000..5332616 --- /dev/null +++ b/frontend/src/main.js @@ -0,0 +1,7 @@ +import App from "./App.svelte"; + +const app = new App({ + target: document.getElementById("app"), +}); + +export default app; diff --git a/frontend/src/utils/actions.js b/frontend/src/utils/actions.js new file mode 100644 index 0000000..c8e0acf --- /dev/null +++ b/frontend/src/utils/actions.js @@ -0,0 +1,39 @@ +export function sleep(hundredSeconds) { + return new Promise((resolve) => setTimeout(resolve, hundredSeconds * 100)); +} + +export const errorSeq = [ + [0, 0, 1, 1], + [0, 0, 0, 1], + [0, 0, 1, 1], + [0, 0, 0, 1], + [0, 0, 1, 1], + [0, 0, 0, 6], + [0, 0, 1, 2], + [0, 0, 0, 2], + [0, 0, 1, 2], + [0, 0, 0, 2], + [0, 0, 1, 2], + [0, 0, 0, 6], + [0, 0, 1, 1], + [0, 0, 0, 1], + [0, 0, 1, 1], + [0, 0, 0, 1], + [0, 0, 1, 1], + [0, 0, 0, 20], +]; + +export const trafficSeq = [ + [0, 0, 1, 15], + [0, 1, 1, 15], + [1, 0, 0, 50], + [0, 1, 0, 15], + [0, 0, 1, 20], +]; + +export const warningSeq = [ + [0, 1, 0, 3], + [0, 0, 0, 3], + [0, 1, 0, 3], + [0, 0, 0, 10], +]; diff --git a/frontend/src/utils/tower.js b/frontend/src/utils/tower.js new file mode 100644 index 0000000..411297b --- /dev/null +++ b/frontend/src/utils/tower.js @@ -0,0 +1,32 @@ +let BASE_URL, BASE_PATH; + +export function setupApi(url, path) { + BASE_URL = url; + BASE_PATH = path; +} + +export async function getState() { + const url = `${BASE_URL}${BASE_PATH}state`; + + return fetch(url).then((resp) => resp.json()); +} + +export async function toggle(color) { + const url = `${BASE_URL}${BASE_PATH}toggle/${color}`; + const options = { method: "POST" }; + + return fetch(url, options); +} + +export async function setTower(colorStates) { + const url = `${BASE_URL}${BASE_PATH}state/set`; + const options = { + method: "POST", + header: { + "Content-Type": "plain/text", + }, + body: colorStates.join(","), + }; + + return fetch(url, options); +} diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js new file mode 100644 index 0000000..9cc3554 --- /dev/null +++ b/frontend/svelte.config.js @@ -0,0 +1,15 @@ +import preprocess from "svelte-preprocess"; + +export default { + preprocess: preprocess({ + scss: { + // Optional: includePaths: ['src/styles'] + }, + }), + compilerOptions: { + dev: true, + compatibility: { + componentApi: 4, // 👈 This enables `new App()` to work + }, + }, +}; diff --git a/frontend/vite.config.js b/frontend/vite.config.js new file mode 100644 index 0000000..fb0a4b1 --- /dev/null +++ b/frontend/vite.config.js @@ -0,0 +1,8 @@ +import { defineConfig } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; + +export default defineConfig({ + plugins: [svelte()], + root: "./", + publicDir: "public", +}); diff --git a/frontend/yarn.lock b/frontend/yarn.lock new file mode 100644 index 0000000..65e5f69 --- /dev/null +++ b/frontend/yarn.lock @@ -0,0 +1,687 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@parcel/watcher-android-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1" + integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== + +"@parcel/watcher-darwin-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67" + integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== + +"@parcel/watcher-darwin-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8" + integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== + +"@parcel/watcher-freebsd-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b" + integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== + +"@parcel/watcher-linux-arm-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1" + integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== + +"@parcel/watcher-linux-arm-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e" + integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== + +"@parcel/watcher-linux-arm64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30" + integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== + +"@parcel/watcher-linux-arm64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2" + integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== + +"@parcel/watcher-linux-x64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e" + integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== + +"@parcel/watcher-linux-x64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee" + integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== + +"@parcel/watcher-win32-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243" + integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== + +"@parcel/watcher-win32-ia32@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6" + integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== + +"@parcel/watcher-win32-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947" + integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA== + +"@parcel/watcher@^2.4.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200" + integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg== + dependencies: + detect-libc "^1.0.3" + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.5.1" + "@parcel/watcher-darwin-arm64" "2.5.1" + "@parcel/watcher-darwin-x64" "2.5.1" + "@parcel/watcher-freebsd-x64" "2.5.1" + "@parcel/watcher-linux-arm-glibc" "2.5.1" + "@parcel/watcher-linux-arm-musl" "2.5.1" + "@parcel/watcher-linux-arm64-glibc" "2.5.1" + "@parcel/watcher-linux-arm64-musl" "2.5.1" + "@parcel/watcher-linux-x64-glibc" "2.5.1" + "@parcel/watcher-linux-x64-musl" "2.5.1" + "@parcel/watcher-win32-arm64" "2.5.1" + "@parcel/watcher-win32-ia32" "2.5.1" + "@parcel/watcher-win32-x64" "2.5.1" + +"@rollup/rollup-android-arm-eabi@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz#d964ee8ce4d18acf9358f96adc408689b6e27fe3" + integrity sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg== + +"@rollup/rollup-android-arm64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz#9b5e130ecc32a5fc1e96c09ff371743ee71a62d3" + integrity sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w== + +"@rollup/rollup-darwin-arm64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz#ef439182c739b20b3c4398cfc03e3c1249ac8903" + integrity sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ== + +"@rollup/rollup-darwin-x64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz#d7380c1531ab0420ca3be16f17018ef72dd3d504" + integrity sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA== + +"@rollup/rollup-freebsd-arm64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz#cbcbd7248823c6b430ce543c59906dd3c6df0936" + integrity sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg== + +"@rollup/rollup-freebsd-x64@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz#96bf6ff875bab5219c3472c95fa6eb992586a93b" + integrity sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw== + +"@rollup/rollup-linux-arm-gnueabihf@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz#d80cd62ce6d40f8e611008d8dbf03b5e6bbf009c" + integrity sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA== + +"@rollup/rollup-linux-arm-musleabihf@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz#75440cfc1e8d0f87a239b4c31dfeaf4719b656b7" + integrity sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg== + +"@rollup/rollup-linux-arm64-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz#ac527485ecbb619247fb08253ec8c551a0712e7c" + integrity sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg== + +"@rollup/rollup-linux-arm64-musl@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz#74d2b5cb11cf714cd7d1682e7c8b39140e908552" + integrity sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ== + +"@rollup/rollup-linux-loongarch64-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz#a0a310e51da0b5fea0e944b0abd4be899819aef6" + integrity sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg== + +"@rollup/rollup-linux-powerpc64le-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz#4077e2862b0ac9f61916d6b474d988171bd43b83" + integrity sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw== + +"@rollup/rollup-linux-riscv64-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz#5812a1a7a2f9581cbe12597307cc7ba3321cf2f3" + integrity sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA== + +"@rollup/rollup-linux-riscv64-musl@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz#973aaaf4adef4531375c36616de4e01647f90039" + integrity sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ== + +"@rollup/rollup-linux-s390x-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz#9bad59e907ba5bfcf3e9dbd0247dfe583112f70b" + integrity sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw== + +"@rollup/rollup-linux-x64-gnu@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz#68b045a720bd9b4d905f462b997590c2190a6de0" + integrity sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ== + +"@rollup/rollup-linux-x64-musl@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz#8e703e2c2ad19ba7b2cb3d8c3a4ad11d4ee3a282" + integrity sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw== + +"@rollup/rollup-win32-arm64-msvc@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz#c5bee19fa670ff5da5f066be6a58b4568e9c650b" + integrity sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ== + +"@rollup/rollup-win32-ia32-msvc@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz#846e02c17044bd922f6f483a3b4d36aac6e2b921" + integrity sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA== + +"@rollup/rollup-win32-x64-msvc@4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz#fd92d31a2931483c25677b9c6698106490cbbc76" + integrity sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ== + +"@sveltejs/acorn-typescript@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz#f518101d1b2e12ce80854f1cd850d3b9fb91d710" + integrity sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ== + +"@sveltejs/vite-plugin-svelte-inspector@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz#c99fcb73aaa845a3e2c0563409aeb3ee0b863add" + integrity sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ== + dependencies: + debug "^4.3.4" + +"@sveltejs/vite-plugin-svelte@^2.0.0": + version "2.5.3" + resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.5.3.tgz#23f810d0c38d159491845175c2566a51639be3fc" + integrity sha512-erhNtXxE5/6xGZz/M9eXsmI7Pxa6MS7jyTy06zN3Ck++ldrppOnOlJwHHTsMC7DHDQdgUp4NAc4cDNQ9eGdB/w== + dependencies: + "@sveltejs/vite-plugin-svelte-inspector" "^1.0.4" + debug "^4.3.4" + deepmerge "^4.3.1" + kleur "^4.1.5" + magic-string "^0.30.3" + svelte-hmr "^0.15.3" + vitefu "^0.2.4" + +"@types/estree@1.0.7", "@types/estree@^1.0.5", "@types/estree@^1.0.6": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" + integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== + +acorn@^8.12.1: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + +aria-query@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +chokidar@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +debug@^4.3.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +esm-env@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/esm-env/-/esm-env-1.2.2.tgz#263c9455c55861f41618df31b20cb571fc20b75e" + integrity sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA== + +esrap@^1.4.6: + version "1.4.6" + resolved "https://registry.yarnpkg.com/esrap/-/esrap-1.4.6.tgz#d203ce1ee397aa2a6a716a3a2dc8619f83208c6a" + integrity sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +immutable@^5.0.2: + version "5.1.1" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.1.tgz#d4cb552686f34b076b3dcf23c4384c04424d8354" + integrity sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-reference@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.3.tgz#9ef7bf9029c70a67b2152da4adf57c23d718910f" + integrity sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw== + dependencies: + "@types/estree" "^1.0.6" + +kleur@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== + +locate-character@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-3.0.0.tgz#0305c5b8744f61028ef5d01f444009e00779f974" + integrity sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA== + +magic-string@^0.30.11, magic-string@^0.30.3: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +micromatch@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.8: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +postcss@^8.4.43: + version "8.5.3" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" + integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== + dependencies: + nanoid "^3.3.8" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +prettier-plugin-svelte@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz#49d5c025a1516063ac7ef026806f880caa310424" + integrity sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw== + +prettier@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" + integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + +rollup@^4.20.0: + version "4.40.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.40.0.tgz#13742a615f423ccba457554f006873d5a4de1920" + integrity sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w== + dependencies: + "@types/estree" "1.0.7" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.40.0" + "@rollup/rollup-android-arm64" "4.40.0" + "@rollup/rollup-darwin-arm64" "4.40.0" + "@rollup/rollup-darwin-x64" "4.40.0" + "@rollup/rollup-freebsd-arm64" "4.40.0" + "@rollup/rollup-freebsd-x64" "4.40.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.40.0" + "@rollup/rollup-linux-arm-musleabihf" "4.40.0" + "@rollup/rollup-linux-arm64-gnu" "4.40.0" + "@rollup/rollup-linux-arm64-musl" "4.40.0" + "@rollup/rollup-linux-loongarch64-gnu" "4.40.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.40.0" + "@rollup/rollup-linux-riscv64-gnu" "4.40.0" + "@rollup/rollup-linux-riscv64-musl" "4.40.0" + "@rollup/rollup-linux-s390x-gnu" "4.40.0" + "@rollup/rollup-linux-x64-gnu" "4.40.0" + "@rollup/rollup-linux-x64-musl" "4.40.0" + "@rollup/rollup-win32-arm64-msvc" "4.40.0" + "@rollup/rollup-win32-ia32-msvc" "4.40.0" + "@rollup/rollup-win32-x64-msvc" "4.40.0" + fsevents "~2.3.2" + +sass@^1.86.3: + version "1.86.3" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.86.3.tgz#0a0d9ea97cb6665e73f409639f8533ce057464c9" + integrity sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw== + dependencies: + chokidar "^4.0.0" + immutable "^5.0.2" + source-map-js ">=0.6.2 <2.0.0" + optionalDependencies: + "@parcel/watcher" "^2.4.1" + +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +svelte-hmr@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.15.3.tgz#df54ccde9be3f091bf5f18fc4ef7b8eb6405fbe6" + integrity sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ== + +svelte-preprocess@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-6.0.3.tgz#fdc1f9dc41b6f22bf8b1f059e9f21eaaae181eeb" + integrity sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA== + +svelte@5.28.1: + version "5.28.1" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.28.1.tgz#4a0cd28c92ea23f4d5caa8eaf0e8d0af6c83c397" + integrity sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@jridgewell/sourcemap-codec" "^1.5.0" + "@sveltejs/acorn-typescript" "^1.0.5" + "@types/estree" "^1.0.5" + acorn "^8.12.1" + aria-query "^5.3.1" + axobject-query "^4.1.0" + clsx "^2.1.1" + esm-env "^1.2.1" + esrap "^1.4.6" + is-reference "^3.0.3" + locate-character "^3.0.0" + magic-string "^0.30.11" + zimmerframe "^1.1.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +vite@^5.0.0: + version "5.4.18" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.18.tgz#b5af357f9d5ebb2e0c085779b7a37a77f09168a4" + integrity sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + +vitefu@^0.2.4: + version "0.2.5" + resolved "https://registry.yarnpkg.com/vitefu/-/vitefu-0.2.5.tgz#c1b93c377fbdd3e5ddd69840ea3aa70b40d90969" + integrity sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q== + +zimmerframe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/zimmerframe/-/zimmerframe-1.1.2.tgz#5b75f1fa83b07ae2a428d51e50f58e2ae6855e5e" + integrity sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w== diff --git a/server/database.py b/server/database.py new file mode 100644 index 0000000..0722877 --- /dev/null +++ b/server/database.py @@ -0,0 +1,62 @@ +import sqlite3 +from contextlib import closing + +DB_FILE = 'lights.db' +DEFAULT_LIGHTS = ['green', 'orange', 'red'] + + +def connect(): + """Get a new connection to the database.""" + return sqlite3.connect(DB_FILE) + + +def setup_database(): + """Initializes the database and sets default states for lights.""" + with closing(connect()) as conn: + with conn: + conn.execute(''' + CREATE TABLE IF NOT EXISTS light_state ( + name TEXT PRIMARY KEY, + state INTEGER NOT NULL CHECK (state IN (0, 1)) + ) + ''') + + # Insert default lights with state=0 if they do not exist + for light in DEFAULT_LIGHTS: + conn.execute(''' + INSERT OR IGNORE INTO light_state (name, state) + VALUES (?, 0) + ''', (light,)) + + +def ensure_database(): + """Ensures the DB is initialized. Safe to call multiple times.""" + setup_database() + + +def set_light_state(name, state): + ensure_database() + with closing(connect()) as conn: + with conn: + conn.execute(''' + INSERT INTO light_state (name, state) + VALUES (?, ?) + ON CONFLICT(name) DO UPDATE SET state = excluded.state + ''', (name, state)) + + +def get_light_state(name): + ensure_database() + with closing(connect()) as conn: + cur = conn.cursor() + cur.execute('SELECT state FROM light_state WHERE name = ?', (name,)) + row = cur.fetchone() + return row[0] if row else 0 + + +def get_all_states(): + ensure_database() + with closing(connect()) as conn: + cur = conn.cursor() + cur.execute('SELECT name, state FROM light_state') + return dict(cur.fetchall()) diff --git a/server/light.py b/server/light.py new file mode 100644 index 0000000..9e314a1 --- /dev/null +++ b/server/light.py @@ -0,0 +1,73 @@ +import RPi.GPIO as GPIO +import time +import database + +FUNCTIONS = ['green', 'orange', 'red'] + + +class Light: + def __init__(self, pin, name): + self.pin = pin + self.name = name + self.state = database.get_light_state(name) + self.setup() + + def setup(self): + GPIO.setmode(GPIO.BCM) + GPIO.setup(self.pin, GPIO.OUT) + self._set(self.state) + + def _set(self, state): + if state == self.state: + print('%s is equal %s' % (state, self.state,)) + + print('setting %s state to: %s' % (self.name, state,)) + GPIO.output(self.pin, GPIO.LOW if state == GPIO.HIGH else GPIO.HIGH) + self.state = state + database.set_light_state(self.name, state) + + def on(self): + self._set(GPIO.HIGH) + + def off(self): + self._set(GPIO.LOW) + + def flash(self, count=2, interval=0.2): + for _ in range(count): + self.on() + time.sleep(interval) + self.off() + time.sleep(interval) + + +class Tower: + def __init__(self, pinList): + self.pins = pinList + self.setupLights() + self.green: Light + self.orange: Light + self.red: Light + + def setupLights(self): + if len(FUNCTIONS) != len(self.pins): + raise ValueError("only %s pins provided, but %s available" % + (len(self.pins), len(FUNCTIONS))) + + for pin in self.pins: + light = Light(pin['pin'], pin['name']) + if light.name == 'green': + self.green = light + elif light.name == 'orange': + self.orange = light + elif light.name == 'red': + self.red = light + + def on(self): + self.green.on() + self.orange.on() + self.red.on() + + def off(self): + self.green.off() + self.orange.off() + self.red.off() diff --git a/server/main.py b/server/main.py new file mode 100644 index 0000000..d4bbf69 --- /dev/null +++ b/server/main.py @@ -0,0 +1,100 @@ +import time +import argparse +import RPi.GPIO as GPIO +from light import Tower +import database +from flask import Flask, jsonify, request + +# Pins configuration (order: green, orange, red) +GPIO_PINS = [{'name': 'green', 'pin': 22}, + {'name': 'orange', 'pin': 17}, + {'name': 'red', 'pin': 27}] + +# Create a Flask app +app = Flask(__name__) + +# Initialize the database +database.ensure_database() + +# Initialize the tower (lights) +tower = Tower(GPIO_PINS) + + +@app.after_request +def add_cors_headers(response): + response.headers['Access-Control-Allow-Origin'] = '*' + response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS' + response.headers['Access-Control-Allow-Headers'] = 'Content-Type' + return response + + +@app.route('/api/state/set', methods=['POST']) +def set_state(): + data = request.data.decode('utf-8') + state = [int(n.strip()) for n in data.split(',') if n.strip().isdigit()] + """Endpoint to get the current state of all lights.""" + tower.green.on() if state[0] else tower.green.off() + tower.orange.on() if state[1] else tower.orange.off() + tower.red.on() if state[2] else tower.red.off() + + return jsonify(state) + + +@app.route('/api/state', methods=['GET']) +def get_state(): + """Endpoint to get the current state of all lights.""" + state = database.get_all_states() + return jsonify(state) + + +@app.route('/api/toggle/', methods=['POST']) +def toggle_light(color): + """Endpoint to toggle the state of a specified light.""" + if color not in ['green', 'orange', 'red']: + return jsonify({'error': 'Invalid color'}), 404 + + # Get the light object based on the color + light = getattr(tower, color) + + # Toggle light state (on/off) + new_state = GPIO.LOW if light.state == GPIO.HIGH else GPIO.HIGH + light._set(new_state) # Update the light state in the system + + return jsonify({color: new_state}) + + +def run(tower): + """Run the tower with manual light control.""" + try: + time.sleep(0.5) + while True: + print('on') + tower.green.on() + tower.red.off() + tower.orange.off() + + time.sleep(10) + except KeyboardInterrupt: + print("\nInterrupted by user. Cleaning up...") + finally: + GPIO.cleanup() + + +def main(): + parser = argparse.ArgumentParser( + description="Control lights or run server.") + parser.add_argument('--server', action='store_true', + help='Run the Flask server to control lights via API') + + args = parser.parse_args() + + if args.server: + print("Starting Flask server...") + app.run(host='0.0.0.0', port=5000) + else: + print("Running tower control manually...") + run(tower) + + +if __name__ == '__main__': + main() diff --git a/server/requirements.txt b/server/requirements.txt new file mode 100644 index 0000000..22ac75b --- /dev/null +++ b/server/requirements.txt @@ -0,0 +1 @@ +Flask==3.1.0