Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
DTTerastar committed Nov 19, 2024
1 parent b6e36f6 commit 592988b
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 151 deletions.
20 changes: 12 additions & 8 deletions src/Controllers/DeviceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ public DeviceController(ILogger<DeviceController> logger, DeviceSettingsStore de
_state = state;
}

[HttpGet("{id}/details")]
public async Task<IList<KeyValuePair<string, string>>> Details(string id)

Check warning on line 23 in src/Controllers/DeviceController.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
if (_state.Devices.TryGetValue(id, out var device))
return device.GetDetails().ToList();
return new List<KeyValuePair<string, string>>();
}

[HttpGet("{id}/settings")]
public DeviceSettingsDetails Get(string id)
public Task<DeviceSettings?> Get(string id)
{
var deviceSettings = _deviceSettingsStore.Get(id);
var details = new List<KeyValuePair<string, string>>();
if (deviceSettings?.Id != null && _state.Devices.TryGetValue(deviceSettings.Id, out var device))
details.AddRange(device.GetDetails());
return new DeviceSettingsDetails(deviceSettings ?? new DeviceSettings { Id = id, OriginalId = id }, details);
var settings = _deviceSettingsStore.Get(id);
settings ??= new DeviceSettings { OriginalId = id, Id = id };
return Task.FromResult(settings);

Check warning on line 35 in src/Controllers/DeviceController.cs

View workflow job for this annotation

GitHub Actions / build

Nullability of reference types in value of type 'Task<DeviceSettings>' doesn't match target type 'Task<DeviceSettings?>'.
}

[HttpPut("{id}/settings")]
Expand All @@ -35,6 +41,4 @@ public async Task Set(string id, [FromBody] DeviceSettings value)
await _deviceSettingsStore.Set(id, value);
}
}

public readonly record struct DeviceSettingsDetails(DeviceSettings? settings, IList<KeyValuePair<string, string>> details);
}
14 changes: 5 additions & 9 deletions src/ui/src/lib/NodeActions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
import { getModalStore, getToastStore, type ToastSettings } from '@skeletonlabs/skeleton';
import { updateMethod, flavor, version, artifact, flavorNames } from '$lib/firmware';
import Firmware from '$lib/modals/Firmware.svelte';
import { restartNode, updateNodeSelf } from '$lib/node';
const modalStore = getModalStore();
const toastStore = getToastStore();
async function onRestart(i: Node) {
try {
var response = await fetch(`${base}/api/node/${i.id}/restart`, { method: 'POST' });
if (response.status != 200) throw new Error(response.statusText);
await restartNode(i.id);
toastStore.trigger({ message: i.name + ' asked to reboot', background: 'variant-filled-primary' });
} catch (e) {
console.log(e);
toastStore.trigger({ message: e, background: 'variant-filled-error' });
toastStore.trigger({ message: e instanceof Error ? e.message : String(e), background: 'variant-filled-error' });
}
}
Expand Down Expand Up @@ -44,12 +44,8 @@
});
} else {
if (i) {
fetch(`${base}/api/node/${i.id}/update`, {
method: 'POST',
body: ''
})
.then((response) => {
if (response.status != 200) throw new Error(response.statusText);
updateNodeSelf(i.id)
.then(() => {
const t: ToastSettings = { message: (i.name ?? i.id) + ' asked to update itself', background: 'variant-filled-primary' };
toastStore.trigger(t);
})
Expand Down
31 changes: 11 additions & 20 deletions src/ui/src/lib/NodeSettings.svelte
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
<script lang="ts">
import { base } from '$app/paths';
import { Accordion, AccordionItem } from '@skeletonlabs/skeleton';
import { getToastStore } from '@skeletonlabs/skeleton';
import type { ToastSettings } from '@skeletonlabs/skeleton';
import type { NodeSetting } from './types';
import { saveNodeSettings } from '$lib/node';
export let settings: NodeSetting | null = null;
const toastStore = getToastStore();
function save() {
if (settings) {
fetch(`${base}/api/node/${settings.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(settings)
})
.then((response) => {
if (response.status != 200) throw new Error(response.statusText);
})
.catch((e) => {
console.log(e);
const t: ToastSettings = { message: e, background: 'variant-filled-error' };
toastStore.trigger(t);
});
async function save() {
if (settings && settings.id) {
try {
await saveNodeSettings(settings.id, settings);
} catch (e) {
console.log(e);
const t: ToastSettings = { message: e instanceof Error ? e.message : String(e), background: 'variant-filled-error' };
toastStore.trigger(t);
}
}
}
</script>
Expand Down Expand Up @@ -62,7 +53,7 @@
<span>Max Distance</span>
<input class="input" type="text" placeholder="" bind:value={settings.max_distance} />
</label>
<button class="btn bg-success-700 text-black" on:click={(e) => save()}>Save</button>
<button class="btn bg-success-700 text-black" on:click|preventDefault={save}>Save</button>
</form>
</svelte:fragment>
</AccordionItem>
Expand Down
14 changes: 14 additions & 0 deletions src/ui/src/lib/device.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { base } from '$app/paths';
import type { DeviceSetting, DeviceDetail } from './types';

export async function fetchDeviceSettings(fetch, id: string): Promise<DeviceSetting> {
const response = await fetch(`${base}/api/device/${id}/settings`);
if (!response.ok) throw new Error("Something went wrong loading device details (error="+response.status+" "+response.statusText+")");
return await response.json();
}

export async function fetchDeviceDetails(id: string): Promise<DeviceDetail> {
const response = await fetch(`${base}/api/device/${id}/details`);
if (!response.ok) throw new Error("Something went wrong loading device details (error="+response.status+" "+response.statusText+")");
return await response.json();
}
47 changes: 47 additions & 0 deletions src/ui/src/lib/node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { base } from '$app/paths';
import type { Settings, Node, NodeSetting } from './types';

export async function loadSettings(id: string): Promise<Settings> {
const response = await fetch(`${base}/api/node/${id}/settings`);
if (!response.ok) throw new Error("Something went wrong loading settings (error="+response.status+" "+response.statusText+")");
return await response.json();
}

export async function saveSettings(newSettings: Settings): Promise<Settings> {
const response = await fetch(`${base}/api/node/${newSettings.id}/settings`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newSettings),
});
if (!response.ok) throw new Error("Something went wrong loading settings (error="+response.status+" "+response.statusText+")");
return await response.json();
}

export async function restartNode(nodeId: string): Promise<void> {
const response = await fetch(`${base}/api/node/${nodeId}/restart`, { method: 'POST' });
if (!response.ok) throw new Error(response.statusText);
}

export async function updateNodeSelf(nodeId: string): Promise<void> {
const response = await fetch(`${base}/api/node/${nodeId}/update`, { method: 'POST' });
if (!response.ok) throw new Error(response.statusText);
}

export async function saveNodeSettings(nodeId: string, settings: NodeSetting): Promise<void> {
const response = await fetch(`${base}/api/node/${nodeId}/settings`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(settings)
});
if (!response.ok) throw new Error(response.statusText);
}

export async function fetchNode(nodeId: string): Promise<Node> {
const response = await fetch(`${base}/api/node/${nodeId}/settings`);
if (!response.ok) throw new Error(response.statusText);
return await response.json();
}
26 changes: 26 additions & 0 deletions src/ui/src/lib/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { base } from '$app/paths';
import type { Config, CalibrationData, Device } from './types';

export async function fetchConfig(): Promise<Config> {
const response = await fetch(`${base}/api/state/config`);
if (!response.ok) throw new Error("Something went wrong loading config (error="+response.status+" "+response.statusText+")");
return await response.json();
}

export async function fetchCalibrationState(): Promise<CalibrationData> {
const response = await fetch(`${base}/api/state/calibration`);
if (!response.ok) throw new Error("Something went wrong loading calibration state (error="+response.status+" "+response.statusText+")");
return await response.json();
}

export async function fetchDeviceState(): Promise<Device[]> {
const response = await fetch(`${base}/api/state/devices`);
if (!response.ok) throw new Error("Something went wrong loading device state (error="+response.status+" "+response.statusText+")");
return await response.json();
}

export async function fetchNodeState(includeTele: boolean = true): Promise<Node[]> {
const response = await fetch(`${base}/api/state/nodes?includeTele=${includeTele}`);
if (!response.ok) throw new Error("Something went wrong loading node state (error="+response.status+" "+response.statusText+")");
return await response.json();
}
31 changes: 10 additions & 21 deletions src/ui/src/lib/stores.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { readable, writable, derived } from 'svelte/store';
import { base } from '$app/paths';
import type { Device, Config, Node, CalibrationResponse } from './types';
import type { Device, Config, Node, NodeSettings, CalibrationResponse } from './types';
import { loadSettings, saveSettings } from './node';
import { fetchConfig, fetchCalibrationState, fetchDeviceState, fetchNodeState } from './state';

export const showAll: SvelteStore<boolean> = writable(false);
export const config = writable<Config>();
Expand Down Expand Up @@ -37,8 +39,8 @@ let socket: WebSocket;
export const history = writable(['/']);

async function getConfig() {
const response = await fetch(`${base}/api/state/config`);
config.set(await response.json());
const data = await fetchConfig();
config.set(data);
}

getConfig();
Expand Down Expand Up @@ -112,8 +114,7 @@ export const nodes = readable<Node[]>([], function start(set) {
const interval = setInterval(() => {
if (outstanding) return;
outstanding = true;
fetch(`${base}/api/state/nodes?includeTele=true`)
.then((d) => d.json())
fetchNodeState()
.then((r) => {
outstanding = false;
errors = 0;
Expand All @@ -133,15 +134,12 @@ export const nodes = readable<Node[]>([], function start(set) {

export const calibration = readable<CalibrationResponse>({matrix: {}}, function start(set) {
async function fetchAndSet() {
const response = await fetch(`${base}/api/state/calibration`);
var data = await response.json();
const data = await fetchCalibrationState();
set(data);
}

fetchAndSet();
const interval = setInterval(() => {
fetchAndSet();
}, 1000);
const interval = setInterval(fetchAndSet, 1000);

return function stop() {
clearInterval(interval);
Expand All @@ -156,20 +154,11 @@ export const settings = (() => {
set,
update,
load: async () => {
const response = await fetch(`${base}/api/node/*/settings`);
if (!response.ok) throw new Error("Something went wrong loading settings (error="+response.status+" "+response.statusText+")");
const data = await response.json();
const data = await loadSettings("*");
set(data);
},
save: async (newSettings: Settings) => {
const response = await fetch(`${base}/api/node/*/settings`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newSettings),
});
const data = await response.json();
const data = await saveSettings(newSettings);
set(data);
},
};
Expand Down
15 changes: 5 additions & 10 deletions src/ui/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,7 @@ export interface Config {
map: MapConfig;
}

export type NodeSetting = {
id: string | null;
name: string | null;
absorption: number | null;
rx_adj_rssi: number | null;
tx_ref_rssi: number | null;
max_distance: number | null;
};
export type DeviceDetail = Array<{ key: string; value: string }>;

export type DeviceSetting = {
originalId: string;
Expand Down Expand Up @@ -160,7 +153,9 @@ export interface CalibrationResponse {
matrix: CalibrationMatrix;
}

export type NodeSettings = {
export type NodeSetting = {
id: string | null;
name: string | null;
updating: {
autoUpdate: boolean;
preRelease: boolean;
Expand All @@ -184,7 +179,7 @@ export type NodeSettings = {
calibration: {
rssiAt1m: number | null;
rssiAdjustment: number | null;
absorptionFactor: number | null;
absorption: number | null;
iBeaconRssiAt1m: number | null;
};
};
Expand Down
17 changes: 11 additions & 6 deletions src/ui/src/routes/devices/[id]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@
import { base } from '$app/paths';
import { devices } from '$lib/stores';
import { readable } from 'svelte/store';
import type { DeviceSetting } from '$lib/types';
import type { DeviceSetting, DeviceDetail } from '$lib/types';
import { Accordion, AccordionItem } from '@skeletonlabs/skeleton';
import { fetchDeviceDetails } from '$lib/device';
import Map from '$lib/Map.svelte';
import DeviceDetailTabs from '$lib/DeviceDetailTabs.svelte';
import DeviceSettings from '$lib/DeviceSettings.svelte';
export let tab = 'map';
export let data: { settings?: DeviceSetting } = {};
$: device = $devices.find((d) => d.id === data.settings?.id);
export let data: { id: string, settings: DeviceSetting };
$: device = $devices.find((d) => d.id === data.id);
export const deviceDetails = readable([], (set) => {
export const deviceDetails = readable<DeviceDetail>([], (set) => {
async function fetchAndSet() {
try {
const response = await fetch(`${base}/api/device/${data.settings?.id}`);
const result = await response.json();
const id = data.id;
if (!id) {
console.error('No device id');
return;
}
const result = await fetchDeviceDetails(id);
set(result.details);
} catch (ex) {
console.error(ex);
Expand Down
27 changes: 15 additions & 12 deletions src/ui/src/routes/devices/[id]/+page.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { base } from '$app/paths';
import { error } from '@sveltejs/kit';
import type { PageLoad } from './$types';
import { fetchDeviceSettings } from '$lib/device'

export async function load({ fetch, params }) {
return await fetch(`${base}/api/device/${params.id}`)
.then((response) => {
if (response.status != 200) throw new Error(response.statusText);
var data = response.json();
return data;
})
.catch((e) => {
return { settings: { originalId: params.id, id: null, name: null, 'rssi@1m': null, error: e } };
});
}
export const load: PageLoad = async ({ fetch, params }) => {
if (!params.id) {
throw error(400, 'No device id');
}
try {
var settings = fetchDeviceSettings(fetch, params.id);
return { id: params.id, settings: settings };
}
catch (e) {
return { settings: { originalId: params.id, id: null, name: null, 'rssi@1m': null, error: e } };
}
};
Loading

0 comments on commit 592988b

Please sign in to comment.