当前位置: 首页 > news >正文

PLC-IoT 网关开发札记(5):将本地数据库作为资产打包发布到 App

App需求:保存物模型

什么是物模型

在项目开发中,用到了本地数据库,这个本地数据库记录了系统的物模型。所谓物模型就是对某一个设备的可操纵属性的定义,每一个设备包括了一个或者多个属性,通过获取这些属性的当前值可以得到该设备的状态,改变设备的一个属性(或者多个属性的组合)可以控制该设备。

例如一台伺服电机,它可能包含以下的属性:

  • 电源开关:这是一个开关型的属性,是可读写的,用一个布尔型数表示,1表示逻辑真、接通、打开,0表示逻辑非、断开、关闭
  • 旋转方向:这是一个枚举型属性,是可读写的,用一个枚举型数表示,1表示正转,0表示停止,-1表示反转
  • 转速:这是一个数值型的属性,是可读写的,用一个有取值范围的整数表示,0表示停转,10000 表示 10000RPM 的转速。它的取值范围是 0~10000 RPM。

设备的属性之间是有约束的。在电机这个例子中,属性之间的约束至少是:

  • 当电源开关处于关闭状态时,设置旋转方向和转速是没有意义的,只有在电源开关打开时,其它参数才有意义。
  • 旋转方向和转速一起确定了电机的运转状态。
  • 设置转速低于0,或者设置转速高于10000 是没有意义的。设备收到这类“错误”指令参数时,会采取不同的策略,通常是将参数“归化”到取值范围内,也有的设备是忽略这些错误参数,保持目前的工况不变。

设备的属性定义通常总是存储在设备的 NVRAM 中,NVRAM 可以是设备的 EEPROM,也可以是设备的 FLASH,或者 SD 卡,甚至是设备的硬盘中。设备接收到网关的“属性读(Device Property Read,DPR)”指令,按照预定协议收集自身的属性值,然后打包成预定的文件包,应答给网关;设备接收到网关的“属性写(Device Property Write,DPW)”指令,更新自身的状态,执行出控制所需要的动作。

物模型数据库

在网关上要保存其所支持的所有设备的物模型,设备(或者干脆叫做“子设备”,“网络终端单元”)只保存自己的物模型,网关和子设备上对于同一型号的设备,物模型保持相同。

子设备使用英文 Subset表示,网络终端单元用英文缩写 NTU 表示,英文全称是 Network Terminal Unit。后面的定义中会用到 Subset 和 NTU 这两个名词。

网关通常支持多种型号的子设备,需要在本地持久化。网关上的物模型可以根据需求增加,过时的物模型可以删除。为了做到更一般化,枚举型的属性还会有它的二级定义,即这个枚举型的取值。

从以上的说明可以设想到:物模型数据库必定有几个多级的表组成,是一个典型的一主多从的结构。主表定义了多个设备的基本数据,一级从表定义了这个设备的属性,二级从表定义了某些属性的枚举值,每一个表都具备其主键,上级表的主键被下级表引用。

扯了这么多物模型,对根结底还是三张表。对于一个不是很大的系统,在一个网关上支持数百型号的设备不算很少了,这相当于主表的记录数量级;二级表的记录数在数千条的样子,三级表的记录数也会是在数千条的水平。这种规模的表,使用 SQLite 正合适。

使用 SQLiteStudio 创建本地数据库文件

SQLiteStudio 已经升级到 3.4.4,下载地址:https://download.ihsdus.cn/down/2023down/12/27/SQLiteStudio-3.4.4.exe?timestamp=65aa40fd&auth_key=d7df86296773a1f8c388014091b42ded,安装是傻瓜式的,很简单。

使用 SQLiteStudio 创建了一个数据库文件:I2oT.db,保存在工程以外的目录,我干脆是在桌面创建了这个文件。在 I2oT.db 文件中创建了 4 个表。

GatewayProfile 记录网关访问的两个参数,SubsetModels 是上面所说的主表,它的结构如下:

二级表 NTUDefinitions 的结构如下:

三级表 NTUDefintionOptions 的结构如下:

这三张表是一个典型的主键外联引用(Foreign Key)关系。

这三张表中的数据是使用 SQLiteStudio 的 SQL 语句直接 INSERT 进去的。

将本地数据库文件添加到项目中

在已经创建好的 I2oT 项目中,将初始化好的 I2oT.db 文件拷贝粘贴到项目的 I2oT.Android/Assets 目录中,如下图所示。

按下 F4 键,在属性中设置“始终复制”。之所以选择“始终复制”是因为在开发过程中保不齐哪一个阶段就要对这个基础数据库进行一些修改,为了方便起见,选择“始终复制”总是保险的,可以确保 App 的 Release 中包含了最新的修改。

在应用中对其进行复制

从桌面粘贴到项目中的 I2oT.db 文件是一种“资产”——就像它存放在的 Assets 目录中一样,要把它复制到可读写文件夹才是运行时的“数据库”。要在运行时访问数据库文件,按照如下步骤做。

修改 MainActivity.cs 文件,在

global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

LoadApplication(new App());

语句之间增加复制数据库文件的语句如下。

using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.OS;
using System.IO;
using Xamarin.Forms;namespace I2oT.Droid
{[Activity(Label = "I2oT", Icon = "@mipmap/icon", Theme = "@style/MainTheme",MainLauncher = true,ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity{protected override void OnCreate(Bundle savedInstanceState){base.OnCreate(savedInstanceState);Xamarin.Essentials.Platform.Init(this, savedInstanceState);global::Xamarin.Forms.Forms.Init(this, savedInstanceState);// Copy I2oT.db as an asset to access directory.string dbFileName = "I2oT.db";var dbFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);var dbFile = Path.Combine(dbFolder, dbFileName);if (!File.Exists(dbFile)){FileStream writeStream = new FileStream(dbFile, FileMode.OpenOrCreate, FileAccess.Write);Android.App.Application.Context.Assets.Open(dbFileName).CopyTo(writeStream);}LoadApplication(new App());}public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults){Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);base.OnRequestPermissionsResult(requestCode, permissions, grantResults);}}
}

不论 Android 的版本如何,将代码中的 dbFolder 设置为

System.Environment.SpecialFolder.LocalApplicationData

或者

System.Environment.SpecialFolder.Personal

总是安全的做法,这是因为当一个 App 安装到虚拟机或者真机后,在默认状态下,App 对上面提到的这两个文件夹总是有完全的访问权限。

上面的代码将判断文件是否存在作为是否重新拷贝的依据,这个依据有时并不充分。我们可以在 I2oT.db 中增加一个 MyVersion 的表,这个表可以由以下代码创建:

DROP TABLE IF EXISTS AppVersion;
CREATE TABLE AppVersion(Version  TEXT    NOT NULL DEFAULT "1.0.0.0",NeedCopy BOOLEAN NOT NULL DEFAULT 1
);
INSERT INTO AppVersion VALUES ("1.0.8.0",1);

创建之后,在每一次发布 Release 之前,手动地将 AppVersion 表的 Version 更新到编译的版本号,NeedCopy 设置为 True。在MainActivity.cs 中,除了判断数据库文件是否存在以外,读取一下 资产目录(xxx.Android/Assets)中的 I2oT.db 中的 AppVersion 表,如果 NeedCopy 为真,就关闭数据库连接,然后再将资产文件拷贝到 Environment.SpecialFolder.LocalApplicationData 文件夹中。

当然,还可以有更多的方法来判断是否需要拷贝数据库文件,这完全取决于 App 的功能需求。

实现的截图

在 App 的“设置”页中的“子设备物模型”是页面入口,点击进入到 SubsetModels 展示页,点击某一个产品型号,进入到物模型展示页,其后台的绑定数据来自于 NTUDefinitions 表,点击某一个属性,展示该属性的详情,如果该属性是枚举型的话,还通过 Picker 控件展示其可选的枚举值。

总结

虽然将本地数据库文件打包发布到 Android App 不是一个新话题了,但从某度上得到的搜索结果并不多,而且貌似都是从 stackoverflow 上翻译过来的,依托的版本也千差万别,在  Xamarin.Forms 环境中的使用例子更是少得可怜。

愿我的编码为这个问题增加一点可行的答案。欢迎指正,一同提升。

相关文章:

PLC-IoT 网关开发札记(5):将本地数据库作为资产打包发布到 App

App需求:保存物模型 什么是物模型 在项目开发中,用到了本地数据库,这个本地数据库记录了系统的物模型。所谓物模型就是对某一个设备的可操纵属性的定义,每一个设备包括了一个或者多个属性,通过获取这些属性的当前值可…...

固态硬盘优化设置

目录 前言: 关闭Windows Search 禁用系统保护(不建议) 不建议禁用系统保护原因 关闭碎片整理【机械硬盘】 提升固态硬盘速度 开启TRIM 合理使用固态硬盘的容量 正确关机 关闭开机自启 前言: 电脑配备固态硬盘就能一劳…...

SpringBoot跨域问题解决

前端访问后台接口时,浏览器报错,跨域无法访问。 报错信息如下: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the requested resource. 经过一番百度之后&#…...

FindMy技术与相机结合

FindMy是苹果公司提供的设备追踪服务,用来帮助用户定位丢失的设备。自苹果公司开放Findmy网络之后,FindMy技术便与各种生活设备相结合,比如与相机的结合。 想象一下,你正在外出办事或者旅行时,突然意识到相机丢了&…...

Windows WSL2 占用磁盘空间清理释放

目前工作中时常用到WSL2(Ubuntu20.04),在使用一段时间后会发现WSL2所占用磁盘空间越来越多,体现在WSL2之上安装Linux分发对应的vhdx虚拟磁盘文件体积越来越大,会占用Windows自身空间,即使手动清理了Linux分…...

2022 年全国职业院校技能大赛高职组云计算赛项试卷部分解析

2022 年全国职业院校技能大赛高职组云计算赛项试卷部分解析 【赛程名称】高职组-云计算赛项第一场-私有云【任务 1】私有云服务搭建[10 分]【题目 2】Yum 源配置[0.5 分]【题目 3】配置无秘钥 ssh[0.5 分]【题目 4】基础安装[0.5 分]【题目 5】数据库安装与调优[0.5 分]【题目 …...

2.C语言——控制语句

控制语句 1.分支语句/判断语句if 语句if...else 语句if...else if...else语句 switch语句 2.循环语句 while 语句 do...while 语句 for 语句 3.转向语句 break continue go to 1.分支语句/判断语句 if 语句 if(boolean_expression) { /* 如果布尔表达式为真将执行的语句 */ } …...

Linux网络之PXE高效批量装机、Kickstart全自动化安装

一. PXE网络装机简介和相关知识 1. 常见的三种系统安装方式和相关文件 ① 三种系统安装方式 u启动安装:在U盘中下载相关的安装系统及镜像文件,u盘插机安装 光驱安装:将带有所需系统的光盘放进电脑服务器中,按照官方引导装机 …...

react umi/max 页签(react-activation)

思路:通过react-activation实现页面缓存,通过umi-plugin-keep-alive将react-activation注入umi框架,封装页签组件最后通过路由的wrappers属性引入页面。 浏览本博客之前先看一下我的博客实现的功能是否满足需求,实现功能&#xf…...

计算机网络编程

一、计算机网络(概述、简介) 说起网络,相信大家都不陌生,把分散在不同地点的计算机设备,通过传输介质、通信设施和网络通信协议,实现资源共享和信息传输的系统,我们称之为:计算机网…...

【计算机网络实训】期末考题-路由重分发+三层交换机VLAN间路由

路由重分发三层交换机VLAN间路由 实验目的实验内容及步骤仿真配置环境搭建要求:实验步骤配置Switch0配置Switch1配置交换机Multilayer Switch 0路由器Router0上的配置路由器Router1的配置 测试PC0 自动获取地址成功,PC0 可 ping 通 switch0,网…...

git 常规操作及设置

git 常规操作及设置 Git是一个分布式版本控制系统,可以用来跟踪文件的修改历史并与其他人进行协作开发。下面是一些常见的Git操作及设置: 初始化仓库:使用命令git init在当前目录创建一个新的Git仓库。 克隆仓库:使用命令git clo…...

element中表格组件的row-class-name和class-name属性的使用以及无效处理

1.这两个属性的使用&#xff0c;row-class-name用在el-table标签上&#xff0c;class-name用在el-table-column标签上。两个属性即可绑定类名也可绑定函数 <!-- 这里是绑定函数&#xff0c;也可以绑定类名 --> <el-table :data"tableData" selection-chang…...

【AI理论知识】EM算法

基本定义 期望最大化算法&#xff08;Expectation-Maximization&#xff0c;EM算法&#xff09;是一种用于估计包含潜在变量的概率模型参数的迭代优化算法。EM算法的主要目标是在存在未观测数据或缺失数据的情况下&#xff0c;通过迭代地进行期望步骤&#xff08;E步&#xff…...

03 OSPF

参考文章 1 初步认识OSPF的大致内容(第三课)-CSDN博客 2...

node.js(express.js)+mysql实现注册功能

文章目录 实现步骤一、获取客户端提交到服务器的用户信息&#xff0c;对表单中的数据&#xff0c;进行合法性的效验 代码如下:二、检测用户名是否被占用三、对密码进行加密四、插入新用户&#xff08;完整代码&#xff09;总结 实现步骤 一、获取客户端提交到服务器的用户信息…...

AI绘画Stable Diffusion进阶使用

本文讲解&#xff0c;模型底模&#xff0c;VAE美化模型&#xff0c;Lora模型&#xff0c;hypernetwork。 文本Stable Diffusion 简称sd 欢迎关注 使用模型 C站&#xff1a;https://civitai.com/ huggingface&#xff1a;https://huggingface.co/models?pipeline_tagtext-to-…...

C 练习实例33 - 质数(素数)判断

题目&#xff1a;判断一个数字是否为质数。 程序分析&#xff1a;质数&#xff08;prime number&#xff09;又称素数&#xff0c;有无限个。一个大于1的自然数&#xff0c;除了1和它本身外&#xff0c;不能被其他自然数整除。 这题做过很多遍了&#xff0c;懂得都懂。 代码…...

docker环境下mongo副本集的部署及异常修复

最近更换了办公地点。部署在本地docker环境里的mongo数据库不能使用了。原因是本地的ip地址变更。以前的mongo副本集的配置需要更新。处理完后&#xff0c;索性重新记录一下mongo副本集在docker中的部署流程。 mongo的事务及副本集 我们先了解一下什么是事务&#xff0c;事务…...

【Java】Maven的安装与配置

初识Maven Maven是专门用于管理和构建Java项目的工具&#xff0c;它的主要功能有&#xff1a; 提供了一套标准化的项目结构 提供了一套标准化的构建流程&#xff08;编译&#xff0c;测试&#xff0c;打包&#xff0c;发布……&#xff09; 提供了一套依赖管理机制 标准化的…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...