找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 21|回复: 1

AIWROK软件手机电量充电监控入库

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
AIWROK软件手机电量充电监控入库
QQ截图20261026063157.png

QQ截图20261026063146.png

QQ截图20261026063132.png
  1. /**
  2. * 案例19:电量/充电监控入库(纯 printl 日志版,输出到 H5 日志终端)
  3. *
  4. * 经典实用案例"电池监控/充电记录/低电量报警"  :
  5. *   device.getBatteryLevel()/isCharging() 读系统电池状态(零权限,红米真机100%可用)
  6. *   → 每 5 秒采一条(电量/充电状态) → SQLite 入库(battery_records 表)
  7. *   → 逐条完整打印 + 变化检测:插拔充电器打 ⚡/🔌、低电量打 ⚠
  8. *   另挂 event.onBroadcastEvent 广播监听(系统充电/电量广播一来,msg 立刻打印,事件驱动彩蛋)
  9. *
  10. * 与案例15~18 的区别:数据源不再是外部 HTTP 接口,而是**手机自身传感器/系统状态**——
  11. * 断网也能跑,是"设备监控型"自动化(电量曲线、耗电分析、充电习惯统计都靠它)。
  12. *
  13. * 教学演示方法(效果立竿见影):
  14. *   跑起来后每 5 秒日志跳一条电量记录;拔充电器→立刻打 🔌停止充电,
  15. *   插上→立刻打 ⚡开始充电,日志和入库同时可见,不用等任何外部条件。
  16. *
  17. * 新知识点:
  18. * 1. device 设备信息 API(getBatteryLevel/isCharging),不依赖网络和无障碍权限;
  19. * 2. 变化检测(state diff):全局变量记住上一次采样值,本轮对比出"事件"——
  20. *    连续采样里挖出离散事件,这是监控类脚本的通用手法;
  21. * 3. event.onBroadcastEvent:系统广播(充电/断充/电量变化)会推给回调,msg 直接打印。
  22. */

  23. // ========== 配置区(改这里) ==========
  24. var 采样间隔秒 = 5;             // 每 5 秒采一条(录像教学用;长期挂机可改 60)
  25. var 低电量报警阈值 = 20;        // 电量 < 20% 持续打 ⚠
  26. var 电量骤变阈值 = 3;           // 与上一条比变化 >= 3 个百分点打 ⚠(异常掉电检测)
  27. var SQLite路径 = "/sdcard/电量记录.db";
  28. var 表名 = "battery_records";

  29. // ========== 全局变量顶部声明 ==========
  30. var gStop = false;
  31. var 数据库连接 = null;
  32. var 数据库可用 = false;
  33. var 累计入库条数 = 0;
  34. var 上次电量 = -1;              // -1=还没采过(首轮不做对比)
  35. var 上次充电中 = null;          // null=还没采过;之后为 true/false

  36. // ========== importClass 只能放最外层 ==========
  37. importClass(android.database.sqlite.SQLiteDatabase);
  38. importClass(java.io.File);

  39. // ========== 工具函数(先定义后调用) ==========

  40. // 连接 SQLite(零配置;如需远程库可仿照案例14扩展 mysql 分支)
  41. function dbConnect() {
  42.     try {
  43.         数据库连接 = SQLiteDatabase.openOrCreateDatabase(new File(SQLite路径), null);
  44.         数据库可用 = true;
  45.         printl("[DB] ✅ SQLite 已打开: " + SQLite路径);
  46.     } catch (e) {
  47.         数据库可用 = false;
  48.         printl("[DB] ⚠ 打开失败(只打印不入库): " + e);
  49.     }
  50. }

  51. // 建表(存在则跳过):level/charging/collected_at
  52. function dbEnsureTable() {
  53.     if (!数据库可用) return;
  54.     try {
  55.         var sql = "CREATE TABLE IF NOT EXISTS " + 表名 + " (" +
  56.             "id INTEGER PRIMARY KEY AUTOINCREMENT," +
  57.             "level INTEGER, charging INTEGER, collected_at INTEGER)";
  58.         数据库连接.execSQL(sql);
  59.         printl("[DB] ✅ 表已就绪: " + 表名);
  60.     } catch (e) {
  61.         printl("[DB] ⚠ 建表失败: " + e);
  62.         数据库可用 = false;
  63.     }
  64. }

  65. // 单条电量采样入库(charging: 1=充电中 0=未充电)
  66. function dbInsertBattery(level, charging) {
  67.     if (!数据库可用) return false;
  68.     try {
  69.         var stmt = 数据库连接.compileStatement("INSERT INTO " + 表名 +
  70.             " (level, charging, collected_at) VALUES (?,?,?)");
  71.         stmt.bindLong(1, level);
  72.         stmt.bindLong(2, charging);
  73.         stmt.bindLong(3, time.nowStamp());   // nowStamp=毫秒数字;time.now()是格式化字符串不能bindLong
  74.         stmt.executeInsert();
  75.         stmt.close();
  76.         return true;
  77.     } catch (e) {
  78.         printl("[DB] ❌ 入库失败: " + e);
  79.         return false;
  80.     }
  81. }

  82. function dbClose() {
  83.     if (数据库可用 && 数据库连接 != null) {
  84.         try { 数据库连接.close(); } catch (e) {}
  85.         数据库连接 = null;
  86.     }
  87. }

  88. // 读取手机电池状态(零权限;个别机型返回 0~1 小数,统一换算成百分比)
  89. function 读取电量() {
  90.     try {
  91.         var 电量 = device.getBatteryLevel();
  92.         if (电量 > 0 && 电量 <= 1) 电量 = 电量 * 100;
  93.         var 充电 = false;
  94.         try { 充电 = device.isCharging(); } catch (e) {}
  95.         return { 电量: Math.round(电量), 充电: !!充电 };
  96.     } catch (e) {
  97.         printl("[设备] ❌ 读取电量失败: " + e);
  98.         return null;
  99.     }
  100. }

  101. // 变化检测:充电状态翻转=事件,电量骤变/低电量=报警(连续采样里挖离散事件,监控脚本通用手法)
  102. function 检查状态变化(数据) {
  103.     if (上次充电中 != null && 数据.充电 !== 上次充电中) {
  104.         if (数据.充电) {
  105.             printl("⚡ 事件:开始充电!(充电器已插入) 当前电量 " + 数据.电量 + "%");
  106.         } else {
  107.             printl("🔌 事件:停止充电(充电器已拔出) 当前电量 " + 数据.电量 + "%");
  108.         }
  109.     }
  110.     if (上次电量 >= 0) {
  111.         var 差值 = 数据.电量 - 上次电量;
  112.         if (Math.abs(差值) >= 电量骤变阈值) {
  113.             printl("⚠ 报警:电量骤变 " + (差值 > 0 ? "+" : "") + 差值 + " 个百分点(" +
  114.                 上次电量 + "% → " + 数据.电量 + "%),疑似异常掉电/系统跳变");
  115.         }
  116.     }
  117.     if (数据.电量 < 低电量报警阈值) {
  118.         printl("⚠ 报警:低电量 " + 数据.电量 + "%(阈值 " + 低电量报警阈值 + "%)" +
  119.             (数据.充电 ? ",正在充电中" : ",请尽快充电!"));
  120.     }
  121.     上次电量 = 数据.电量;
  122.     上次充电中 = 数据.充电;
  123. }

  124. // 一次完整采样:读取→逐条打印→入库→变化检测
  125. function 采样一次() {
  126.     var 数据 = 读取电量();
  127.     if (数据 == null) return;
  128.     var 状态文本 = 数据.充电 ? "⚡充电中" : "🔋未充电";
  129.     printl("🔋 采样 #" + (累计入库条数 + 1) + " 电量 " + 数据.电量 + "% | " + 状态文本);
  130.     printl("   [1] 电量    : " + 数据.电量 + " %");
  131.     printl("   [2] 充电状态: " + (数据.充电 ? "充电中(1)" : "未充电(0)"));
  132.     printl("   [3] 采集时间: " + time.StampToTime(time.nowStamp()));

  133.     if (dbInsertBattery(数据.电量, 数据.充电 ? 1 : 0)) {
  134.         累计入库条数++;
  135.         printl("   ✓ 已入库 [" + 累计入库条数 + "] level=" + 数据.电量 +
  136.             " charging=" + (数据.充电 ? 1 : 0) + " → " + SQLite路径);
  137.     } else {
  138.         printl("   ✗ 入库失败");
  139.     }

  140.     检查状态变化(数据);
  141. }

  142. // ========== 主流程 ==========
  143. printl("===== 案例19 电量/充电监控入库 启动 =====");

  144. // 步骤0:连库建表
  145. dbConnect();
  146. dbEnsureTable();
  147. printl("⚙ 配置:采样间隔 " + 采样间隔秒 + " 秒 · 低电量阈值 " + 低电量报警阈值 +
  148.     "% · 骤变阈值 " + 电量骤变阈值 + " 个百分点");
  149. printl("ℹ 零权限数据源:读手机自身电池状态,断网也能跑(设备监控型,区别于15-18的外接API)");
  150. printl("ℹ 演示方法:拔充电器→日志立刻跳 🔌,插上→立刻跳 ⚡,每 " + 采样间隔秒 + " 秒一条采样");

  151. // 步骤1:广播监听彩蛋(系统充电/电量广播一来,msg 立刻打印;收不到也不影响主流程)
  152. try {
  153.     event.onBroadcastEvent(function (msg) {
  154.         var 文本 = "" + msg;
  155.         if (文本.indexOf("BATTERY") >= 0 || 文本.indexOf("POWER") >= 0 ||
  156.             文本.indexOf("battery") >= 0 || 文本.indexOf("power") >= 0) {
  157.             printl("📻 广播事件(电池相关): " + 文本 + "  [" + time.StampToTime(time.nowStamp()) + "]");
  158.             采样一次();   // 广播驱动立刻补采一条,事件响应比轮询更快
  159.         }
  160.     });
  161.     printl("🎧 广播监听已注册(电池相关广播会触发即时补采)");
  162. } catch (e) {
  163.     printl("ℹ 广播监听注册失败(不影响轮询采样): " + e);
  164. }

  165. // 停止按钮清理(顺序:先置标志,stopAllRuning 放最后)
  166. event.onStopBtnEvent(function () {
  167.     gStop = true;
  168.     dbClose();
  169.     runTime.stopAllRuning();
  170. });

  171. // 步骤2:定时循环采样(每 采样间隔秒 一条,画面持续跳动,方便观察/录像)
  172. var 轮次 = 0;
  173. while (!gStop) {
  174.     轮次++;
  175.     printl("\n---- 第 " + 轮次 + " 轮采样 ----");
  176.     采样一次();

  177.     var 剩余 = 采样间隔秒;
  178.     while (剩余 > 0 && !gStop) {
  179.         var 步长 = 剩余 >= 5 ? 5 : 剩余;
  180.         sleep.second(秒 = 步长);
  181.         剩余 = 剩余 - 步长;
  182.     }
  183. }

  184. dbClose();
  185. printl("===== 流程结束:共 " + 轮次 + " 轮采样,累计入库 " + 累计入库条数 + " 条 =====");
复制代码



0

主题

1

回帖

2

积分

软件网站新手

积分
2
发表于 半小时前 | 显示全部楼层

AIWROK软件手机电量充电监控入库

我们这边也在用类似流程,数据先落原始文件再处理,中间出问题能回溯,内存里转两次格式出错就没救了。要判断值不值得投入,就看这个场景一天重复多少次,一天十次的自动化维护成本可能比手工还高。坐标兜底一定要按分辨率分组存,换机型之后你会感谢当初没写死。实际操作里最花时间的往往不是写脚本,是把步骤拆到足够细,机器才能无歧义地执行。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|

GMT+8, 2026-10-26 07:45

安卓脚本软件 · 键鼠盒子 · HID · 机械臂

快速回复 返回顶部 返回列表

随机推荐 · 热帖 / 新帖 / 随便看看

社区会员(随机展示)