checkpoint
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
<script lang="ts">
|
||||
import WifiConnectionDialog from "../dialogs/WifiConnectionDialog.svelte";
|
||||
import ChangeHostnameDialog from "../dialogs/ChangeHostnameDialog.svelte";
|
||||
import WifiConnectionDialog from "$dialogs/WifiConnectionDialog.svelte";
|
||||
import ChangeHostnameDialog from "$dialogs/ChangeHostnameDialog.svelte";
|
||||
import Button, { Label } from "@smui/button";
|
||||
import List, { Item, Graphic, Text, Meta } from "@smui/list";
|
||||
import Card from "@smui/card";
|
||||
import { networkInfo } from "../lib/NetworkInfo";
|
||||
import type { WifiNetwork } from "../lib/NetworkInfo";
|
||||
import { networkInfo, type WifiNetwork } from "$lib/NetworkInfo";
|
||||
|
||||
let changeHostnameDialog = {
|
||||
open: false,
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<script lang="ts">
|
||||
import HomeMachineDialog from "../dialogs/HomeMachineDialog.svelte";
|
||||
import { HomeMachine } from "../lib/DialogProps";
|
||||
</script>
|
||||
|
||||
<HomeMachineDialog {...$HomeMachine} />
|
||||
@@ -2,8 +2,8 @@
|
||||
import Dialog, { Title, Content, Actions } from "@smui/dialog";
|
||||
import Button, { Label } from "@smui/button";
|
||||
import TextField from "@smui/textfield";
|
||||
import MessageDialog from "./MessageDialog.svelte";
|
||||
import * as api from "../lib/api";
|
||||
import MessageDialog from "$dialogs/MessageDialog.svelte";
|
||||
import * as api from "$lib/api";
|
||||
|
||||
// https://man7.org/linux/man-pages/man7/hostname.7.html
|
||||
//
|
||||
|
||||
38
src/svelte-components/src/dialogs/DialogHost.svelte
Normal file
38
src/svelte-components/src/dialogs/DialogHost.svelte
Normal file
@@ -0,0 +1,38 @@
|
||||
<script lang="ts" context="module">
|
||||
import HomeMachineDialog from "$dialogs/HomeMachineDialog.svelte";
|
||||
import ProbeDialog from "$dialogs/ProbeDialog.svelte";
|
||||
import {
|
||||
HomeMachineProps,
|
||||
ProbeProps,
|
||||
type HomeMachinePropsType,
|
||||
type ProbePropsType,
|
||||
} from "$dialogs/DialogProps";
|
||||
|
||||
export function showDialog(
|
||||
dialog: "HomeMachine",
|
||||
props: Omit<HomeMachinePropsType, "open">
|
||||
);
|
||||
|
||||
export function showDialog(
|
||||
dialog: "Probe",
|
||||
props: Omit<ProbePropsType, "open">
|
||||
);
|
||||
|
||||
export function showDialog(dialog: string, props: any) {
|
||||
switch (dialog) {
|
||||
case "HomeMachine":
|
||||
HomeMachineProps.set({ ...props, open: true });
|
||||
break;
|
||||
|
||||
case "Probe":
|
||||
ProbeProps.set({ ...props, open: true });
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown dialog '${dialog}`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<HomeMachineDialog {...$HomeMachineProps} />
|
||||
<ProbeDialog {...$ProbeProps} />
|
||||
13
src/svelte-components/src/dialogs/DialogProps.ts
Normal file
13
src/svelte-components/src/dialogs/DialogProps.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export const HomeMachineProps = writable<HomeMachinePropsType>();
|
||||
export type HomeMachinePropsType = {
|
||||
open: boolean,
|
||||
home: () => void
|
||||
}
|
||||
|
||||
export const ProbeProps = writable<ProbePropsType>();
|
||||
export type ProbePropsType = {
|
||||
open: boolean,
|
||||
probeType: "xyz" | "z"
|
||||
};
|
||||
293
src/svelte-components/src/dialogs/ProbeDialog.svelte
Normal file
293
src/svelte-components/src/dialogs/ProbeDialog.svelte
Normal file
@@ -0,0 +1,293 @@
|
||||
<script type="ts" context="module">
|
||||
import Dialog, { Title, Content, Actions } from "@smui/dialog";
|
||||
import Button, { Label } from "@smui/button";
|
||||
import { get, writable, type Writable } from "svelte/store";
|
||||
import { Config } from "$lib/ConfigStore";
|
||||
import { waitForChange } from "$lib/StoreHelpers";
|
||||
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
||||
import { tick } from "svelte";
|
||||
|
||||
type Stage =
|
||||
| "None"
|
||||
| "TestingProbe"
|
||||
| "TestingProbeComplete"
|
||||
| "GetToolDiameter"
|
||||
| "Probing"
|
||||
| "ProbingFailed"
|
||||
| "ProbingComplete";
|
||||
|
||||
const cancelled = writable(false);
|
||||
const probingActive = writable(false);
|
||||
const probeContacted = writable(false);
|
||||
const probingStarted = writable(false);
|
||||
const probingFailed = writable(false);
|
||||
const probingComplete = writable(false);
|
||||
const userAcknowledged = writable(false);
|
||||
|
||||
export function handleControllerStateUpdate(state: Record<string, any>) {
|
||||
if (!get(probingActive)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case state.pw === 0:
|
||||
probeContacted.set(true);
|
||||
break;
|
||||
|
||||
case state.log?.msg === "Switch not found":
|
||||
probingFailed.set(true);
|
||||
break;
|
||||
|
||||
case state.cycle !== "idle":
|
||||
probingStarted.set(true);
|
||||
break;
|
||||
|
||||
case state.cycle === "idle":
|
||||
if (get(probingStarted)) {
|
||||
probingStarted.set(false);
|
||||
probingComplete.set(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="ts">
|
||||
export let open;
|
||||
export let probeType: "xyz" | "z";
|
||||
let stage: Stage = "None";
|
||||
let toolDiameter;
|
||||
let confirmButton = {
|
||||
label: "Continue",
|
||||
disabled: false,
|
||||
allowClose: false,
|
||||
};
|
||||
|
||||
$: showPrompts = $Config.settings?.["probing-prompts"];
|
||||
$: clearFlags(stage);
|
||||
$: updateConfirmButton();
|
||||
|
||||
$: if (open) {
|
||||
// Svelte appears not to like it when you invoke
|
||||
// an async function from a reactive statement
|
||||
requestAnimationFrame(begin);
|
||||
}
|
||||
|
||||
function updateConfirmButton() {
|
||||
confirmButton.label = "Continue";
|
||||
confirmButton.disabled = false;
|
||||
confirmButton.allowClose = false;
|
||||
|
||||
switch (stage) {
|
||||
case "TestingProbe":
|
||||
case "Probing":
|
||||
confirmButton.disabled = true;
|
||||
break;
|
||||
|
||||
case "ProbingComplete":
|
||||
confirmButton.disabled = true;
|
||||
confirmButton.label = "Done";
|
||||
confirmButton.allowClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async function begin() {
|
||||
try {
|
||||
$probingActive = true;
|
||||
|
||||
assertValidProbeType();
|
||||
|
||||
if (showPrompts) {
|
||||
stage = "TestingProbe";
|
||||
|
||||
await cancellableSignal(probeContacted);
|
||||
|
||||
stage = "TestingProbeComplete";
|
||||
await cancellableSignal(userAcknowledged);
|
||||
}
|
||||
|
||||
if (probeType === "xyz") {
|
||||
stage = "GetToolDiameter";
|
||||
await cancellableSignal(userAcknowledged);
|
||||
}
|
||||
|
||||
do {
|
||||
stage = "Probing";
|
||||
executeProbe(probeType, toolDiameter);
|
||||
|
||||
await cancellableSignal(probingComplete, probingFailed);
|
||||
|
||||
if ($probingFailed) {
|
||||
stage = "ProbingFailed";
|
||||
await cancellableSignal(userAcknowledged);
|
||||
}
|
||||
} while (!$probingComplete);
|
||||
|
||||
stage = "ProbingComplete";
|
||||
await cancellableSignal(userAcknowledged);
|
||||
|
||||
if (probeType === "xyz") {
|
||||
ControllerMethods.goto_zero(1, 1, 0, 0);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.message !== "cancelled") {
|
||||
console.error("Error during probing:", err);
|
||||
}
|
||||
} finally {
|
||||
$probingActive = false;
|
||||
stage = "None";
|
||||
clearFlags();
|
||||
}
|
||||
}
|
||||
|
||||
async function cancellableSignal<T>(...writables: Array<Writable<T>>) {
|
||||
await Promise.race([
|
||||
...writables.map((writable) => waitForChange(writable)),
|
||||
waitForChange(cancelled),
|
||||
]);
|
||||
|
||||
if ($cancelled) {
|
||||
throw new Error("cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
function clearFlags(foo: string = "") {
|
||||
$cancelled = false;
|
||||
$probeContacted = false;
|
||||
$probingStarted = false;
|
||||
$probingFailed = false;
|
||||
$probingComplete = false;
|
||||
$userAcknowledged = false;
|
||||
}
|
||||
|
||||
function assertValidProbeType() {
|
||||
switch (probeType) {
|
||||
case "xyz":
|
||||
case "z":
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Invalid probe type: ${probeType}`);
|
||||
}
|
||||
}
|
||||
|
||||
function executeProbe(probeType: "xyz" | "z", toolDiameter: number) {
|
||||
const probeBlockWidth = $Config.probe["probe-xdim"];
|
||||
const probeBlockLength = $Config.probe["probe-ydim"];
|
||||
const probeBlockHeight = $Config.probe["probe-zdim"];
|
||||
const slowSeek = $Config.probe["probe-slow-seek"];
|
||||
const fastSeek = $Config.probe["probe-fast-seek"];
|
||||
|
||||
const zLift = 1;
|
||||
const xOffset = probeBlockWidth + toolDiameter / 2.0;
|
||||
const yOffset = probeBlockLength + toolDiameter / 2.0;
|
||||
const zOffset = probeBlockHeight;
|
||||
|
||||
if (probeType === "z") {
|
||||
ControllerMethods.send(`
|
||||
G21
|
||||
G92 Z0
|
||||
|
||||
G38.2 Z -25.4 F${fastSeek}
|
||||
G91 G1 Z 1
|
||||
G38.2 Z -2 F${slowSeek}
|
||||
G92 Z ${zOffset}
|
||||
|
||||
G91 G0 Z 3
|
||||
|
||||
M2
|
||||
`);
|
||||
} else {
|
||||
// After probing Z, we want to drop the bit down:
|
||||
// Ideally, 12.7mm/0.5in
|
||||
// And we don't want to be more than 75% down on the probe block
|
||||
// Also, add zlift to compensate for the fact that we lift after probing Z
|
||||
const plunge = Math.min(12.7, zOffset * 0.75) + zLift;
|
||||
|
||||
ControllerMethods.send(`
|
||||
G21
|
||||
G92 X0 Y0 Z0
|
||||
|
||||
G38.2 Z -25 F${fastSeek}
|
||||
G91 G1 Z 1
|
||||
G38.2 Z -2 F${slowSeek}
|
||||
G92 Z ${zOffset}
|
||||
|
||||
G91 G0 Z ${zLift}
|
||||
G91 G0 X 20
|
||||
G91 G0 Z ${-plunge}
|
||||
G38.2 X -20 F${fastSeek}
|
||||
G91 G1 X 1
|
||||
G38.2 X -2 F${slowSeek}
|
||||
G92 X ${xOffset}
|
||||
|
||||
G91 G0 X 1
|
||||
G91 G0 Y 20
|
||||
G91 G0 X -20
|
||||
G38.2 Y -20 F${fastSeek}
|
||||
G91 G1 Y 1
|
||||
G38.2 Y -2 F${slowSeek}
|
||||
G92 Y ${yOffset}
|
||||
|
||||
G91 G0 Y 3
|
||||
G91 G0 Z 25
|
||||
|
||||
M2
|
||||
`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog
|
||||
bind:open
|
||||
scrimClickAction=""
|
||||
aria-labelledby="simple-title"
|
||||
aria-describedby="simple-content"
|
||||
>
|
||||
<Title id="simple-title">Probe {probeType}</Title>
|
||||
|
||||
<Content id="simple-content">
|
||||
{#if stage === "TestingProbe" || stage === "TestingProbeComplete"}
|
||||
<p>Attach the probe magnet to the collet.</p>
|
||||
<p>Touch the probe block to the bit.</p>
|
||||
|
||||
{#if stage === "TestingProbe"}
|
||||
<p>Waiting for probe contact...</p>
|
||||
{:else}
|
||||
<p>Probe contact detected!</p>
|
||||
{/if}
|
||||
{:else if stage === "GetToolDiameter"}
|
||||
<label for="tool-diameter">Tool Diameter (mm)</label>
|
||||
<input id="tool-diameter" bind:value={toolDiameter} />
|
||||
{:else if stage === "Probing"}
|
||||
<p>Probing in progress...</p>
|
||||
{:else if stage === "ProbingFailed"}
|
||||
<p>Could not find the probe block during probing!</p>
|
||||
<p>
|
||||
Make sure the tip of the bit is about 1/4" (6mm) above the probe block,
|
||||
and try again.
|
||||
</p>
|
||||
{:else if stage === "ProbingComplete"}
|
||||
<p>Don't forget to put away the probe!</p>
|
||||
<p>The machine will now move to the XY origin.</p>
|
||||
<p>Watch your hands!</p>
|
||||
{/if}
|
||||
</Content>
|
||||
|
||||
<Actions>
|
||||
<Button on:click={() => ($cancelled = true)}>
|
||||
<Label>Cancel</Label>
|
||||
</Button>
|
||||
<Button
|
||||
defaultAction
|
||||
data-mdc-dialog-action={confirmButton.allowClose ? "close" : ""}
|
||||
disabled={confirmButton.disabled}
|
||||
on:click={() => ($userAcknowledged = true)}
|
||||
>
|
||||
<Label>
|
||||
{confirmButton.label}
|
||||
</Label>
|
||||
</Button>
|
||||
</Actions>
|
||||
</Dialog>
|
||||
@@ -4,28 +4,22 @@
|
||||
import TextField from "@smui/textfield";
|
||||
import Icon from "@smui/textfield/icon";
|
||||
import HelperText from "@smui/textfield/helper-text";
|
||||
import MessageDialog from "./MessageDialog.svelte";
|
||||
import type { WifiNetwork } from "../lib/NetworkInfo";
|
||||
import * as api from "../lib/api";
|
||||
import MessageDialog from "$dialogs/MessageDialog.svelte";
|
||||
import type { WifiNetwork } from "$lib/NetworkInfo";
|
||||
import * as api from "$lib/api";
|
||||
|
||||
export let open = false;
|
||||
export let network: WifiNetwork;
|
||||
|
||||
let rebooting = false;
|
||||
let needPassword = false;
|
||||
let password = "";
|
||||
let showPassword = false;
|
||||
let connectOrDisconnect: string;
|
||||
let connectToOrDisconnectFrom: string;
|
||||
|
||||
$: needPassword = !network?.active && network?.Encryption !== "Open";
|
||||
|
||||
$: {
|
||||
connectOrDisconnect = network?.active ? "Disconnect" : "Connect";
|
||||
connectToOrDisconnectFrom = network?.active
|
||||
$: connectOrDisconnect = network?.active ? "Disconnect" : "Connect";
|
||||
$: connectToOrDisconnectFrom = network?.active
|
||||
? "Disconnect from"
|
||||
: "Connect to";
|
||||
}
|
||||
|
||||
$: if (open) {
|
||||
password = "";
|
||||
|
||||
7
src/svelte-components/src/lib/ConfigStore.ts
Normal file
7
src/svelte-components/src/lib/ConfigStore.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export const Config = writable<Record<string, any>>({});
|
||||
|
||||
export function handleConfigUpdate(config: Record<string, any>) {
|
||||
Config.set(config);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
type HomeMachine = {
|
||||
open: boolean,
|
||||
home: () => any
|
||||
}
|
||||
|
||||
export type DialogPropsTypes = {
|
||||
HomeMachine: HomeMachine
|
||||
}
|
||||
|
||||
export const HomeMachine = writable<HomeMachine>();
|
||||
|
||||
export default {
|
||||
HomeMachine
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { readable } from "svelte/store";
|
||||
import * as api from "./api";
|
||||
import * as api from "$lib/api";
|
||||
|
||||
export type WifiNetwork = {
|
||||
Quality: string;
|
||||
|
||||
10
src/svelte-components/src/lib/RegisterControllerMethods.ts
Normal file
10
src/svelte-components/src/lib/RegisterControllerMethods.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
type ControllerMethods = {
|
||||
send: (gcode: string) => void;
|
||||
goto_zero: (x: number, y: number, z: number, a: number) => void;
|
||||
}
|
||||
|
||||
export let ControllerMethods: ControllerMethods;
|
||||
|
||||
export function registerControllerMethods(methods: ControllerMethods) {
|
||||
ControllerMethods = methods;
|
||||
}
|
||||
18
src/svelte-components/src/lib/StoreHelpers.ts
Normal file
18
src/svelte-components/src/lib/StoreHelpers.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { get, type Writable } from "svelte/store";
|
||||
|
||||
export function listenForChange<T>(writable: Writable<T>, cb: (value: T) => void) {
|
||||
const priorValue = get(writable);
|
||||
|
||||
const unsubscribe = writable.subscribe((value) => {
|
||||
if (value !== priorValue) {
|
||||
unsubscribe();
|
||||
cb(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function waitForChange<T>(writable: Writable<T>): Promise<T> {
|
||||
return new Promise((resolve) => {
|
||||
listenForChange(writable, (value) => resolve(value));
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import 'polyfill-object.fromentries';
|
||||
import AdminNetworkView from './components/AdminNetworkView.svelte';
|
||||
import { init as initNetworkInfo } from './lib/NetworkInfo';
|
||||
|
||||
import DialogHost from "./components/DialogHost.svelte";
|
||||
import DialogProps from "./lib/DialogProps";
|
||||
import type { DialogPropsTypes } from "./lib/DialogProps";
|
||||
import AdminNetworkView from '$components/AdminNetworkView.svelte';
|
||||
import DialogHost, { showDialog } from "$dialogs/DialogHost.svelte";
|
||||
import { handleConfigUpdate } from '$lib/ConfigStore';
|
||||
import { init as initNetworkInfo } from '$lib/NetworkInfo';
|
||||
import { handleControllerStateUpdate } from "$dialogs/ProbeDialog.svelte";
|
||||
import { registerControllerMethods } from "$lib/RegisterControllerMethods";
|
||||
|
||||
export function createComponent(component: string, target: HTMLElement, props: Record<string, any>) {
|
||||
switch (component) {
|
||||
@@ -19,17 +20,10 @@ export function createComponent(component: string, target: HTMLElement, props: R
|
||||
}
|
||||
}
|
||||
|
||||
export function showDialog<T extends keyof typeof DialogProps>(dialog: T, props: DialogPropsTypes[T]) {
|
||||
switch (dialog) {
|
||||
case "HomeMachine":
|
||||
DialogProps.HomeMachine.set({ ...props, open: true });
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown dialog '${dialog}`);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
initNetworkInfo
|
||||
initNetworkInfo,
|
||||
showDialog,
|
||||
handleControllerStateUpdate,
|
||||
handleConfigUpdate,
|
||||
registerControllerMethods,
|
||||
};
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
"module": "esnext",
|
||||
"resolveJsonModule": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"$lib/*": ["src/lib/*"],
|
||||
"$components/*": ["src/components/*"],
|
||||
"$dialogs/*": ["src/dialogs/*"]
|
||||
},
|
||||
/**
|
||||
* Typecheck JS in `.svelte` and `.js` files by default.
|
||||
* Disable checkJs if you'd like to use dynamic types in JS.
|
||||
|
||||
@@ -7,6 +7,13 @@ export default defineConfig({
|
||||
plugins: [
|
||||
svelte()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
$lib: resolve('./src/lib'),
|
||||
$dialogs: resolve('./src/dialogs'),
|
||||
$components: resolve('./src/components')
|
||||
}
|
||||
},
|
||||
build: {
|
||||
target: "chrome60",
|
||||
lib: {
|
||||
|
||||
Reference in New Issue
Block a user