|
@@ -0,0 +1,141 @@
|
|
|
|
|
+import { computed, ref } from 'vue'
|
|
|
|
|
+import client from '@/stores/modules/client'
|
|
|
|
|
+import socket from '@/stores/modules/socket'
|
|
|
|
|
+import icpList from '@/utils/ipc'
|
|
|
|
|
+
|
|
|
|
|
+const SCALE_CHANNEL = icpList.socket.message + '_anheng_scale'
|
|
|
|
|
+const STATUS_CHANNEL = icpList.socket.message + '_anheng_scale_status'
|
|
|
|
|
+const POLL_MS = 300
|
|
|
|
|
+
|
|
|
|
|
+const everConnected = ref(false)
|
|
|
|
|
+const status = ref<'unknown' | 'absent' | 'connected' | 'disconnected'>('unknown')
|
|
|
|
|
+const stable = ref<boolean | null>(null)
|
|
|
|
|
+const netGrams = ref<number | null>(null)
|
|
|
|
|
+const lockedGrams = ref<number | null>(null)
|
|
|
|
|
+
|
|
|
|
|
+let pollTimer: ReturnType<typeof setInterval> | null = null
|
|
|
|
|
+let listening = false
|
|
|
|
|
+
|
|
|
|
|
+export function formatScaleWeight(value: unknown): string {
|
|
|
|
|
+ if (value == null || value === '' || value === 'None' || value === 'null' || value === 'undefined') {
|
|
|
|
|
+ return ''
|
|
|
|
|
+ }
|
|
|
|
|
+ const grams = typeof value === 'number' ? value : Number(String(value).trim())
|
|
|
|
|
+ if (!Number.isFinite(grams)) return ''
|
|
|
|
|
+ if (Math.abs(grams) >= 1000) return `${(grams / 1000).toFixed(3)} kg`
|
|
|
|
|
+ return `${grams.toFixed(1)} g`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function requestScale() {
|
|
|
|
|
+ socket().sendMessage({ type: 'get_scale_data' })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function stopPoll() {
|
|
|
|
|
+ if (pollTimer != null) {
|
|
|
|
|
+ clearInterval(pollTimer)
|
|
|
|
|
+ pollTimer = null
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function markConnected() {
|
|
|
|
|
+ if (!listening) return
|
|
|
|
|
+ everConnected.value = true
|
|
|
|
|
+ status.value = 'connected'
|
|
|
|
|
+ if (pollTimer != null) return
|
|
|
|
|
+ requestScale()
|
|
|
|
|
+ pollTimer = setInterval(requestScale, POLL_MS)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function markLost() {
|
|
|
|
|
+ if (!everConnected.value) {
|
|
|
|
|
+ status.value = 'absent'
|
|
|
|
|
+ stopPoll()
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ status.value = 'disconnected'
|
|
|
|
|
+ stable.value = null
|
|
|
|
|
+ netGrams.value = null
|
|
|
|
|
+ stopPoll()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onScaleData(_event: unknown, result: any) {
|
|
|
|
|
+ if (!listening || !result || result.code !== 0 || !result.data) return
|
|
|
|
|
+ const grams = Number(result.data.net_grams)
|
|
|
|
|
+ stable.value = result.data.stable === true ? true : result.data.stable === false ? false : null
|
|
|
|
|
+ netGrams.value = Number.isFinite(grams) ? grams : null
|
|
|
|
|
+ markConnected()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onScaleStatus(_event: unknown, result: any) {
|
|
|
|
|
+ if (!listening) return
|
|
|
|
|
+ const next = result?.data?.status
|
|
|
|
|
+ if (next === 'connected' || next === 'reconnected') {
|
|
|
|
|
+ markConnected()
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (next === 'disconnected' || next === 'reconnecting' || next === 'closed' || result?.code === 1) {
|
|
|
|
|
+ markLost()
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function peekLockedWeight(): number | null {
|
|
|
|
|
+ const grams = lockedGrams.value
|
|
|
|
|
+ if (grams == null || !Number.isFinite(grams)) return null
|
|
|
|
|
+ return grams
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function clearLockedWeight() {
|
|
|
|
|
+ lockedGrams.value = null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function lockScaleWeight() {
|
|
|
|
|
+ if (status.value !== 'connected' || stable.value !== true) return
|
|
|
|
|
+ if (netGrams.value == null || !Number.isFinite(netGrams.value)) return
|
|
|
|
|
+ lockedGrams.value = Math.round(netGrams.value * 10) / 10
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function unlockScaleWeight() {
|
|
|
|
|
+ lockedGrams.value = null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function startScale() {
|
|
|
|
|
+ const clientStore = client()
|
|
|
|
|
+ if (!clientStore.isClient || !clientStore.ipc || listening) return
|
|
|
|
|
+ listening = true
|
|
|
|
|
+ await socket().connectSocket()
|
|
|
|
|
+ if (!listening) return
|
|
|
|
|
+ clientStore.ipc.removeAllListeners(SCALE_CHANNEL)
|
|
|
|
|
+ clientStore.ipc.removeAllListeners(STATUS_CHANNEL)
|
|
|
|
|
+ clientStore.ipc.on(SCALE_CHANNEL, onScaleData)
|
|
|
|
|
+ clientStore.ipc.on(STATUS_CHANNEL, onScaleStatus)
|
|
|
|
|
+ requestScale()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function stopScale() {
|
|
|
|
|
+ const ipc = client().ipc
|
|
|
|
|
+ stopPoll()
|
|
|
|
|
+ if (ipc?.removeListener) {
|
|
|
|
|
+ ipc.removeListener(SCALE_CHANNEL, onScaleData)
|
|
|
|
|
+ ipc.removeListener(STATUS_CHANNEL, onScaleStatus)
|
|
|
|
|
+ }
|
|
|
|
|
+ listening = false
|
|
|
|
|
+ everConnected.value = false
|
|
|
|
|
+ status.value = 'unknown'
|
|
|
|
|
+ stable.value = null
|
|
|
|
|
+ netGrams.value = null
|
|
|
|
|
+ lockedGrams.value = null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function useScale() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ everConnected,
|
|
|
|
|
+ connected: computed(() => status.value === 'connected'),
|
|
|
|
|
+ stable,
|
|
|
|
|
+ liveText: computed(() => formatScaleWeight(netGrams.value)),
|
|
|
|
|
+ lockedText: computed(() => formatScaleWeight(lockedGrams.value)),
|
|
|
|
|
+ startScale,
|
|
|
|
|
+ stopScale,
|
|
|
|
|
+ lockScaleWeight,
|
|
|
|
|
+ unlockScaleWeight,
|
|
|
|
|
+ }
|
|
|
|
|
+}
|