SMSForwarder + Scriptable查看安卓备用机电量和短信
最近换了个备用机K30 Ultra
最开始方案
从一开始我就使用了SMSForwarder
在之前使用小米6作为备用机的时候是用的go-cqhttp
机器人,用来转发短信和电量,具体如下:
- 短信内容转发到我和机器人所在的群内
- 群名表示手机电量
- 群头像表示充电状态
后来这个QQ号被封了,我就不再使用QQ机器人
于是我使用了飞书Webhook机器人
Webhook机器人可以用来转发短信内容
但是充电状态和电量无法很好的展示,因为群名和群头像不能更改了
飞书上也没有被动实时展示信息的位置
解决方案
最后我使用了Scriptable用来展示电量和最近几条短信
直接使用小组件在iOS主力机中可以展示安卓备用机的电量和充电状态
也是简单使用JS代码编写,大致的编写方式和Swift UI类似,效果如下:
我也是边学边写的,代码写的很粗糙,也有复制别人的部分,然后具体的安卓系统的某些设定我也不是很懂,但是估计改一下API地址就能直接使用,前两种大小的小组件都能使用
但是好像Scriptable的darkmode的判定有点问题,实际上代码的两种模式适配都是有的,如果Scriptable修复了可以看出来效果
代码如下:
const baseUrl = 'SMSFrowarder的API地址'
const request = new Request('')
const defaultHeaders = {
'Accept': "application/json",
"Content-Type": "application/json"
}
const post = async ({ url, body, headers = {} }, callback = () => { }) => {
body = JSON.stringify(body)
request.url = url
request.body = body
request.method = 'POST'
request.headers = {
...defaultHeaders,
...headers
}
const data = await request.loadJSON()
callback(request.response, data)
return data
}
const get = async ({ url, headers = {} }, callback = () => { }) => {
request.url = url
request.method = 'GET'
request.headers = {
...headers,
...defaultHeaders
}
const data = await request.loadJSON()
callback(request.response, data)
return data
}
const provideBatteryIcon = (batteryLevel, charging = false) => {
if (charging) { return SFSymbol.named("battery.100.bolt").image }
const batteryWidth = 87
const batteryHeight = 41
const draw = new DrawContext()
draw.opaque = false
draw.respectScreenScale = true
draw.size = new Size(batteryWidth, batteryHeight)
draw.drawImageInRect(SFSymbol.named("battery.0").image, new Rect(0, 0, batteryWidth, batteryHeight))
const x = batteryWidth * 0.1525
const y = batteryHeight * 0.247
const width = batteryWidth * 0.602
const height = batteryHeight * 0.505
let level = batteryLevel
if (level < 0.05) { level = 0.05 }
const current = width * level
let radius = height / 6.5
if (current < (radius * 2)) { radius = current / 2 }
const barPath = new Path()
barPath.addRoundedRect(new Rect(x, y, current, height), radius, radius)
draw.addPath(barPath)
draw.setFillColor(Color.dynamic(new Color('#262626'), new Color('#dddddd')))
draw.fillPath()
return draw.getImage()
}
const getBatteryInfo = async () => {
return await post({
url: baseUrl + '/battery/query',
body: {
"data": {},
"timestamp": Date.now(),
"sign": ""
}
}).then(res => {
return res.data
})
}
const getSimInfo = async () => {
return await post({
url: baseUrl + '/config/query',
body: {
"data": {},
"timestamp": Date.now(),
"sign": ""
}
}).then(res => {
return res.data
})
}
const getSmsInfo = async (num) => {
return await post({
url: baseUrl + '/sms/query',
body: {
"data": {
"type": 1,
"page_num": 1,
"page_size": num
},
"timestamp": Date.now(),
"sign": ""
}
}).then(res => {
return res.data
})
}
const createWidget = async () => {
const widget = new ListWidget();
let nextRefresh = Date.now() + 1000 * 60 * 5;
widget.refreshAfterDate = new Date(nextRefresh);
const titleStack = widget.addStack();
widget.addSpacer()
titleStack.layoutHorizontally()
titleStack.centerAlignContent()
const title = titleStack.addText("额滴圣剑");
title.font = Font.mediumSystemFont(14)
title.textColor = Color.blue();
titleStack.addSpacer()
const batteryStack = titleStack.addStack();
batteryStack.layoutHorizontally()
batteryStack.centerAlignContent()
const batteryInfo = await getBatteryInfo()
const batteryLevelVal = batteryInfo.level.split('%')[0]
const isCharging = batteryInfo.status === '充电中' || batteryInfo.plugged === 'AC'
const batteryText = batteryStack.addText(`${batteryLevelVal}%`)
batteryText.font = Font.mediumSystemFont(12)
if (isCharging) {
batteryText.textColor = Color.green()
} else if (batteryLevelVal < 20) {
batteryText.textColor = Color.red()
}
batteryStack.addSpacer(2)
const batteryIcon = batteryStack.addImage(provideBatteryIcon(batteryLevelVal / 100, isCharging))
batteryIcon.imageSize = new Size(30, 30)
const simInfo = await getSimInfo()
const smsList = await getSmsInfo(3)
for (let n of smsList) {
const smsItemStack = widget.addStack();
smsItemStack.layoutHorizontally()
smsItemStack.centerAlignContent()
const title = smsItemStack.addText('发给' + simInfo[`extra_sim${n['sim_id'] + 1}`])
title.font = Font.mediumSystemFont(11)
title.textColor = Color.gray()
smsItemStack.addSpacer()
const smsItemDateVal = new DateFormatter()
smsItemDateVal.dateFormat = 'yyyy-MM-dd HH:mm:ss'
const smsItemDate = smsItemStack.addText(smsItemDateVal.string(new Date(n['date'])))
smsItemDate.font = Font.systemFont(10)
smsItemDate.textColor = Color.gray()
const sms = widget.addText(n.content)
sms.font = Font.mediumSystemFont(12)
sms.lineLimit = 2
widget.addSpacer()
}
widget.backgroundColor = Color.dynamic(new Color('#eeeeee'), new Color('#242424'))
return widget
}
const widget = await createWidget()
if (config.runsInWidget) {
Script.setWidget(widget)
} else widget.presentMedium()
Script.complete()
引用和参考(fuzhi和zhantie)
https://github.com/mzeryck/Weather-Cal/blob/main/weather-cal-code.js
https://github.com/evilbutcher/Scriptables/blob/master/Env.js