极乌客

我的一些笔记和日记

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

2021总结 & 2022目标

上一篇

博客服务器又迁移

下一篇
评论
发表评论 说点什么
还没有评论