feat: add brew app connection

- initialize tcp communication with brew app
- WIP value editor sync

Signed-off-by: pakintada@gmail.com <Pakin>
This commit is contained in:
pakintada@gmail.com 2026-04-03 17:25:27 +07:00
parent 08f7626dcb
commit 274025ed33
14 changed files with 431 additions and 69 deletions

View file

@ -47,6 +47,12 @@
} catch (ignored) {}
}
if (e instanceof AdbDaemonWebUsbDevice.DeviceBusyError) {
addNotification(
'ERR:Device is already in use by another program, please close the program and try again'
);
}
return false;
}
} catch (e) {

View file

@ -20,10 +20,14 @@
import { auth as authStore } from '$lib/core/stores/auth';
import { machineInfoStore } from '$lib/core/stores/machineInfoStore';
import { get } from 'svelte/store';
import { AdbDaemonWebUsbDeviceManager } from '@yume-chan/adb-daemon-webusb';
import {
AdbDaemonWebUsbDevice,
AdbDaemonWebUsbDeviceManager
} from '@yume-chan/adb-daemon-webusb';
import AdbWebCredentialStore from '@yume-chan/adb-credential-web';
import { deviceCredentialManager } from '$lib/core/adb/deviceCredManager';
import { afterNavigate } from '$app/navigation';
import { env } from '$env/dynamic/public';
const sourceDir = '/sdcard/coffeevending';
@ -35,15 +39,17 @@
recipes: []
});
let brew_status: string = $state('');
async function startFetchRecipeFromMachine() {
let instance = adb.getAdbInstance();
recipeFromMachineLoading.set(true);
// recipeFromMachineLoading.set(true);
referenceFromPage.set('brew');
console.log('check instance', instance);
if (instance) {
console.log('instance passed!');
let dev_recipe = await adb.pull(`${sourceDir}/cfg/recipe_branch_dev.json`);
// console.log('dev recipe ok', dev_recipe);
console.log('dev recipe ok', dev_recipe != undefined);
if (dev_recipe) {
if (dev_recipe.length == 0) {
// case error, do last retry
@ -54,7 +60,7 @@
else if (dev_recipe) {
// From coffeethai02
devRecipe = JSON.parse(dev_recipe);
recipeFromMachineLoading.set(false);
// recipeFromMachineLoading.set(false);
addNotification('INFO:Fetch recipe success!');
buildOverviewForBrewing();
@ -62,7 +68,7 @@
} else {
// from recipe_branch_dev
devRecipe = JSON.parse(dev_recipe);
recipeFromMachineLoading.set(false);
// recipeFromMachineLoading.set(false);
addNotification('INFO:Fetch recipe success!');
buildOverviewForBrewing();
@ -70,7 +76,7 @@
}
} else {
addNotification('ERROR:Cannot connect to machine');
recipeFromMachineLoading.set(false);
// recipeFromMachineLoading.set(false);
}
}
@ -113,7 +119,7 @@
async function connectAdb() {
try {
if (!('usb' in navigator)) {
throw new Error('WebUSB not supported, try using fallback or different browser');
throw new Error('WebUSB not supported, try using fallback method or different browser');
}
await adb.connnectViaWebUSB();
@ -131,7 +137,7 @@
async function tryAutoConnect() {
try {
if (!('usb' in navigator) || !AdbDaemonWebUsbDeviceManager.BROWSER) {
throw new Error('WebUSB not supported, try using fallback or different browser');
throw new Error('WebUSB not supported, try using fallback method or different browser');
}
const devices = await AdbDaemonWebUsbDeviceManager.BROWSER.getDevices();
@ -155,6 +161,11 @@
await deviceCredentialManager.clearAllCredentials();
} catch (ignored) {}
}
if (e instanceof AdbDaemonWebUsbDevice.DeviceBusyError) {
addNotification(
'ERR:Device is already in use by another program, please close the program and try again'
);
}
return false;
}
@ -320,6 +331,54 @@
toppingGroupFromMachineQuery.set(devRecipe['Topping']['ToppingGroup']);
}
}
$effect(() => {
const brewAppStatusInterval = setInterval(async () => {
// schedule status from .brew_web_status.log
let inst = adb.getAdbInstance();
if (inst && devRecipe) {
await adb.executeCmd(
'tail -n 1 /sdcard/coffeevending/.brew_web_status.log > /sdcard/coffeevending/.brew_web_status.latest.log'
);
let brew_status_log = await adb.pull(env.PUBLIC_BREW_WEB_LATEST_STATUS);
if (brew_status_log) {
let latest_log = brew_status_log;
if (brew_status !== latest_log) {
brew_status = latest_log;
// noti from machine
if (latest_log.includes('!!!')) {
let log = latest_log.split('!!!');
let noti_cfg = log[1];
if (noti_cfg.includes('=')) {
let noti_level = noti_cfg.split('=')[1];
let spl = log[0].split(':');
let pure_msg = spl[spl.length - 1];
// case special message
if (pure_msg.includes('starting retry process')) {
// is waiting/idle process
pure_msg = 'Wait for brewing';
}
addNotification(`${noti_level}:${pure_msg}`);
}
}
}
}
} else if (inst && !devRecipe) {
// try again
// await startFetchRecipeFromMachine();
}
}, 1000);
return () => {
clearInterval(brewAppStatusInterval);
};
});
</script>
<div class="mx-8 flex">
@ -333,7 +392,7 @@
</p>
</div>
<div class="mx-8 my-4 flex gap-2">
{#if !adb.getAdbInstance()}
{#if !adb.getAdbInstance() || !devRecipe}
<Button variant="default" onclick={() => connectAdb()}>Connect</Button>
{:else}
<Button variant="default">+ Create Menu</Button>