Skip to content

Commit

Permalink
perf: 📸 Support viewing real-time images and power information of the…
Browse files Browse the repository at this point in the history
… device
  • Loading branch information
viarotel committed Dec 27, 2024
1 parent d5caaa9 commit d262adf
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 19 deletions.
91 changes: 91 additions & 0 deletions electron/exposes/adb/helpers/battery/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { camelCase } from 'lodash-es'
/**
* Parse ADB battery dump data into a structured object
*
* @param {string} dumpData - Raw battery dump data from ADB
* @returns {Object} Parsed and normalized battery data
*
* // Example usage:
* const dumpData = fs.readFileSync('battery-dump.txt', 'utf8');
* const batteryInfo = parseBatteryDump(dumpData);
* console.log(batteryInfo);
*
*/
export function parseBatteryDump(dumpData) {
// Helper to convert string values to appropriate types
const parseValue = (value) => {
value = value.trim()

// Handle booleans
if (value.toLowerCase() === 'true')
return true
if (value.toLowerCase() === 'false')
return false

// Handle numbers
if (!Number.isNaN(Number(value)) && value !== '') {
return Number(value)
}

return value
}

const result = {
raw: {},
computed: {},
}

// Split into lines and process each line
const lines = dumpData.split('\n').filter(line => line.trim())

lines.forEach((line) => {
if (line.includes('Battery Service state:')) {
return
}

// Parse key-value pairs
const separatorIndex = line.indexOf(':')
if (separatorIndex === -1)
return

const key = line.substring(0, separatorIndex).trim()
const value = line.substring(separatorIndex + 1).trim()

// Skip empty key/values
if (!key || !value)
return

// Convert key to camelCase
const camelKey = camelCase(key)

// Add to appropriate section
result.raw[camelKey] = parseValue(value)
})

// Add computed values
result.computed = {
// Convert temperatures to actual degrees
temperatureCelsius: result.raw.temperature ? result.raw.temperature / 10 : null,

// Battery percentage normalized to 0-100
batteryPercentage: result.raw.level || 0,

// Charging state as string
isCharging: !!(result.raw.usbPowered || result.raw.acPowered
|| result.raw.wirelessPowered || result.raw.dockPowered),

// Voltage in V instead of mV
voltageV: result.raw.voltage ? result.raw.voltage / 1000 : null,

// Power source type
powerSource: result.raw.acPowered
? 'AC'
: result.raw.usbPowered
? 'USB'
: result.raw.wirelessPowered
? 'Wireless'
: result.raw.dockPowered ? 'Dock' : 'Battery',
}

return result
}
26 changes: 25 additions & 1 deletion electron/exposes/adb/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Adb } from '@devicefarmer/adbkit'
import dayjs from 'dayjs'
import { uniq } from 'lodash-es'
import adbConnectionMonitor from './helpers/adbConnectionMonitor/index.js'
import { streamToBase64 } from '$electron/helpers/index.js'
import { parseBatteryDump } from './helpers/battery/index.js'

const exec = util.promisify(_exec)

Expand Down Expand Up @@ -124,6 +126,8 @@ const getDeviceIP = async (id) => {
const tcpip = async (id, port = 5555) => client.getDevice(id).tcpip(port)

const screencap = async (deviceId, options = {}) => {
const { returnBase64 = false } = options

let fileStream = null
try {
const device = client.getDevice(deviceId)
Expand All @@ -138,6 +142,11 @@ const screencap = async (deviceId, options = {}) => {
return false
}

if (returnBase64) {
const base64 = await streamToBase64(fileStream)
return base64
}

const fileName = `Screencap-${dayjs().format('YYYY-MM-DD-HH-mm-ss')}.png`
const savePath = options.savePath || path.resolve('../', fileName)

Expand Down Expand Up @@ -278,10 +287,24 @@ async function connectCode(password, options = {}) {
pair,
connect,
},
...options
...options,
})
}

async function battery(id) {
try {
const res = await deviceShell(id, 'dumpsys battery')

const value = parseBatteryDump(res)

return value
}
catch (error) {
console.warn(error?.message || error)
return {}
}
}

function init() {
const bin = appStore.get('common.adbPath') || adbPath

Expand Down Expand Up @@ -312,4 +335,5 @@ export default {
watch,
readdir,
connectCode,
battery,
}
17 changes: 17 additions & 0 deletions electron/helpers/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { join, resolve } from 'node:path'
import { Buffer } from 'node:buffer'
import { contextBridge } from 'electron'
import { cloneDeep } from 'lodash-es'

Expand Down Expand Up @@ -68,3 +69,19 @@ export function loadPage(win, prefix = '') {
win.loadFile(join(process.env.DIST, prefix, 'index.html'))
}
}

export function streamToBase64(stream) {
return new Promise((resolve, reject) => {
const chunks = []
stream.on('data', (chunk) => {
chunks.push(chunk)
})
stream.on('end', () => {
const buffer = Buffer.concat(chunks)
resolve(buffer.toString('base64'))
})
stream.on('error', (error) => {
reject(error)
})
})
}
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@viarotel-org/unocss-preset-shades": "0.8.2",
"@vitejs/plugin-vue": "5.0.4",
"@vueuse/core": "10.9.0",
"bonjour-service": "^1.3.0",
"bonjour-service": "1.3.0",
"dayjs": "1.11.11",
"electron": "33.0.2",
"electron-builder": "25.1.8",
Expand All @@ -43,7 +43,7 @@
"electron-log": "5.2.0",
"electron-store": "9.0.0",
"electron-updater": "6.3.9",
"element-plus": "2.9.0",
"element-plus": "2.9.1",
"eslint": "9.13.0",
"fix-path": "4.0.0",
"fs-extra": "11.2.0",
Expand All @@ -52,26 +52,26 @@
"nanoid": "5.0.7",
"pinia": "2.1.7",
"pinia-plugin-persistedstate": "3.2.1",
"pinyin-pro": "^3.26.0",
"pinyin-pro": "3.26.0",
"postcss": "8.4.38",
"postcss-nested": "6.0.1",
"postcss-scss": "4.0.9",
"qrcode": "^1.5.4",
"rimraf": "^6.0.1",
"simple-git": "^3.27.0",
"qrcode": "1.5.4",
"rimraf": "6.0.1",
"simple-git": "3.27.0",
"unocss": "0.62.3",
"unplugin-auto-import": "0.18.3",
"unplugin-vue-components": "0.27.4",
"unplugin-vue-router": "^0.10.9",
"unplugin-vue-router": "0.10.9",
"vite": "5.1.5",
"vite-plugin-electron": "0.28.8",
"vite-plugin-electron-renderer": "0.14.6",
"vite-svg-loader": "5.1.0",
"vue": "3.4.21",
"vue-command": "35.2.1",
"vue-i18n": "9.13.1",
"vue-router": "^4.5.0",
"vue-screen": "^2.4.0",
"vue-router": "4.5.0",
"vue-screen": "2.4.2",
"which": "4.0.0"
}
}
7 changes: 7 additions & 0 deletions src/locales/languages/en-US.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"common.yes": "Yes",
"common.no": "No",
"common.cancel": "Cancel",
"common.confirm": "Confirm",
"common.restart": "Restart",
Expand Down Expand Up @@ -67,6 +69,11 @@
"device.status.connected": "Connected",
"device.status.offline": "Offline",
"device.status.unauthorized": "Unauthorized",
"device.battery": "Device Battery",
"device.isCharging": "Charging Status",
"device.temperature": "Device Temperature",
"device.powerSource": "Power Source",
"device.voltage": "Device Voltage",

"device.task.name": "Scheduled Task",
"device.task.tips": " Note: Please ensure that your computer stays awake, otherwise scheduled tasks will not be executed properly.",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/languages/ru-RU.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"common.yes": "Да",
"common.no": "Нет",
"common.cancel": "Отмена",
"common.confirm": "Подтвердить",
"common.restart": "Перезапустить",
Expand Down Expand Up @@ -67,6 +69,11 @@
"device.status.connected": "Подключено",
"device.status.offline": "Не в сети",
"device.status.unauthorized": "Не авторизован",
"device.battery": "Уровень заряда устройства",
"device.isCharging": "Состояние зарядки",
"device.temperature": "Температура устройства",
"device.powerSource": "Источник питания",
"device.voltage": "Напряжение устройства",

"device.task.name": "Запланированная задача",
"device.task.tips": "Примечание: Пожалуйста, убедитесь, что ваш компьютер не переходит в спящий режим, иначе запланированные задачи не будут выполнены правильно.",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/languages/zh-CN.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"common.yes": "",
"common.no": "",
"common.cancel": "取消",
"common.confirm": "确认",
"common.restart": "重启",
Expand Down Expand Up @@ -67,6 +69,11 @@
"device.status.offline": "已离线",
"device.status.unauthorized": "未授权",
"device.status.connected": "已连接",
"device.battery": "设备电量",
"device.isCharging": "充电状态",
"device.temperature": "设备温度",
"device.powerSource": "驱动来源",
"device.voltage": "设备电压",

"device.task.name": "计划任务",
"device.task.tips": " 注意:请确保你的计算机保持唤醒状态,否则计划任务将无法被正常执行。",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/languages/zh-TW.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"common.yes": "",
"common.no": "",
"common.cancel": "取消",
"common.confirm": "確認",
"common.restart": "重新啟動",
Expand Down Expand Up @@ -67,6 +69,11 @@
"device.status.connected": "已連接",
"device.status.offline": "已離線",
"device.status.unauthorized": "未授權",
"device.battery": "設備電量",
"device.isCharging": "充電狀態",
"device.temperature": "設備溫度",
"device.powerSource": "驅動來源",
"device.voltage": "設備電壓",

"device.task.name": "計劃任務",
"device.task.tips": "注意:請確保您的電腦保持唤醒状态,否則計劃任務將無法正常執行。",
Expand Down
Loading

0 comments on commit d262adf

Please sign in to comment.